package com.jiayue.ipfcst.client.protocol2file;


import com.syjy.DataExchangeException;
import com.syjy.container.ProtocolDataContainer;
import com.syjy.tunnelinfo.DataPoint;
import com.syjy.tunnelinfo.TunnelStatus;
import com.syjy.tunnelworker.BaseProtocolTunnel;
import com.syjy.tunnelworker.gathers.DataGatherInterface;
import com.syjy.tunnelworker.workassist.SingleThreadPoolExecutorUtil;
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.MasterInterface;

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

/**
 * modbus协议TCP数据采集
 *
 * @author 修唯xiuwei
 * @version 3.0
 */

public class ModbusRtuDataGatherWithTcpServer extends BaseProtocolTunnel<GatherModbusRtuByTcpServerTunnelInfo, ModbusRtuMasterWithTcpServer> implements DataGatherInterface {

	/**
	 * 通道点位  ---- 点位对象
	 */
	Map<Integer, DataPoint> dataPointMap;


	/**
	 * 0: 线圈   1：寄存器
	 */
	private  int functionFlag ;

	/**
	 * 向modbus slave端发送的请求
	 */
	private List<Obj4RequestRegister> requestRegisterList;


	/**
	 * 向modbus slave端发送线圈的请求
	 */
	private List<Obj4RequestCoil> requestCoilList;


	/**
	 * 构造方法
	 *
	 * @param gatherModbusRtuByTcpServerTunnelInfo 通道信息
	 */
	public ModbusRtuDataGatherWithTcpServer(final GatherModbusRtuByTcpServerTunnelInfo gatherModbusRtuByTcpServerTunnelInfo) {
		super(gatherModbusRtuByTcpServerTunnelInfo);
	}

	@Override
	public ModbusRtuDataGatherWithTcpServer buildTunnel() throws DataExchangeException {
		protocolBuilder = new MyModbusRtuMasterWithTcpServer(tunnelInfo.getSelfPort());
		protocolBuilder.setLog(this.log);
		setTunnelStatus(TunnelStatus.BUILT);
		protocolTunnelContainer.addTunnel(this);
		log.info("成功创建ModbusTCPMaster通道对象：{}", this.tunnelInfo.getTunnelName());
		return this;
	}

	@Override
	public void parseGatherDataPoint() throws DataExchangeException {
		log.info("解析该通道下所管理的点位");
		List<DataPoint> dataPoints = this.tunnelInfo.getDataPoints();
		if (dataPoints == null || dataPoints.size() == 0) {
			return;
		}
		if (this.tunnelInfo.getFunctionCode() == 1 || this.tunnelInfo.getFunctionCode() == 2) {
			functionFlag =0;
		}else {
			functionFlag =1;
		}
		Map<Integer, ModbusDataTypeEnum> points = new HashMap<>();
		List<Integer> coilPoints = new ArrayList<>();
		this.dataPointMap = new HashMap<>();
		if (functionFlag ==0) {
			for (DataPoint d : dataPoints) {
				this.dataPointMap.put(d.getProtocolPoint(), d);
				coilPoints.add(d.getProtocolPoint());
			}
			try {
				this.requestCoilList=ModbusRequestDataUtils.splitModbusRequest(coilPoints, this.tunnelInfo.getSlaveId(), FunctionCode.valueOf(this.tunnelInfo.getFunctionCode()));
			} catch (ModbusException e) {
				throw new DataExchangeException(e.getCode(), e.getMsg());
			}
		} else {
			for (DataPoint d : dataPoints) {
				this.dataPointMap.put(d.getProtocolPoint(), d);
				points.put(d.getProtocolPoint(), d.getDataType());
			}
			try {
				this.requestRegisterList=ModbusRequestDataUtils.splitModbusRequest(points, this.tunnelInfo.getSlaveId(), FunctionCode.valueOf(this.tunnelInfo.getFunctionCode()));
			} catch (ModbusException e) {
				throw new DataExchangeException(e.getCode(), e.getMsg());
			}
		}
		log.info("解析该通道下所管理的点位完成");
	}


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


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


	@Override
	public void getDataFromProtocol() throws DataExchangeException {
		if (this.protocolBuilder.getChannels().size() == 0) {
			log.trace("当前没有客户端联入");
			setTunnelStatus(TunnelStatus.LISTENPORTSUCCESSANDNOCONN);
			return;
		}
		log.info("获取到从通道中获取的点位");
		try {
			if(functionFlag ==1  && this.requestRegisterList!=null) {
				Map<Integer, IModbusDataType> map = ModbusRequestDataUtils.getRegisterData((MasterInterface) this.protocolBuilder, this.requestRegisterList);
				if (map==null ||map.size()==0){
					this.setTunnelStatus(TunnelStatus.LISTENPORTSUCCESSANDCONNANDCOMMERROR);
				}else{
					this.setTunnelStatus(TunnelStatus.LISTENPORTSUCCESSANDCONN);
				}
				for (Integer i : map.keySet()) {
					if (map.get(i) instanceof NumericModbusData) {
						if (map==null ||map.size()==0){
							this.setTunnelStatus(TunnelStatus.LISTENPORTSUCCESSANDCONNANDCOMMERROR);
						}else{
							this.setTunnelStatus(TunnelStatus.LISTENPORTSUCCESSANDCONN);
						}
						ProtocolDataContainer.getInstance().putNumber(dataPointMap.get(i).getId(), ((NumericModbusData) map.get(i)).getValue().multiply(BigDecimal.valueOf(dataPointMap.get(i).getMag())));
					} else {
						ProtocolDataContainer.getInstance().putBoolean(dataPointMap.get(i).getId(), ((BooleanModbusDataInRegister) map.get(i)).getValue(0));
					}
				}
			}else if(functionFlag==0 && this.requestCoilList!=null){
				Map<Integer, Boolean> map = ModbusRequestDataUtils.getCoilData(this.protocolBuilder, this.requestCoilList);
				for (Integer i : map.keySet()) {
						ProtocolDataContainer.getInstance().putBoolean(dataPointMap.get(i).getId(), map.get(i));
				}
			}
		} catch (ModbusException e) {
			if("无客户端连接".equals(e.getMsg())){
				this.setTunnelStatus(TunnelStatus.LISTENPORTSUCCESSANDNOCONN);
			}
			this.setTunnelStatus(TunnelStatus.LISTENPORTSUCCESSANDCONNANDCOMMERROR);
			throw new DataExchangeException(0,e.getMsg());
		}
	}



	class MyModbusRtuMasterWithTcpServer extends ModbusRtuMasterWithTcpServer{

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

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

}
