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

import lombok.extern.slf4j.Slf4j;
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.utils.CollecUtils;
import net.vtstar.zhongtong.avi.equipment.domain.PaintshopStation;
import net.vtstar.zhongtong.avi.global.constant.Constant;
import net.vtstar.zhongtong.avi.monitoring.domain.enums.StationState;
import net.wimpi.modbus.io.ModbusTCPTransaction;
import net.wimpi.modbus.msg.*;
import net.wimpi.modbus.net.TCPMasterConnection;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Component
public class AVIElectrophoresisJob extends GatherJob {

    //电泳空中行车
    private static final String EQUIPMENT_TYPE = "PLC_E";

    @Autowired
    private EquipInfoService equipInfoService;
    @Autowired
    private ModbusService modbusService;
    @Resource(name = "redisTemplate")
    private ValueOperations valueOperations;
    @Resource(name = "laneStationCache")
    private Cache laneStationCache;

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

        log.info("-------------------------------");
        log.info("AVIElectrophoresisJob start");
        List<PaintshopStation> temStation = laneStationCache.get(Long.valueOf("111"), ArrayList.class);
        if (CollecUtils.isEmpty(temStation) || temStation.size() != 14){
            log.error("空中行车的工位数不对!");
            return;
        }
        Map<Integer, List<PaintshopStation>> collect = temStation.stream().collect(Collectors.groupingBy(PaintshopStation::getSequence));
        //处理空中行车
        List<EquipCommunication> commList = equipInfoService.getCommunicationListByEquipType(EQUIPMENT_TYPE, 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;

                Integer functionCode = entry.getKey();
                ModbusRequest modbusRequest = null;
                ModbusResponse response = null;
                if (1 == functionCode) {
                    modbusRequest = new ReadCoilsRequest(start, quantity);
                } else if (2 == functionCode) {
                    modbusRequest = new ReadInputDiscretesRequest(start, quantity);
                } else if (3 == functionCode) {
                    modbusRequest = new ReadMultipleRegistersRequest(start, quantity);
                } else if (4 == functionCode) {
                    modbusRequest = new ReadInputRegistersRequest(start, quantity);
                }
                modbusRequest.setUnitID(slaveId);
                try {
                    TCPMasterConnection connection = new TCPMasterConnection(InetAddress.getByName(poolKey.getHost()));
                    connection.setPort(port);
                    connection.setTimeout(3000);
                    connection.connect();
                    ModbusTCPTransaction transaction = new ModbusTCPTransaction(connection);
                    transaction.setReconnecting(false);
                    transaction.setRequest(modbusRequest);
                    transaction.execute();
                    response = transaction.getResponse();
                } catch (Exception e) {
                    log.error("PLC连接异常, PLC地址: {}, 端口:{}", poolKey.getHost(), poolKey.getPort());
                    continue;
                }
                if (null == response) {
                    log.error("读取失败！ response 为空！");
                    return;
                }
                String[] hexStrs = response.getHexMessage().split(" ");
                if (hexStrs.length == 9) {
                    log.error("读取失败！ length 为9！");
                    return;
                }
                StringBuilder sb = new StringBuilder();
                for (int i = 9; i < hexStrs.length; i++) {
                    Integer newValue = Integer.valueOf(hexStrs[i], 16);
                    int j = 0;
                    while (j < 8) {
                        sb.append(newValue % 2);
                        newValue = newValue / 2;
                        j++;
                    }
                }
                byte[] bytes = sb.toString().getBytes();
                for (EquipDataTemplateItem templateItem : value) {
                    Integer address = templateItem.getAddress();
                    int quality = address - start;
                    byte state = bytes[quality];

                    String fieldName = templateItem.getFieldName();
                    String sequence = fieldName.split(":")[1];
                    PaintshopStation station = collect.get(Integer.valueOf(sequence)).get(0);
                    if (state == 48) {
                        station.setState(StationState.FREE);
                    } else {
                        station.setState(StationState.USE);
                    }
                    valueOperations.set(Constant.STATION_PREFIX + station.getCode(), station);
                }
            }
        }
    }
}