package com.yeejoin.amos.iec104.tcp.server.session;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Predicate;

import com.yeejoin.amos.connect.dao.entity.ConfigVo;
import com.yeejoin.amos.connect.dao.entity.PointConfigVo;
import org.apache.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.util.ObjectUtils;

import com.yeejoin.amos.iec104.business.service.intfc.IConfService;
import com.yeejoin.amos.iec104.business.service.intfc.IPointConfigService;
import com.yeejoin.amos.iec104.context.FireAutoIntfContext;
import com.yeejoin.amos.iec104.tcp.entity.Apdu;
import com.yeejoin.amos.iec104.tcp.entity.Asdu;
import com.yeejoin.amos.iec104.tcp.utils.ChangeUtils;
import com.yeejoin.amos.iec104.tcp.utils.GenerateDate;

import io.netty.channel.ChannelHandlerContext;

public class Session {

	ChannelHandlerContext ctx;
	private String commonAddr = "";
	private String infoAddr = "";
	private String channelNo = "";
	int receiveNum = 0;
	int sendNum = 0;
	long timeRecorder = 0;
	private long recordTime = 0;
	private ReentrantLock serialLock = new ReentrantLock();
//	private Semaphore secruitingSemaphore = new Semaphore(1);
//	boolean startCommunication = false;
	boolean stopCommunication = false;
	boolean startRecruiting = false;
	CountDownLatch latch;
	private Semaphore recruitingSemaphore = new Semaphore(1);
	boolean recIpackate = false;
	private  BlockingQueue<Apdu> handleBlockingRecQueue = new LinkedBlockingQueue<Apdu>();
	private  BlockingQueue<String> handleBlockingSendQueue = new LinkedBlockingQueue<String>();
	
	private  BlockingQueue<PointConfigVo> SOEBlockingRecQueue = new LinkedBlockingQueue<PointConfigVo>();
	private  BlockingQueue<PointConfigVo> SECBlockingRecQueue = new LinkedBlockingQueue<PointConfigVo>();
	
	ScheduledExecutorService test_Communication = null;
	ScheduledExecutorService eecruiting_Communication = null;
	ScheduledExecutorService send_Communication = null;
	ScheduledExecutorService ack_Communication = null;
	ScheduledExecutorService rec_Communication = null;
	ScheduledExecutorService soe_Communication = null;
	ScheduledExecutorService sec_Communication = null;
	
	private  IPointConfigService pointConfigService;
	private  IConfService confService;
	
	public Session(ChannelHandlerContext ctx) {
		this.ctx  = ctx;
		pointConfigService = (IPointConfigService) FireAutoIntfContext.getInstance().getBean(IPointConfigService.class);
		confService = (IConfService) FireAutoIntfContext.getInstance().getBean(IConfService.class);
		InetSocketAddress socket =  (InetSocketAddress) this.ctx.channel().localAddress();
		ConfigVo client = confService.getServerByPort(socket.getPort()+"");
		channelNo = client.getChannelNo();
		
		addTestlistener();
		addSendDatalistener();
		addRecruitingDatalistener();
		addACKDatalistener();
		addRecDatalistener();
		addSOEDataListener();
		addSECDataListener();
	}
	
	public void addSOE(PointConfigVo soe) {
		SOEBlockingRecQueue.add(soe);
	}
	public void addSEC(PointConfigVo soe) {
		SECBlockingRecQueue.add(soe);
	}

	private void addSECDataListener() {
		sec_Communication = Executors.newSingleThreadScheduledExecutor();
        // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间
		sec_Communication.execute(sec_runnable);;
	}

