package com.yeejoin.amos.iec104.tcp.client.invoke;

import com.alibaba.fastjson.JSONObject;
import com.yeejoin.amos.connect.common.enums.RedisKeyEnum;
import com.yeejoin.amos.connect.dao.entity.PointConfigVo;
import com.yeejoin.amos.iec104.business.constants.IEC104Constant;
import com.yeejoin.amos.iec104.business.param.AlarmParam;
import com.yeejoin.amos.iec104.business.service.intfc.IClientListenService;
import com.yeejoin.amos.iec104.business.service.intfc.IConfService;
import com.yeejoin.amos.iec104.business.service.intfc.IPointConfigService;
import com.yeejoin.amos.iec104.context.FireAutoIntfContext;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.LinkedList;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


public class GeneralDataQueue {
    private static final BlockingQueue<AlarmParam> blockingQueue = new LinkedBlockingQueue<AlarmParam>();

    private ScheduledExecutorService service_general = null;

    private IClientListenService clientListenService;

    private IPointConfigService pointConfigService;

    private IConfService confService;

    private volatile static GeneralDataQueue instance = null;

    private RedisTemplate<String, String> redisTemplate;

    private GeneralDataQueue() {
        clientListenService = (IClientListenService) FireAutoIntfContext.getInstance().getBean(IClientListenService.class);
        confService = (IConfService) FireAutoIntfContext.getInstance().getBean(IConfService.class);
        pointConfigService = (IPointConfigService) FireAutoIntfContext.getInstance().getBean(IPointConfigService.class);
        redisTemplate = (RedisTemplate) FireAutoIntfContext.getInstance().getBean("redisTemplate");
    }

    public static GeneralDataQueue getInstance() {
        //先检查实例是否存在，如果不存在才进入下面的同步块
        if (instance == null) {
            //同步块，线程安全的创建实例
            synchronized (GeneralDataQueue.class) {
                //再次检查实例是否存在，如果不存在才真的创建实例
                if (instance == null) {
                    instance = new GeneralDataQueue();
                }
            }
        }
        return instance;
    }

    /**
     * 启动apdu数据消费任务
     */
    public void start() {
        service_general = Executors.newSingleThreadScheduledExecutor();
        // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间
        service_general.scheduleAtFixedRate(task_runnable, 5, 10, TimeUnit.SECONDS);
    }

    public void add(AlarmParam recData) {
        blockingQueue.add(recData);
    }

    Runnable task_runnable = new Runnable() {

        private boolean alarmParamIsChange(AlarmParam alarmParam) {
            String redisKey = RedisKeyEnum.buildKey(alarmParam.getPointCode(), RedisKeyEnum.K001);
            String data = redisTemplate.opsForValue().get(redisKey);
            if (StringUtils.isEmpty(data)) {
                redisTemplate.opsForValue().set(redisKey, JSONObject.toJSONString(alarmParam));
                return true;
            } else {
                AlarmParam oldAlarmParam = JSONObject.parseObject(data, AlarmParam.class);
                if (oldAlarmParam.getState().equals(alarmParam.getState())) {
                    return false;
                } else {
                    redisTemplate.opsForValue().set(redisKey, JSONObject.toJSONString(alarmParam));
                    return true;
                }
            }
        }

        public void run() {
            while (true) {
                try {
                    AlarmParam param1 = blockingQueue.take();
                    LinkedList<AlarmParam> datas = new LinkedList<>();
                    PointConfigVo vo = pointConfigService.findByServicesIdAndInfoAddress(param1.getServiceId(), Integer.valueOf(param1.getInformationAddress()));
                    if (ObjectUtils.isEmpty(vo)) continue;
                    param1.setPointCode(vo.getPointCode());
                    if (alarmParamIsChange(param1)) {
                        datas.add(param1);
                        clientListenService.sendDatas(IEC104Constant.GENERAL_MESSAGE, datas);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    Logger.getLogger(this.getClass()).error(e.getMessage());
                }
            }
        }
    };


}
