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.SenderModbusTcpTunnelInfo;
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 io.netty.channel.Channel;
import org.apache.commons.lang3.StringUtils;
import wei.yigulu.modbus.netty.ModbusTcpSlaverBuilder;

import java.math.BigDecimal;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * modbus 转发数据通道
 *
 * @author 修唯xiuwei
 * @version 3.0
 */
public class ModbusTcpDataSender extends AbstractModbusDataSender<SenderModbusTcpTunnelInfo, ModbusTcpSlaverBuilder> {

  private List<String> ips = new ArrayList<>();

  /**
   * 构造方法； 配置所需信息
   * 并将数据按照 点位顺序进行排序 以便后期点位写入寄存器
   *
   * @param senderModbusTcpTunnelInfo 发送方网络通讯协议tcp通道信息
   */
  public ModbusTcpDataSender(SenderModbusTcpTunnelInfo senderModbusTcpTunnelInfo) {
    super(senderModbusTcpTunnelInfo);
  }

  /**
   * 构建通道所需的信息
   *
   * @return 开启监听
   */
  @Override
  public ModbusTcpDataSender buildTunnel() throws DataExchangeException {
    parseGatherDataPoint();
    protocolBuilder = new MyModbusTcpSlaverBuilder(this.tunnelInfo.getSelfPort());
    protocolBuilder.setLog(this.log);
    if(StringUtils.isNotBlank(this.tunnelInfo.getRemoteIp())) {
      this.ips = Arrays.asList(this.tunnelInfo.getRemoteIp().split(","));
    }
    this.setTunnelStatus(TunnelStatus.BUILT);
    getProtocolTunnelContainer().addTunnel(this);
    setSlaveId(this.tunnelInfo.getSlaveId());
    setModbusSlaveDataContainer(protocolBuilder.getModbusSlaveDataContainer());
    if (this.tunnelInfo.getFunctionCode() == 1 || this.tunnelInfo.getFunctionCode() == 2) {
      setFunctionFlag(0);
    } else {
      setFunctionFlag(1);
    }
    log.info("成功创建ModbusTCPSlaver通道对象：{}", this.tunnelInfo.getTunnelName());
    return this;
  }


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


  @Override
  public void updateData2Protocol() throws DataExchangeException {
    String ip;
    List<String> bl=new ArrayList<>(ips);
    for (Channel channel : this.protocolBuilder.getChannels()) {
      ip=((InetSocketAddress) channel.remoteAddress()).getHostString();
      bl.remove(ip);
    }
    if(!bl.isEmpty()){
      log.warn("{}未连接到子站",bl.get(0));
      this.setTunnelStatus(TunnelStatus.LISTENPORTSUCCESSANDNOCONN);
    }else{
      this.setTunnelStatus(TunnelStatus.LISTENPORTSUCCESSANDCONN);
    }
    super.updateData2Protocol();
  }

  @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()));
        }
      });
    }

  }

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

  @Override
  public ModbusTcpDataSender startTunnel() throws DataExchangeException {
    log.info("modbus TCP slaver {} 通道开始连接", getTunnelInfo().getTunnelName());
    protocolTunnelContainer.addSaveSendDataTask(this);
    protocolTunnelContainer.addUpdateDateTask(this);
    try {
      SingleThreadPoolExecutorUtil.executeBySingleThreadExecutor(() -> {
        try {
          this.protocolBuilder.create();
          log.error("Modbus TCP slaver  通道监听结束");
        } catch (Exception e) {
          log.error("Modbus TCP slaver  创建通道失败", e);
          setTunnelStatus(TunnelStatus.LISTENPORTFAIL);
        }
      });
    } catch (Exception e) {
      log.error("Modbus TCP slaver 创建通道失败", e);
      setTunnelStatus(TunnelStatus.LISTENPORTFAIL);
      throw new DataExchangeException(10007, "Modbus TCP slaver创建通道失败");
    }
    if (TunnelStatus.LISTENPORTFAIL != getTunnelStatus()) {
      setTunnelStatus(TunnelStatus.LISTENPORTSUCCESS);
    }
    return this;
  }


  class MyModbusTcpSlaverBuilder extends ModbusTcpSlaverBuilder {

    public MyModbusTcpSlaverBuilder(int port) {
      super(port);
    }

    @Override
    public void connected(InetSocketAddress ipSocket) {
      setTunnelStatus(TunnelStatus.LISTENPORTSUCCESSANDCONN);
    }

    @Override
    public void disconnected(InetSocketAddress ipSocket) {

      if (this.getChannels().size() == 0)
        //当没有连接联入监听端口时  设置该状态
        setTunnelStatus(TunnelStatus.LISTENPORTSUCCESSANDNOCONN);
    }
  }
}
