package com.jiayue.ipfcst.dataexchange.tunnelworker;

import ch.qos.logback.classic.Logger;
import cn.hutool.core.util.RuntimeUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.jiayue.ipfcst.common.core.util.SpringContextHolder;
import com.jiayue.ipfcst.common.data.constant.enums.TunnelStatus;
import com.jiayue.ipfcst.common.data.constant.enums.TunnelType;
import com.jiayue.ipfcst.common.data.entity.BaseTunnelInfo;
import com.jiayue.ipfcst.common.data.entity.ChannelDisconLog;
import com.jiayue.ipfcst.console.service.ChannelDisconLogService;
import com.jiayue.ipfcst.dataexchange.container.ProtocolTunnelContainer;
import com.jiayue.ipfcst.dataexchange.exception.DataExchangeException;
import com.jiayue.ipfcst.dataexchange.logger.TunnelLoggerFactory;
import com.jiayue.ipfcst.dataexchange.tunnelworker.gathers.iml.Iec104TcpDataGather;
import com.jiayue.ipfcst.dataexchange.tunnelworker.gathers.iml.ModbusTcpDataGather;
import lombok.Getter;
import lombok.Setter;
import org.joda.time.DateTime;

import java.net.InetSocketAddress;
import java.util.List;

/**
 * 通道信息的抽象类，用以实时储存、管理、改变、查询通道的状态
 *
 * @author 修唯xiuwei
 * @version 3.0
 */
@Getter
@Setter
public abstract class BaseProtocolTunnel<T extends BaseTunnelInfo> {


  protected Logger log;
  /**
   * 该通道的信息及其负责采集的点位
   */
  @JSONField(serialize = false)
  protected T tunnelInfo;
  /**
   * 通道的ID
   */
  protected String tunnelId;
  /**
   * 通道的类型
   */
  protected TunnelType tunnelType;
  /**
   * 连接接信息
   */
  @JSONField(serialize = false)
  protected List<InetSocketAddress> connectors;
  /**
   * 通道容器
   */
  protected ProtocolTunnelContainer protocolTunnelContainer = ProtocolTunnelContainer.getInstance();
  /**
   * 通道的状态
   */
  private TunnelStatus tunnelStatus;

  /**
   * 顶层的构造方法
   *
   * @param tunnelInfo 通道信息
   */
  public BaseProtocolTunnel(T tunnelInfo) {
    this.tunnelInfo = tunnelInfo;
    this.tunnelType = tunnelInfo.getTunnelType();
    this.tunnelId = tunnelInfo.getId();
    this.log = TunnelLoggerFactory.getLogger(tunnelId, tunnelInfo.getTunnelName());
  }

  public synchronized void setTunnelStatus(TunnelStatus tunnelStatus) {
    if (TunnelStatus.ACTIVECLOSE.equals(getTunnelStatus()) && TunnelStatus.LOSECONN.equals(tunnelStatus)) {
      return;
    } else {
      this.tunnelStatus = (tunnelStatus);
    }
    try {
      ChannelDisconLogService channelDisconLogService = SpringContextHolder.getBean(ChannelDisconLogService.class);
      List<ChannelDisconLog> channelList = channelDisconLogService.get(tunnelId);
      ChannelDisconLog channelDisconLog = null;
      //连接成功的状态
      if (TunnelStatus.CONNECTED.equals(getTunnelStatus()) || TunnelStatus.LISTENPORTSUCCESS.equals(getTunnelStatus()) || TunnelStatus.LISTENSERIALSUCCESS.equals(getTunnelStatus())) {
        if (channelList.size() != 0) {
          channelDisconLog = channelList.get(channelList.size() - 1);
          channelDisconLog.setReconnectTime(DateTime.now().getMillis());
          channelDisconLog.countAndSetDuration();
          channelDisconLogService.save(channelDisconLog);
        }
      } else if (TunnelStatus.ACTIVECLOSE.equals(getTunnelStatus()) || TunnelStatus.LOSECONN.equals(getTunnelStatus()) || TunnelStatus.CONNECTING.equals(getTunnelStatus())) {
      //通道断开的状态
      /*  if (this instanceof Iec104TcpDataGather) {
          new Thread(() -> {
            String str = RuntimeUtil.execForStr("ping " + ((Iec104TcpDataGather) this).getTunnelInfo().getRemoteIp() + " -c 4");
            getLog().info("ping远程IP结果:" + str);
          }).run();
        } else if (this instanceof ModbusTcpDataGather) {
          new Thread(() -> {
            String str = RuntimeUtil.execForStr("ping " + ((ModbusTcpDataGather) this).getTunnelInfo().getRemoteIp() + " -c 4");
            getLog().info("ping远程IP结果:" + str);
          }).run();
        }*/
        if (channelList.size() == 0) {
          channelDisconLog = new ChannelDisconLog();
          channelDisconLog.setChannelId(this.tunnelId);
          channelDisconLog.setChannelName(this.tunnelInfo.getTunnelName());
          channelDisconLog.setDisconnectTime(DateTime.now().getMillis());
          channelDisconLogService.save(channelDisconLog);
        }
      }
    } catch (Exception e) {
      log.error("在向数据库置入断线记录是发生异常" + e);
    }

  }

  /**
   * 开启通道通讯
   *
   * @return AbstractDataGather abstract data gather
   * @throws DataExchangeException 抛出自定义的异常
   */
  public  abstract  BaseProtocolTunnel startTunnel() throws DataExchangeException;

  /**
   * 创建不同协议对应的通道
   *
   * @return AbstractDataGather abstract data gather
   * @throws DataExchangeException 抛出自定义的异常
   */
  public abstract BaseProtocolTunnel buildTunnel() throws DataExchangeException;


  /**
   * 更新通道信息
   *
   * @param tunnelInfo 通道信息
   * @return 实体本身
   */
  public BaseProtocolTunnel refreshTunnelInfo(T tunnelInfo) {
    log.info("刷新{}的通道信息及点位", tunnelInfo.getTunnelName());
    this.tunnelInfo = tunnelInfo;
    TunnelLoggerFactory.stop(this.getLog());
   this.setLog(TunnelLoggerFactory.getLogger(tunnelId, tunnelInfo.getTunnelName()));
    return this;
  }

  /**
   * 解析采集数据点表
   *
   * @throws DataExchangeException 自定义异常
   */
  public abstract void parseGatherDataPoint() throws DataExchangeException;


  /**
   * 通道停止
   * 停止 关闭通道
   *
   * @return {@link BaseProtocolTunnel}
   * @throws DataExchangeException 数据交换异常
   */
  public BaseProtocolTunnel tunnelStop() throws DataExchangeException {
    setTunnelStatus(TunnelStatus.ACTIVECLOSE);
    protocolTunnelContainer.stopUpdateTask(this.tunnelId);
    TunnelLoggerFactory.stop(log);
    return this;
  }


  public JSONObject getJSONObj() {
    JSONObject jsonObject = new JSONObject();
    jsonObject.put("tunnelId", this.tunnelId);
    jsonObject.put("tunnelName", this.tunnelInfo.getTunnelName());
    jsonObject.put("tunnelType", this.tunnelType);
    jsonObject.put("tunnelStatus", this.tunnelStatus);
    return jsonObject;
  }

}
