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

import com.jiayue.ipfcst.common.data.constant.enums.TunnelStatus;
import com.jiayue.ipfcst.common.data.entity.ProtocolDataType;
import com.jiayue.ipfcst.common.data.entity.ProtocolSenderDataPoint;
import com.jiayue.ipfcst.common.data.entity.sendertunnelinfo.SenderCdtRtuTunnelInfo;
import com.jiayue.ipfcst.dataexchange.dataprocesser.datagainerhandler.BaseDataGainer;
import com.jiayue.ipfcst.dataexchange.dataprocesser.datagainerhandler.DataGainerBuilder;
import com.jiayue.ipfcst.dataexchange.dataprocesser.datagainerhandler.NumOrBool;
import com.jiayue.ipfcst.dataexchange.exception.DataExchangeException;
import com.jiayue.ipfcst.dataexchange.tunnelworker.BaseProtocolTunnel;
import com.jiayue.ipfcst.dataexchange.tunnelworker.senders.DataSenderInterface;
import com.jiayue.ipfcst.dataexchange.tunnelworker.workassist.SingleThreadPoolExecutorUtil;
import com.jiayue.ipfcst.dataexchange.tunnelworker.workassist.TunnelBuilder;
import com.jiayue.ipfcst.dataexchange.tunnelworker.workassist.cdt.MyCDTDataTransmitter;
import wei.yigulu.cdt.netty.CDTSlaver;
import wei.yigulu.purejavacomm.PureJavaCommChannelConfig;

import java.math.BigDecimal;
import java.util.*;

/**
 * cdt Rtu 采集通道
 * 转发点表 默认点表连续
 *
 * @author: xiuwei
 * @version:
 */
public class CdtRtuDataSender extends BaseProtocolTunnel<SenderCdtRtuTunnelInfo> implements DataSenderInterface {


  /**
   * CDT slave 的客户端实体 CDT协议00-f0是遥测  f0之后是遥信
   */
  CDTSlaver cdtSlaver;


  /**
   * 遥测点位构造器
   */
  Map<Integer, BaseDataGainer<Number>> ycDataPoints = new HashMap<>();

  /**
   * 遥信点位构造器
   */
  Map<Integer, BaseDataGainer<Boolean>> yxDataPoints = new HashMap<>();

  /**
   * 自定义的CDT slave 的数据发送逻辑   CDTDataTransmitter的实现类
   */
  MyCDTDataTransmitter myCDTDataTransmitter = new MyCDTDataTransmitter(this);

  /**
   * 遥信数据池 用于给myCDTDataTransmitter 发送数据
   */
  Map<Integer, Boolean> yxVal = new HashMap<>();

  /**
   * 遥测数据池 用于给myCDTDataTransmitter 发送数据
   */
  Map<Integer, Integer> ycVal = new HashMap<>();

  /**
   * 顶层的构造方法
   *
   * @param tunnelInfo cdt转发的通道信息
   */
  public CdtRtuDataSender(SenderCdtRtuTunnelInfo tunnelInfo) {
    super(tunnelInfo);
  }

  @Override
  public BaseProtocolTunnel startTunnel() throws DataExchangeException {
    log.info("Cdt Rtu slaver {}  开始监听", getTunnelInfo().getTunnelName());
    protocolTunnelContainer.addUpdateDateTask(this);
    protocolTunnelContainer.addSaveSendDataTask(this);
    if (this.cdtSlaver != null && !TunnelStatus.BUILT.equals(this.getTunnelStatus())) {
      cdtSlaver.stop();
      buildTunnel();
    }
    try {
      SingleThreadPoolExecutorUtil.executeBySingleThreadExecutor(() -> {
        cdtSlaver.create();
        log.warn("cdt slaver {} 串口监听失败", getTunnelInfo().getTunnelName());
        this.setTunnelStatus(TunnelStatus.LISTENSERIALFAIL);
      });
    } catch (Exception e) {
      log.warn("cdt slaver {} 串口监听异常", getTunnelInfo().getTunnelName());
      this.setTunnelStatus(TunnelStatus.LISTENSERIALFAIL);
      throw new DataExchangeException(10013, "cdt rtu slave通道创建时发生异常");
    }
    if (!TunnelStatus.LISTENSERIALFAIL.equals(getTunnelStatus())) {
      setTunnelStatus(TunnelStatus.LISTENSERIALSUCCESS);
    }
    return this;
  }

