package com.jiayue.ipfcst.dataexchange.tunnelworker.gathers.iml;

import com.alibaba.fastjson.JSON;
import com.jiayue.ipfcst.common.data.constant.enums.DataSourceEnum;
import com.jiayue.ipfcst.common.data.entity.BaseTunnelInfo;
import com.jiayue.ipfcst.common.data.entity.ProtocolGatherDataPoint;
import com.jiayue.ipfcst.dataexchange.container.ProtocolDataContainer;
import com.jiayue.ipfcst.dataexchange.exception.DataExchangeException;
import com.jiayue.ipfcst.dataexchange.tunnelworker.BaseProtocolTunnel;
import com.jiayue.ipfcst.dataexchange.tunnelworker.gathers.DataGatherInterface;
import lombok.Getter;
import lombok.Setter;
import wei.yigulu.modbus.domain.FunctionCode;
import wei.yigulu.modbus.domain.Obj4RequestCoil;
import wei.yigulu.modbus.domain.Obj4RequestRegister;
import wei.yigulu.modbus.domain.datatype.BooleanModbusDataInRegister;
import wei.yigulu.modbus.domain.datatype.IModbusDataType;
import wei.yigulu.modbus.domain.datatype.ModbusDataTypeEnum;
import wei.yigulu.modbus.domain.datatype.NumericModbusData;
import wei.yigulu.modbus.exceptiom.ModbusException;
import wei.yigulu.modbus.utils.ModbusRequestDataUtils;
import wei.yigulu.netty.BaseProtocolBuilder;
import wei.yigulu.netty.MasterInterface;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 抽象的modbus数据获取
 *
 * @author: xiuwei
 * @version:
 */
@Setter
@Getter
public abstract class AbstractModbusDataGather<T extends BaseTunnelInfo, E extends BaseProtocolBuilder> extends BaseProtocolTunnel<T> implements DataGatherInterface {

  int slaveId;

  FunctionCode functionCode;
  /**
   * 通道点位  ---- 点位对象
   */
  Map<Integer, ProtocolGatherDataPoint> dataPointMap;
  /**
   * 0: 线圈   1：寄存器
   */
  private int functionFlag;
  /**
   * 向modbus slave端发送的请求
   */
  private List<Obj4RequestRegister> requestRegisterList;
  /**
   * 向modbus slave端发送线圈的请求
   */
  private List<Obj4RequestCoil> requestCoilList;

  protected E protocolBuilder;


  /**
   * 连续异常的次数
   */
  protected int consecutiveExceptions;


  /**
   * 顶层的构造方法
   *
   * @param tunnelInfo 通道信息
   */
  public AbstractModbusDataGather(T tunnelInfo) {
    super(tunnelInfo);
  }

  @Override
  public void parseGatherDataPoint() throws DataExchangeException {
    log.info("解析该通道下所管理的点位");
    List<ProtocolGatherDataPoint> dataPoints = tunnelInfo.getDataPoints();
    if (dataPoints == null || dataPoints.size() == 0) {
      return;
    }
    dataPoints.removeIf((o) -> o.getProtocolPointNo() == null || o.getDataSource() != DataSourceEnum.GATHER);
    if (getFunctionCode().getCode() == 1 || getFunctionCode().getCode() == 2) {
      setFunctionFlag(0);
    } else {
      setFunctionFlag(1);
    }
    Map<Integer, ModbusDataTypeEnum> points = new HashMap<>();
    List<Integer> coilPoints = new ArrayList<>();
    setDataPointMap(new HashMap<>());
    if (getFunctionFlag() == 0) {
      for (ProtocolGatherDataPoint d : dataPoints) {
        getDataPointMap().put(d.getProtocolPointNo(), d);
        coilPoints.add(d.getProtocolPointNo());
      }
      try {
        setRequestCoilList(ModbusRequestDataUtils.splitModbusRequest(coilPoints, getSlaveId(), getFunctionCode()));
      } catch (ModbusException e) {
        throw new DataExchangeException(e.getCode(), e.getMsg());
      }
    } else {
      for (ProtocolGatherDataPoint d : dataPoints) {
        getDataPointMap().put(d.getProtocolPointNo(), d);
        points.put(d.getProtocolPointNo(), d.getProtocolPointType().getModbusDataType());
      }
      try {
        setRequestRegisterList(ModbusRequestDataUtils.splitModbusRequest(points, getSlaveId(), getFunctionCode()));
      } catch (ModbusException e) {
        throw new DataExchangeException(e.getCode(), e.getMsg());
      }
      log.info("解析该通道下所管理的点位完成");
    }
  }

  @Override
  public void getDataFromProtocol() throws DataExchangeException {
    log.info("获取到从通道中获取的点位");
      try {
        if (getFunctionFlag() == 1 && getRequestRegisterList() != null) {
          Map<Integer, IModbusDataType> map = ModbusRequestDataUtils.getRegisterData((MasterInterface) protocolBuilder, getRequestRegisterList());
          log.info(JSON.toJSONString(map));
          if (map == null || map.size() == 0) {
            throw new DataExchangeException(10003, "通讯数据帧解析异常");
          }
          for (Integer i : map.keySet()) {
            if (map.get(i) instanceof NumericModbusData) {
              ProtocolDataContainer.getInstance().putNumber(getDataPointMap().get(i).getId(), ((NumericModbusData) map.get(i)).getValue().multiply(BigDecimal.valueOf(getDataPointMap().get(i).getMagnification())));
            } else {
              ProtocolDataContainer.getInstance().putBoolean(getDataPointMap().get(i).getId(), ((BooleanModbusDataInRegister) map.get(i)).getValue(0));
            }
          }
        } else if (getFunctionFlag() == 0 && getRequestRegisterList() != null) {
          Map<Integer, Boolean> map = ModbusRequestDataUtils.getCoilData((MasterInterface) protocolBuilder, getRequestCoilList());
          log.info(JSON.toJSONString(map));
          if (map == null || map.size() == 0) {
            throw new DataExchangeException(10003, "通讯数据帧解析异常");
          }
          for (Integer i : map.keySet()) {
            ProtocolDataContainer.getInstance().putBoolean(getDataPointMap().get(i).getId(), map.get(i));
          }
        }
      } catch (ModbusException e) {
        throw new DataExchangeException(e.getCode(), e.getMsg());
      }
  }

}