	Runnable sec_runnable = new Runnable() {
		
		@Override
		public void run() {
			while(!stopCommunication) {
				try {
			        PointConfigVo vo = SECBlockingRecQueue.take();
//					int len = 0;
					PointConfigVo p = null;
					StringBuffer strAsduDataBytes = new StringBuffer();
//					int sendCount = 0;
//					do {
						if (!ObjectUtils.isEmpty(vo)) {
							p = new PointConfigVo();
							BeanUtils.copyProperties(vo, p);
							vo = null;
						} 
//						else {
//							p = SECBlockingRecQueue.poll();
//						}
						if (ObjectUtils.isEmpty(p)) {
							break;
						}
						if ("yc".equals(p.getPointType())) {
							p.setOriginatorAddress(p.getOriginatorAddress() + 0x4000);
						}
						strAsduDataBytes.append(ChangeUtils.encodeInfomationAddress(p.getOriginatorAddress())); // 信息体地址，3个字节
						if (p.getOriginatorAddress() < 0x4000) {
							String status = Integer.toHexString(Integer.valueOf(p.getValue()));
					        status = status.length() > 1? status : "0".concat(status);
					        strAsduDataBytes.append(status); // 点状态  正常   合格  不合格  漏检
//					        len++;
						} else {
							String sendData = "";
							byte[] elements = ChangeUtils.float2byte(Float.parseFloat(p.getValue()));
					        sendData = sendData + ChangeUtils.toHexString(elements);
					        sendData = sendData + Integer.toHexString(0x80 | 0);
					        strAsduDataBytes.append(sendData); // 点状态  正常   合格  不合格  漏检
//					        len += 4;
						}
//				        sendCount++;
//					} while(len < 240);
					StringBuffer strAsduBytes = new StringBuffer(); 
					if ("yc".equals(p.getPointType())) {
						strAsduBytes.append("0D");
					} else {
						strAsduBytes.append("01");
					}
					String strSoeCount = Integer.toHexString(1);
					strAsduBytes.append(strSoeCount.length() > 1? strSoeCount : "0".concat(strSoeCount)); // 可变结构限定词，1个SEC
					strAsduBytes.append("0300"); // 传送原因，2个字节，3-表突发事件
					strAsduBytes.append(commonAddr); // 公共地址，2个字节	
					strAsduBytes.append(strAsduDataBytes);
					String dataUnitLen = Integer.toHexString(strAsduBytes.toString().replace(" ", "").length() / 2 + 4);
			        String length = dataUnitLen.length() > 1 ? dataUnitLen : "0".concat(dataUnitLen);
			        
			        serialLock.lock();
			        byte[] sendNumBytes = new byte[2];
					byte[] recNumBytes = new byte[2];
			        sendNumBytes[0] = (byte) (sendNum << 1);
					sendNumBytes[1] = (byte) (sendNum >> 7);
			        
					recNumBytes[0] = (byte) (receiveNum << 1);
			        recNumBytes[1] = (byte) (receiveNum >> 7);
			        
			        String recStr = ChangeUtils.toHexString(recNumBytes);
			        String sendStr = ChangeUtils.toHexString(sendNumBytes);
			        sendNum ++;
					String dataStr = "68" + length +  sendStr +  recStr + strAsduBytes.toString().replace(" ", "");
					Logger.getLogger(this.getClass()).debug("SEC 报文为： " + dataStr);
					handleBlockingSendQueue.add(dataStr);
					
					serialLock.unlock();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	};

	private void addSOEDataListener() {
		soe_Communication = Executors.newSingleThreadScheduledExecutor();
        // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间
		soe_Communication.execute(soe_runnable);;
	}
	
	Runnable soe_runnable = new Runnable() {
		
		@Override
		public void run() {
			while(!stopCommunication) {
				try {
			        PointConfigVo vo = SOEBlockingRecQueue.take();
					int len = 0;
					PointConfigVo p = null;
					StringBuffer strAsduDataBytes = new StringBuffer();
					int sendCount = 0;
					do {
						if (!ObjectUtils.isEmpty(vo)) {
							p = new PointConfigVo();
							BeanUtils.copyProperties(vo, p);
							vo = null;
						} else {
							p = SOEBlockingRecQueue.poll();
						}
						if (ObjectUtils.isEmpty(p)) {
							break;
						}
						strAsduDataBytes.append(ChangeUtils.encodeInfomationAddress(p.getOriginatorAddress())); // 信息体地址，3个字节

						String status = Integer.toHexString(Integer.valueOf(p.getValue()));
				        status = status.length() > 1? status : "0".concat(status);
				        strAsduDataBytes.append(status); // 点状态  正常   合格  不合格  漏检
				        strAsduDataBytes.append(GenerateDate.getCP56Time2a());
				        len += 4;
				        sendCount++;
					} while(len < 240);
					StringBuffer strAsduBytes = new StringBuffer("1E"); 
					String strSoeCount = Integer.toHexString(sendCount);
					strAsduBytes.append(strSoeCount.length() > 1? strSoeCount : "0".concat(strSoeCount)); // 可变结构限定词，1个SOE
					strAsduBytes.append("0300"); // 传送原因，2个字节，3-表突发事件
					strAsduBytes.append(commonAddr); // 公共地址，2个字节	
					strAsduBytes.append(strAsduDataBytes.toString());
					String dataUnitLen = Integer.toHexString(strAsduBytes.toString().replace(" ", "").length() / 2 + 4);
			        String length = dataUnitLen.length() > 1 ? dataUnitLen : "0".concat(dataUnitLen);
			        
			        serialLock.lock();
			        byte[] sendNumBytes = new byte[2];
					byte[] recNumBytes = new byte[2];
			        sendNumBytes[0] = (byte) (sendNum << 1);
					sendNumBytes[1] = (byte) (sendNum >> 7);
			        
					recNumBytes[0] = (byte) (receiveNum << 1);
			        recNumBytes[1] = (byte) (receiveNum >> 7);
			        
			        String recStr = ChangeUtils.toHexString(recNumBytes);
			        String sendStr = ChangeUtils.toHexString(sendNumBytes);
			        sendNum ++;
					String dataStr = "68" + length +  sendStr +  recStr + strAsduBytes.toString().replace(" ", "");
					Logger.getLogger(this.getClass()).debug("soe 报文为： " + dataStr);
					handleBlockingSendQueue.add(dataStr);
					
					serialLock.unlock();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	};


	private void addRecDatalistener() {
		rec_Communication = Executors.newSingleThreadScheduledExecutor();
        // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间
		rec_Communication.execute(data_runnable);;
	}


	private void addACKDatalistener() {
		timeRecorder = new Date().getTime();
		ack_Communication = Executors.newSingleThreadScheduledExecutor();
        // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间
		ack_Communication.scheduleAtFixedRate(ack_runnable, 1, 1, TimeUnit.SECONDS);
	}
	
	Runnable ack_runnable = new Runnable() {
		
		@Override
		public void run() {
			long currentTime = new Date().getTime();
			if (recIpackate && ((currentTime - timeRecorder) / 1000) > 3) {
				recIpackate = false;
				byte[] recNum = new byte[2];
		        recNum[0] = (byte) (receiveNum << 1);
		        recNum[1] = (byte) (receiveNum >> 7);
		        String recStr = ChangeUtils.toHexString(recNum);
		        ctx.channel().writeAndFlush("68040100" + recStr);
			}
		}
	};

	private void addRecruitingDatalistener() {
//		latch = new CountDownLatch(1); 
		eecruiting_Communication = Executors.newSingleThreadScheduledExecutor();
        // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间
		eecruiting_Communication.execute(Recruiting_runnable);;
	}

	private void addSendDatalistener() {
		send_Communication = Executors.newSingleThreadScheduledExecutor();
        // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间
		send_Communication.execute(send_runnable);;
	}
	
	Runnable send_runnable = new Runnable() {
		
		@Override
		public void run() {
			while(!stopCommunication) {
				try {
					String data = handleBlockingSendQueue.take();
					ctx.channel().writeAndFlush(data.replace(" ", ""));
					recIpackate = false;
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	};
	
	public void respondTiming(Apdu apdu) {
		Asdu asdu = apdu.getAsdu();
		
		byte[] send =  new byte[2];
		byte[] rec = new byte[2];
		serialLock.lock();
		send[0] = (byte) (sendNum << 1);
		send[1] = (byte) (sendNum >> 7);
			
        rec[0] = (byte) (receiveNum << 1);
        rec[1] = (byte) (receiveNum >> 7);
        
        String recStr = ChangeUtils.toHexString(rec);
        String sendStr = ChangeUtils.toHexString(send);
        sendNum ++;
        serialLock.unlock();
    	String jihuoQueRen = "6814" + 
				sendStr + 
    			recStr + 
				"67010700" + 
				ChangeUtils.encodeCommonAddress(asdu.getCommonAddress()) + 
				ChangeUtils.encodeInfomationAddress(asdu.getOriginatorAddress()) + 
				GenerateDate.getCP56Time2a();
    	commonAddr = ChangeUtils.encodeCommonAddress(asdu.getCommonAddress());
    	infoAddr = ChangeUtils.encodeCommonAddress(asdu.getOriginatorAddress());
    	recIpackate = false;
        handleBlockingSendQueue.add(jihuoQueRen.replace(" ", ""));
	}
	
	Runnable data_runnable = new Runnable() {
		
		@Override
		public void run() {
			while(!stopCommunication) {
				try {
					Apdu apdu = handleBlockingRecQueue.take();
					Asdu asdu = apdu.getAsdu();
					if (asdu.getTypeId() == 100) { //服务端接收处理客户端总招请求
						respondRecruiting(apdu);
					} else if (asdu.getTypeId() == 103) { //服务端接收处理客户端总招请求
						respondTiming(apdu);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	};
	
	Runnable Recruiting_runnable = new Runnable() {
		
		@Override
		public void run() {
			while(!stopCommunication) {
				try {
//					latch.await();
					recruitingSemaphore.acquire();
				} catch (Exception e) {
				}
				Logger.getLogger(this.getClass()).info("start process Recruiting 1");
				while(startRecruiting) {
					Logger.getLogger(this.getClass()).info("start process Recruiting 2");
					try {
						List<PointConfigVo> yx = pointConfigService.getAllYXPointData(channelNo);
						
						if (!ObjectUtils.isEmpty(yx) && yx.size() > 0) {
							Logger.getLogger(this.getClass()).info("start process yx Recruiting");
							recIpackate = false;
							String infomationAddress = ChangeUtils.encodeInfomationAddress(yx.get(0).getOriginatorAddress());
							Iterator<PointConfigVo> it = yx.iterator();
							do {
								int len = 0;
								String sendData = "";
								do {
									PointConfigVo p = it.next();
									if (ObjectUtils.isEmpty(infomationAddress)) {
										infomationAddress = ChangeUtils.encodeInfomationAddress(p.getOriginatorAddress());
									}
									String status = "";
									String value = ObjectUtils.isEmpty(p.getValue()) ? "0" : p.getValue();
									if (p.getInvalid()) {
										status = Integer.toHexString(Integer.valueOf(value) | 0x80);
									} else {
										status = Integer.toHexString(Integer.valueOf(value));
									}

							        status = status.length() > 1? status : "0".concat(status);
							        sendData = sendData + status;
							        len++;
								} while(it.hasNext() && len < 126);
								StringBuffer strAsduBytes = new StringBuffer("01"); // 
								strAsduBytes.append(Integer.toHexString(0x80 | len)); // 
								strAsduBytes.append("1400"); // 
								strAsduBytes.append(commonAddr); // 
								strAsduBytes.append(infomationAddress); // 信息体地址，3个字节
								infomationAddress = null;
								strAsduBytes.append(sendData);
								String dataUnitLen = Integer.toHexString(strAsduBytes.toString().replace(" ", "").length() / 2 + 4);
						        String length = dataUnitLen.length() > 1 ? dataUnitLen : "0".concat(dataUnitLen);
						        
						        serialLock.lock();
						        byte[] sendNumBytes = new byte[2];
								byte[] recNumBytes = new byte[2];
						        sendNumBytes[0] = (byte) (sendNum << 1);
								sendNumBytes[1] = (byte) (sendNum >> 7);
						        
								recNumBytes[0] = (byte) (receiveNum << 1);
						        recNumBytes[1] = (byte) (receiveNum >> 7);
						        
						        String recStr = ChangeUtils.toHexString(recNumBytes);
						        String sendStr = ChangeUtils.toHexString(sendNumBytes);
						        sendNum ++;
								String dataStr = "68" + length +  sendStr +  recStr + strAsduBytes.toString().replace(" ", "");
								Logger.getLogger(this.getClass()).debug("yx 报文为： " + dataStr);
								handleBlockingSendQueue.add(dataStr);
								
								serialLock.unlock();
							} while(it.hasNext());
						}
						List<PointConfigVo> yc = pointConfigService.getAllYCPointData(channelNo);
						if (!ObjectUtils.isEmpty(yc) && yc.size() > 0) {
							Logger.getLogger(this.getClass()).info("start process yc Recruiting");
							recIpackate = false;
							String infomationAddress = ChangeUtils.encodeInfomationAddress(yc.get(0).getOriginatorAddress() + 0x4000);
							Iterator<PointConfigVo> it = yc.iterator();
							do {
								int len = 0;
								String sendData = "";
								do {
									PointConfigVo p = it.next();

									String value = ObjectUtils.isEmpty(p.getValue()) ? "0" : p.getValue();
									if (ObjectUtils.isEmpty(infomationAddress)) {
										infomationAddress = ChangeUtils.encodeInfomationAddress(p.getOriginatorAddress() + 0x4000);
									}
									byte[] elements = ChangeUtils.float2byte(Float.parseFloat(value));
							        sendData = sendData + " " + ChangeUtils.toHexString(elements);
							        sendData = sendData + Integer.toHexString(0x80 | 0);
							        len ++;
								} while(it.hasNext() && len < 120);
								StringBuffer strAsduBytes = new StringBuffer("0D"); // 
								strAsduBytes.append(Integer.toHexString(0x80 | len)); // 
								strAsduBytes.append("1400"); // 
								strAsduBytes.append(commonAddr); // 
								strAsduBytes.append(infomationAddress); // 信息体地址，3个字节
								infomationAddress = null;
								strAsduBytes.append(sendData);
								String dataUnitLen = Integer.toHexString(strAsduBytes.toString().replace(" ", "").length() / 2 + 4);
						        String length = dataUnitLen.length() > 1 ? dataUnitLen : "0".concat(dataUnitLen);
						        
						        serialLock.lock();
						        byte[] sendNumBytes = new byte[2];
								byte[] recNumBytes = new byte[2];
						        sendNumBytes[0] = (byte) (sendNum << 1);
								sendNumBytes[1] = (byte) (sendNum >> 7);
						        
								recNumBytes[0] = (byte) (receiveNum << 1);
						        recNumBytes[1] = (byte) (receiveNum >> 7);
						        
						        String recStr = ChangeUtils.toHexString(recNumBytes);
						        String sendStr = ChangeUtils.toHexString(sendNumBytes);
						        sendNum ++;
								String dataStr = "68" + length +  sendStr +  recStr + strAsduBytes.toString();
								handleBlockingSendQueue.add(dataStr.replace(" ", ""));
								recIpackate = false;
								serialLock.unlock();
							} while(it.hasNext());
						}
	
						serialLock.lock();
				        byte[] sendNumBytes = new byte[2];
						byte[] recNumBytes = new byte[2];
				        sendNumBytes[0] = (byte) (sendNum << 1);
						sendNumBytes[1] = (byte) (sendNum >> 7);
				        
						recNumBytes[0] = (byte) (receiveNum << 1);
				        recNumBytes[1] = (byte) (receiveNum >> 7);
				        
				        String recStr = ChangeUtils.toHexString(recNumBytes);
				        String sendStr = ChangeUtils.toHexString(sendNumBytes);
				        sendNum ++;
				        serialLock.unlock();
			            //发送总招  激活终止
			            String jihuoStop = "680E" + 
			            		sendStr+ 
			            		 recStr + 
			    				"64010A00" + 
			    				commonAddr + 
			    				"000000" + 
			    				"14";
			            handleBlockingSendQueue.add(jihuoStop.replace(" ", ""));
					} catch (Exception e) {
						e.printStackTrace();
					}
					startRecruiting = false;
				} 
			}
		}
	};

	protected void respondRecruiting(Apdu apdu) {
		byte[] sendNumBytes = new byte[2];
		byte[] recNumBytes = new byte[2];
		try {
			serialLock.lock();
			sendNumBytes[0] = (byte) (sendNum << 1);
			sendNumBytes[1] = (byte) (sendNum >> 7);
	        
			recNumBytes[0] = (byte) (receiveNum << 1);
	        recNumBytes[1] = (byte) (receiveNum >> 7);
	        
	        String recStr = ChangeUtils.toHexString(recNumBytes);
	        String sendStr = ChangeUtils.toHexString(sendNumBytes);
	        sendNum ++;
	        
	        if (apdu.getAsdu().getCauseOfTransmission() == 6) {
	        	Asdu asdu = apdu.getAsdu();
		    	String jihuoQueRen = "680E" + 
						sendStr + 
		    			recStr + 
						"64010700" + 
						ChangeUtils.encodeCommonAddress(asdu.getCommonAddress()) + 
						ChangeUtils.encodeInfomationAddress(asdu.getOriginatorAddress()) + 
						"14";
		    	startRecruiting = true;
//		    	latch.countDown();
		    	recruitingSemaphore.release();
		    	handleBlockingSendQueue.add(jihuoQueRen.replace(" ", ""));
		    	recIpackate = false;
		        //secruitingSemaphore.release(); // 释放一个许可
	        }
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			serialLock.unlock();
		}
	}
	
	public void processPoints(List<PointConfigVo> points) {
		change(points); //变为消息
		soe(points);
	}
	
	public static List<PointConfigVo> filter(List<PointConfigVo> points, Predicate<PointConfigVo> condition) {
		List<PointConfigVo> results = new ArrayList<PointConfigVo>();
		for (PointConfigVo c : points) {
			if(condition.test(c)) {
				results.add(c);
	        }
		}
		return results;
	}
	

	private void soe(List<PointConfigVo> points) {
		List list = filter(points, (c) -> c.getOriginatorAddress() < 0x4000);
		if (list.size() <= 0) return; 
		Iterator<PointConfigVo> it = list.iterator();
		//处理遥信数据
		do {
			StringBuffer strAsduBytes = new StringBuffer("1E"); 
			StringBuffer strAsduDataBytes = new StringBuffer();

			int byteNumber = 0;
			int soeNumber = 0;
			do {
				PointConfigVo point = it.next();
				strAsduDataBytes.append(ChangeUtils.encodeInfomationAddress(point.getOriginatorAddress())); // 信息体地址，3个字节

				String status = Integer.toHexString(Integer.valueOf(point.getValue()));
		        status = status.length() > 1? status : "0".concat(status);
		        strAsduDataBytes.append(status); // 点状态  正常   合格  不合格  漏检
		        strAsduDataBytes.append(GenerateDate.getCP56Time2a());
		        byteNumber += 8;
		        soeNumber++;
			} while(it.hasNext() && byteNumber < 230);

			strAsduBytes.append((soeNumber+"").length() > 1? (soeNumber+"") : "0".concat(soeNumber+"")); // 可变结构限定词，1个SOE
			strAsduBytes.append("0300"); // 传送原因，2个字节，3-表突发事件
			strAsduBytes.append(commonAddr); // 公共地址，2个字节	
			strAsduBytes.append(strAsduDataBytes);
			int apduLen = strAsduBytes.toString().replace(" ", "").length() / 2 + 4;
			String len = Integer.toHexString(apduLen).length() > 1? Integer.toHexString(apduLen): "0".concat(Integer.toHexString(apduLen));
			serialLock.lock();
			byte[] sendNumBytes = new byte[2];
			byte[] recNumBytes = new byte[2];
			sendNumBytes[0] = (byte) (sendNum << 1);
			sendNumBytes[1] = (byte) (sendNum >> 7);
	        
			recNumBytes[0] = (byte) (receiveNum << 1);
	        recNumBytes[1] = (byte) (receiveNum >> 7);
	        
	        String recStr = ChangeUtils.toHexString(recNumBytes);
	        String sendStr = ChangeUtils.toHexString(sendNumBytes);
	        sendNum ++;
			String soe = "68" + len +  sendStr +  recStr + strAsduBytes.toString();
			handleBlockingSendQueue.add(soe.replace(" ", ""));
			serialLock.unlock();
		} while(it.hasNext());
	}


	private void change(List<PointConfigVo> points) {
		List yc = filter(points, (c) -> c.getOriginatorAddress() > 0x4000);
		List yx = filter(points, (c) -> c.getOriginatorAddress() <= 0x4000);
		if (yc.size() > 0) {
			//处理遥测数据
			Iterator<PointConfigVo> it = yc.iterator();
			do {
				StringBuffer strAsduBytes = new StringBuffer("01"); 
				StringBuffer strAsduDataBytes = new StringBuffer();

				int byteNumber = 0;
				int soeNumber = 0;
				do {
					PointConfigVo point = it.next();
					if (validateThreshold(point)) {
						strAsduDataBytes.append(ChangeUtils.encodeInfomationAddress(point.getOriginatorAddress())); // 信息体地址，3个字节

						byte[] elements = ChangeUtils.float2byte(Float.parseFloat(point.getValue()));
				        strAsduDataBytes.append(ChangeUtils.toHexString(elements)); // 
				        byteNumber += 4;
				        soeNumber++;
					}
				} while(it.hasNext() && byteNumber < 230);

				strAsduBytes.append((soeNumber+"").length() > 1? (soeNumber+"") : "0".concat(soeNumber+"")); // 可变结构限定词，1个SOE
				strAsduBytes.append("0300"); // 传送原因，2个字节，3-表突发事件
				strAsduBytes.append(commonAddr); // 公共地址，2个字节	
				strAsduBytes.append(strAsduDataBytes);
				int apduLen = strAsduBytes.toString().replace(" ", "").length() / 2 + 4;
				String len = Integer.toHexString(apduLen).length() > 1? Integer.toHexString(apduLen): "0".concat(Integer.toHexString(apduLen));
				serialLock.lock();
				byte[] sendNumBytes = new byte[2];
				byte[] recNumBytes = new byte[2];
				sendNumBytes[0] = (byte) (sendNum << 1);
				sendNumBytes[1] = (byte) (sendNum >> 7);
		        
				recNumBytes[0] = (byte) (receiveNum << 1);
		        recNumBytes[1] = (byte) (receiveNum >> 7);
		        
		        String recStr = ChangeUtils.toHexString(recNumBytes);
		        String sendStr = ChangeUtils.toHexString(sendNumBytes);
		        sendNum ++;
				String soe = "68" + len +  sendStr +  recStr + strAsduBytes.toString();
				handleBlockingSendQueue.add(soe.replace(" ", ""));
				serialLock.unlock();
			} while(it.hasNext());
		} 
		if (yx.size() > 0) {
			//处理遥信数据
			Iterator<PointConfigVo> it = yx.iterator();
			//处理遥信数据
			do {
				StringBuffer strAsduBytes = new StringBuffer("01"); 
				StringBuffer strAsduDataBytes = new StringBuffer();

				int byteNumber = 0;
				int soeNumber = 0;
				do {
					PointConfigVo point = it.next();
					strAsduDataBytes.append(ChangeUtils.encodeInfomationAddress(point.getOriginatorAddress())); // 信息体地址，3个字节

					String status = Integer.toHexString(Integer.valueOf(point.getValue()));
			        status = status.length() > 1? status : "0".concat(status);
			        strAsduDataBytes.append(status); // 点状态  正常   合格  不合格  漏检
			        byteNumber += 8;
			        soeNumber++;
				} while(it.hasNext() && byteNumber < 230);

				strAsduBytes.append((soeNumber+"").length() > 1? (soeNumber+"") : "0".concat(soeNumber+"")); // 可变结构限定词，1个SOE
				strAsduBytes.append("0300"); // 传送原因，2个字节，3-表突发事件
				strAsduBytes.append(commonAddr); // 公共地址，2个字节	
				strAsduBytes.append(strAsduDataBytes);
				int apduLen = strAsduBytes.toString().replace(" ", "").length() / 2 + 4;
				String len = Integer.toHexString(apduLen).length() > 1? Integer.toHexString(apduLen): "0".concat(Integer.toHexString(apduLen));
				serialLock.lock();
				byte[] sendNumBytes = new byte[2];
				byte[] recNumBytes = new byte[2];
				sendNumBytes[0] = (byte) (sendNum << 1);
				sendNumBytes[1] = (byte) (sendNum >> 7);
		        
				recNumBytes[0] = (byte) (receiveNum << 1);
		        recNumBytes[1] = (byte) (receiveNum >> 7);
		        
		        String recStr = ChangeUtils.toHexString(recNumBytes);
		        String sendStr = ChangeUtils.toHexString(sendNumBytes);
		        sendNum ++;
				String soe = "68" + len +  sendStr +  recStr + strAsduBytes.toString();
				handleBlockingSendQueue.add(soe.replace(" ", ""));
				serialLock.unlock();
			} while(it.hasNext());
		}
	}


	private boolean validateThreshold(PointConfigVo point) {
		return false;
	}


	private void addTestlistener() {
		test_Communication = Executors.newSingleThreadScheduledExecutor();
        // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间
		test_Communication.scheduleAtFixedRate(test_runnable, 0, 1, TimeUnit.SECONDS);
	}
	


	Runnable test_runnable = new Runnable() {
		
		@Override
		public void run() {
			Date date = new Date();
			//recordTime;
			if (!stopCommunication && ((date.getTime() - recordTime) / 1000) >= 10) {
				ctx.channel().writeAndFlush("680443000000");
			}
		}
	};
	public void refreshRecordTime() {
		Date date = new Date();
		this.recordTime = date.getTime();
	}

	public void process(Apdu apdu) {
		if (!validateApdu(apdu)) {
			return;
		}
		refreshRecordTime();
		if (apdu.getApciType() == Apdu.ApciType.I_FORMAT) {
            //处理I命令
			if (ObjectUtils.isEmpty(commonAddr)) {
				commonAddr = ChangeUtils.encodeCommonAddress(apdu.getAsdu().getCommonAddress());
			}
			timeRecorder = new Date().getTime();
			recIpackate = true;
			handleBlockingRecQueue.add(apdu);
        } else if (apdu.getApciType() == Apdu.ApciType.S_FORMAT) {
        	Logger.getLogger(this.getClass()).warn("返回S确认帧");
        	if (apdu.getReceiveSeqNumber() != sendNum) {
				closeChinnel();
			}
        } else if (apdu.getApciType() == Apdu.ApciType.STARTDT_ACT) {
        	sendNum = 0;
        	receiveNum = 0;
        	ctx.channel().writeAndFlush("68040B000000");
        } else if (apdu.getApciType() == Apdu.ApciType.STOPDT_ACT) {
        	sendNum = 0;
        	receiveNum = 0;
        	ctx.channel().writeAndFlush("680423000000");
        } else if (apdu.getApciType() == Apdu.ApciType.TESTFR_ACT) {
        	ctx.channel().writeAndFlush("680483000000");
        } else {
        	Logger.getLogger(this.getClass()).warn("其他报文：" + apdu.getApciType());
        }
	}
	

	public boolean validateApdu(Apdu apdu) {
		if (apdu.getApciType() == Apdu.ApciType.I_FORMAT) {
			if (apdu.getSendSeqNumber() != receiveNum || apdu.getReceiveSeqNumber() != sendNum) {
				closeChinnel();
				return false;
			}

			if (receiveNum == apdu.getSendSeqNumber()) {
				receiveNum++;
				return true;
			}
		} else if (apdu.getApciType() == Apdu.ApciType.S_FORMAT) {
			if (apdu.getReceiveSeqNumber() != sendNum) {
				closeChinnel();
				return false;
			}
	 	}
		
		return true;
	}

	private void closeChinnel() {
//		startCommunication = false;
		stopCommunication = false;
		startRecruiting = false;
		recIpackate = false;
		receiveNum = 0;
		sendNum = 0;
		if (serialLock.isLocked()) {
			serialLock.unlock();
			serialLock = null;
		}
//		try {
//			secruitingSemaphore = null;
//		} catch (Exception e) {
//
//		}
		
		ctx.channel().close();
		
		if (test_Communication != null) {
			test_Communication.shutdownNow();
			test_Communication = null;
		}
		if (eecruiting_Communication != null) {
			eecruiting_Communication.shutdownNow();
			eecruiting_Communication = null;
		}
		if (send_Communication != null) {
			send_Communication.shutdownNow();
			send_Communication = null;
		}
		if (ack_Communication != null) {
			ack_Communication.shutdownNow();
			ack_Communication = null;
		}
		handleBlockingRecQueue.clear();
		handleBlockingSendQueue.clear();
		SessionManager.getInstance().removeSession(ctx);
	}
}
