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.SenderModbusRtuTunnelInfo;
import com.jiayue.ipfcst.dataexchange.dataprocesser.datagainerhandler.BaseDataGainer;
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.workassist.SingleThreadPoolExecutorUtil;
import com.jiayue.ipfcst.dataexchange.tunnelworker.workassist.TunnelBuilder;
import wei.yigulu.modbus.netty.ModbusRtuSlaverBuilder;
import wei.yigulu.purejavacomm.PureJavaCommChannelConfig;

import java.math.BigDecimal;

/**
 * modbus Rtu 的数据转发通道
 *
 * @author: xiuwei
 * @version:
 */

public class ModbusRtuDataSender extends AbstractModbusDataSender<SenderModbusRtuTunnelInfo, ModbusRtuSlaverBuilder> {


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

  @Override
  public BaseProtocolTunnel startTunnel() throws DataExchangeException {
    log.info("modbus RTU slaver {} 通道开始连接", getTunnelInfo().getTunnelName());
    protocolTunnelContainer.addSaveSendDataTask(this);
    protocolTunnelContainer.addUpdateDateTask(this);
    try {
      SingleThreadPoolExecutorUtil.executeBySingleThreadExecutor(() -> {
        try {
          this.protocolBuilder.create();
          log.error("Modbus Rtu slaver  创建通道失败");
          setTunnelStatus(TunnelStatus.LISTENSERIALFAIL);
        } catch (Exception e) {
          log.error("Modbus Rtu slaver  创建通道失败", e);
          setTunnelStatus(TunnelStatus.LISTENSERIALFAIL);
        }
      });
    } catch (Exception e) {
      log.error("Modbus Rtu slaver 创建通道失败", e);
      setTunnelStatus(TunnelStatus.LISTENSERIALFAIL);
      throw new DataExchangeException(10007, "Modbus Rtu slaver创建通道失败");
    }
    if (!TunnelStatus.LISTENSERIALFAIL.equals(getTunnelStatus())) {
      setTunnelStatus(TunnelStatus.LISTENSERIALSUCCESS);
    }
    return this;
  }

  @Override
  public ModbusRtuDataSender buildTunnel() throws DataExchangeException {
    parseGatherDataPoint();
    protocolBuilder = new ModbusRtuSlaverBuilder(this.tunnelInfo.getSerialName());
    protocolBuilder.setBaudRate(tunnelInfo.getBaudRate());
    protocolBuilder.setDataBits(PureJavaCommChannelConfig.Databits.valueOf(tunnelInfo.getDataBits()));
    protocolBuilder.setStopBits(PureJavaCommChannelConfig.Stopbits.valueOf(tunnelInfo.getStopBits()));
    protocolBuilder.setParity(PureJavaCommChannelConfig.Paritybit.valueOf(tunnelInfo.getParity()));
    setSlaveId(this.tunnelInfo.getSlaveId());
    setModbusSlaveDataContainer(protocolBuilder.getModbusSlaveDataContainer());
    if (this.tunnelInfo.getFunctionCode() == 1 || this.tunnelInfo.getFunctionCode() == 2) {
      setFunctionFlag(0);
    } else {
      setFunctionFlag(1);
    }
    protocolBuilder.setLog(this.log);
    log.info("成功创建ModbusRTUSlaver通道对象：{}", this.tunnelInfo.getTunnelName());
    setTunnelStatus(TunnelStatus.BUILT);
    protocolTunnelContainer.addTunnel(this);
    return this;
  }


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

  @Override
  public BaseProtocolTunnel tunnelStop() throws DataExchangeException {
    if (this.protocolBuilder != null) {
      this.protocolBuilder.stop();
    }
    this.protocolBuilder = null;
    log.info("关闭Modbus RTU Slave {}", this.tunnelInfo.getTunnelName());
    return super.tunnelStop();
  }


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

  }

}