  @Override
  public BaseProtocolTunnel buildTunnel() throws DataExchangeException {
    parseGatherDataPoint();
    cdtSlaver = new CDTSlaver(getTunnelInfo().getSerialName(), myCDTDataTransmitter.setLog(log));
    cdtSlaver.setLog(log);
    cdtSlaver.setBaudRate(getTunnelInfo().getBaudRate()).setDataBits(PureJavaCommChannelConfig.Databits.valueOf(8)).setParity(PureJavaCommChannelConfig.Paritybit.valueOf(this.getTunnelInfo().getParity()));
    this.setTunnelStatus(TunnelStatus.BUILT);
    getProtocolTunnelContainer().addTunnel(this);
    log.info("成功创建CdtRtuSlaver通道对象：{}", this.tunnelInfo.getTunnelName());
    return this;
  }

  @Override
  public BaseProtocolTunnel tunnelStop() throws DataExchangeException {
    if (this.cdtSlaver != null) {
      this.cdtSlaver.stop();
    }
    log.info("关闭CdtRtuSlaver通道：{}", this.tunnelInfo.getTunnelName());
    return super.tunnelStop();
  }

  @Override
  public void parseGatherDataPoint() throws DataExchangeException {
    List<ProtocolSenderDataPoint> protocolSenderDataPoints = this.getTunnelInfo().getDataPoints();
    yxDataPoints = new HashMap<>();
    ycDataPoints = new HashMap<>();
    if (protocolSenderDataPoints == null || protocolSenderDataPoints.size() == 0) {
      return;
    }
    protocolSenderDataPoints.removeIf((o) -> o.getProtocolPointNo() == null);
    //拆分遥测遥信
    for (ProtocolSenderDataPoint protocolSenderDataPoint : protocolSenderDataPoints) {
      if (ProtocolDataType.A.equals(protocolSenderDataPoint.getProtocolPointType())) {
        //遥信
        yxDataPoints.put(protocolSenderDataPoint.getProtocolPointNo(), DataGainerBuilder.build(protocolSenderDataPoint));
      } else {
        //遥测
        ycDataPoints.put(protocolSenderDataPoint.getProtocolPointNo(), DataGainerBuilder.build(protocolSenderDataPoint));
      }
    }
  }


  @Override
  public void updateData2Protocol() throws DataExchangeException {
    yxDataPoints.forEach((k, v) -> {
      try {
        yxVal.put(k, v.getData());
      } catch (DataExchangeException e) {
        e.printStackTrace();
      }
    });
    ycDataPoints.forEach((k, v) -> {
      try {
        ycVal.put(k, v.getData().intValue());
      } catch (DataExchangeException e) {
        e.printStackTrace();
      }
    });
    myCDTDataTransmitter.setImportantYc(ycVal);
    myCDTDataTransmitter.setYx(yxVal);
  }

  @Override
  public void setValueByManual(ProtocolSenderDataPoint dataPoint, Double value) throws DataExchangeException {
    if (dataPoint.getProtocolPointType() == ProtocolDataType.A) {
      this.yxDataPoints.put(dataPoint.getProtocolPointNo(), new BaseDataGainer<Boolean>(NumOrBool.BOOL, 1D) {
        @Override
        public Boolean getData() throws DataExchangeException {
          return value > 0;
        }
      });
    } else {
      this.ycDataPoints.put(dataPoint.getProtocolPointNo(), new BaseDataGainer<Number>(NumOrBool.NUM, dataPoint.getMagnification()) {
        @Override
        public Number getData() throws DataExchangeException {
          return BigDecimal.valueOf(value).multiply(BigDecimal.valueOf(dataPoint.getMagnification()));
        }
      });
    }

  }


  @Override
  public String getDataBeingSent(){
    return TunnelBuilder.buildSenderDataStr(yxDataPoints,ycDataPoints);

  }


}
