package net.vtstar.zhongtong.avi.monitoring.job;

import io.netty.buffer.ByteBuf;
import lombok.extern.slf4j.Slf4j;
import net.vtstar.protocol.modbus.tcp.netty.packet.AbstractModbusResponse;
import net.vtstar.protocol.modbus.tcp.netty.utils.NettyUtils;
import net.vtstar.protocol.modbus.tcp.netty.utils.PoolKey;
import net.vtstar.scada.base.equipmgt.domain.*;
import net.vtstar.scada.base.equipmgt.service.EquipInfoService;
import net.vtstar.scada.base.gather.job.GatherJob;
import net.vtstar.scada.base.global.service.ModbusService;
import net.vtstar.zhongtong.avi.equipment.domain.PaintshopStation;
import net.vtstar.zhongtong.avi.global.constant.Constant;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class AviWarningJob extends GatherJob {

    private static final String EQUIPMENT_TYPE = "PLC";

    @Autowired
    private EquipInfoService equipInfoService;
    @Autowired
    private ModbusService modbusService;

    @Resource(name = "redisTemplate")
    private ValueOperations valueOperations;

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {

        log.info("-------------------------------");
        log.info("AVIMonitorJob start");

        List<EquipInfo> equipInfoList = equipInfoService.getEquipInfoList(EQUIPMENT_TYPE);
        if (CollectionUtils.isEmpty(equipInfoList)) {
            return;
        }
        //处理工位正反转用
        List<PaintshopStation> stations = new ArrayList<>();
        for (EquipInfo equipInfo : equipInfoList) {

            List<EquipCommunication> commList = equipInfoService.getCommunicationListByEquipType(equipInfo.getEquipCode(), 1);
            if (CollectionUtils.isEmpty(commList)) {
                return;
            }
            for (EquipCommunication communication : commList) {
                EquipDataChannel dataChannel = communication.getDataChannel();
                if (null != dataChannel.getEquipCode() && dataChannel.getEquipCode().startsWith(EQUIPMENT_TYPE)) {
                    continue;
                }
                String ip = dataChannel.getIp();
                Integer port = dataChannel.getPort();
                PoolKey poolKey = NettyUtils.wrapPoolKey(ip, port);
                Integer slaveId = dataChannel.getNo();
                EquipDataTemplate template = communication.getDataTemplate();
                if (template == null) {
                    log.info("无法获取设备的数据模板，设备编号：{}", dataChannel.getEquipCode());
                    continue;
                }
                List<EquipDataTemplateItem> templateItemList = template.getTemplateItemList();
                if (CollectionUtils.isEmpty(templateItemList)) {
                    log.info("无法获取数据模板的条目，设备编号：{},模板名称：{}", dataChannel.getEquipCode(), template.getName());
                    continue;
                }

                Map<Integer, List<EquipDataTemplateItem>> listMap = modbusService.groupByFuntionCode(templateItemList);
                for (Map.Entry<Integer, List<EquipDataTemplateItem>> entry : listMap.entrySet()) {
                    List<EquipDataTemplateItem> value = entry.getValue();
                    if (CollectionUtils.isEmpty(value)) {
                        continue;
                    }
                    Integer start = value.get(0).getAddress();
                    Integer end = value.get(value.size() - 1).getAddress();
                    Integer size = value.get(value.size() - 1).getLength();
                    Integer quantity = end + size - start;

                    AbstractModbusResponse response = null;
                    Integer functionCode = entry.getKey();
                    try {
                        if (1 == functionCode) {
                            response = modbusService.readCoilRegister(slaveId, poolKey, start, quantity);
                        } else if (2 == functionCode) {
                            response = modbusService.readInputDiscretes(slaveId, poolKey, start, quantity);
                        } else if (3 == functionCode) {
                            response = modbusService.readMultipleRegister(slaveId, poolKey, start, quantity);
                        } else if (4 == functionCode) {
                            response = modbusService.readInputRegister(slaveId, poolKey, start, quantity);
                        }
                    } catch (Exception e) {
                        log.error("读取失败。ip{}， 端口{}, slave{}, start{}, size{}", poolKey.getHost(), poolKey.getPort(), slaveId, start, quantity);
                        continue;
                    }
                    if (null == response) {
                        log.error("读取失败！ response 为空！");
                        continue;
                    }
                    ByteBuf body = response.getBody();
                    if (null == body) {
                        log.error("response.body is null!!");
                        continue;
                    }
                    int length = body.readableBytes();
                    byte[] bytes = new byte[length];
                    body.getBytes(body.readerIndex(), bytes);
                    
                    for (EquipDataTemplateItem templateItem : value) {
                        Integer address = templateItem.getAddress();
                        int quality = address - start;
                        int register = quality / 8;
                        int offset = quality % 8;
                        byte state = bytes[register];

                        String fieldName = templateItem.getFieldName();
                        if (fieldName.startsWith("warning")) {
                            String[] split = fieldName.split(":");
                            String areaNo = split[1];
                            String warningCode = split[2];
                            if ((state & (0x01 << offset)) == 0) {
                                state = 0;
                            } else {
                                state = 1;
                            }
                            valueOperations.set(Constant.WARNING_PREFIX + areaNo + ":" + warningCode, state);
                        }
                    }
                }
            }
        }
    }
}