package com.yeejoin.amos.iec104.tcp.client;

import java.net.InetSocketAddress;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.log4j.Logger;
import org.springframework.util.ObjectUtils;

import com.yeejoin.amos.iec104.tcp.client.invoke.ApduQueue;
import com.yeejoin.amos.iec104.tcp.entity.Apdu;
import com.yeejoin.amos.iec104.tcp.entity.ServerData;
import com.yeejoin.amos.iec104.tcp.utils.ChangeUtils;
import com.yeejoin.amos.iec104.tcp.utils.Constant;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.SimpleChannelInboundHandler;

public class ClientHandler extends SimpleChannelInboundHandler<Apdu>{
	
	public IEC104Client client = null; //接收序号
	private ChannelHandlerContext ctx;
	private long recordTime = 0;
	private boolean running = true;
	private int MAX_INTERVAL_T3 = 10; 
	private int MAX_INTERVAL_T1 = 1000 * 30;  
	private int MAX_INTERVAL_T2 = 1000 * 3; 
	private int MAX_INTERVAL_T = 1000 * 60 * 5;
	
	private boolean connetOk = false;
	private boolean reviceIPackage = false;
	private long lastTimeReviceI = 0;
	private boolean startZZ = false;
	private boolean startSystem = true;
	private ScheduledExecutorService testService = null;
	private ReentrantLock lock = new ReentrantLock(true);
	private ReentrantLock zzlock = new ReentrantLock(true);
	
	public ClientHandler(IEC104Client client) {
		recordTime = new Date().getTime();
		this.client = client;
		
	}

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Apdu apdu) throws Exception {
    	try {
    		Date date = new Date();
    		this.recordTime = date.getTime();
    		ChannelPromise promise = ctx.newPromise();
            if (apdu.getApciType() == Apdu.ApciType.I_FORMAT) {
//                this.client.setSendSeqNum(apdu.getReceiveSeqNumber());
//                this.client.setReceiveSeqNum(apdu.getSendSeqNumber());
            	if (!ObjectUtils.isEmpty(testService)) {
        			testService.shutdownNow();
        			testService = null;
        		}
                this.lastTimeReviceI = this.recordTime;
                reviceIPackage = true;
                
                //  处理I命令
                handleData(apdu);
            } else if (apdu.getApciType() == Apdu.ApciType.S_FORMAT) {
//            	this.client.relase();
            	if (!ObjectUtils.isEmpty(testService)) {
        			testService.shutdownNow();
        			testService = null;
        		}
            }else if (apdu.getApciType() == Apdu.ApciType.STARTDT_ACT) {
            	ctx.channel().writeAndFlush("68040B000000", promise);
                Logger.getLogger(this.getClass()).debug("确认启动消息，U类型");
                if (!ObjectUtils.isEmpty(testService)) {
        			testService.shutdownNow();
        			testService = null;
        		}
            } else if (apdu.getApciType() == Apdu.ApciType.STOPDT_ACT) {
            	ctx.channel().writeAndFlush("680423000000", promise);
                Logger.getLogger(this.getClass()).debug("确认停止消息，U类型");
                if (!ObjectUtils.isEmpty(testService)) {
        			testService.shutdownNow();
        			testService = null;
        		}
                connetOk = false;
            } else if (apdu.getApciType() == Apdu.ApciType.TESTFR_ACT) {
            	ctx.channel().writeAndFlush("680483000000", promise);
            	
                Logger.getLogger(this.getClass()).debug("确认测试消息，U类型");
            }  else if (apdu.getApciType() == Apdu.ApciType.STARTDT_CON) {
                Logger.getLogger(this.getClass()).debug("启动确认帧回复，U类型");
                if (!ObjectUtils.isEmpty(startService)) {
        			startService.shutdownNow();
        			startService = null;
        		}
                startZZ = true;
                if (startSystem) {
                	ctx.channel().writeAndFlush("680443000000", promise);
                }
                startSystem = false;
                
                connetOk = true;
            } else if (apdu.getApciType() == Apdu.ApciType.TESTFR_CON) {
                Logger.getLogger(this.getClass()).debug("确认测试消息回复，U类型");
                if (startZZ) {
            		startZZ = false;
            		sendZzCommand();
            	}
            } else{
            	Logger.getLogger(this.getClass()).debug("其它报文：" + apdu.getApciType());
            	if (!ObjectUtils.isEmpty(testService)) {
        			testService.shutdownNow();
        			testService = null;
        		}
            }
        }catch (Exception e){
        	e.printStackTrace();
        	Logger.getLogger(this.getClass()).debug("异常错误,"+ e);
        }
    }
 
    private void handleData(Apdu apdu) {
    	if (apdu.getAsdu().getTypeId()== 100) {
    		return;
    	}
    	ServerData serverData = new ServerData();
    	serverData.setApdu(apdu);
    	serverData.setServerId(client.getClientId());
    	ApduQueue.getInstance().add(serverData);
	}

	private ScheduledExecutorService zzService = null;
	private ScheduledExecutorService startService = null;
	
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		super.channelActive(ctx);
    	Runnable runnable = new Runnable() {
            public void run() {
                ctx.channel().writeAndFlush("680407000000");
            }
        };
        startService = Executors.newSingleThreadScheduledExecutor();
        // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间
        startService.scheduleAtFixedRate(runnable, Constant.Z_Z_INITIALDELAY, Constant.S_S_PREIOD, TimeUnit.SECONDS);
        Date date = new Date();
		this.recordTime = date.getTime();
		if (!recordTimeThread.isAlive()) {
			recordTimeThread.start();
		}
		
		this.ctx = ctx;
		InetSocketAddress insocket = (InetSocketAddress) ctx.channel()
                .remoteAddress();
        String clientIP = insocket.getAddress().getHostAddress();
		Logger.getLogger("channelActive 建立了TCP连接 --->" + clientIP);
	}
	

    @Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		super.channelInactive(ctx);
		if (!ObjectUtils.isEmpty(startService)) {
			startService.shutdownNow();
			startService = null;
		}
		if (!ObjectUtils.isEmpty(zzService)) {
			zzService.shutdownNow();
			zzService = null;
		}
		if (recordTimeThread.isAlive()) {
			running = false;
		}		
		InetSocketAddress insocket = (InetSocketAddress) ctx.channel()
                .remoteAddress();
        String clientIP = insocket.getAddress().getHostAddress();
		Logger.getLogger("channelActive 断开了TCP连接 --->" + clientIP);
//		this.client.setReceiveSeqNum(0);
//		this.client.setSendSeqNum(0);
		this.client.closeChannel();
	}

	private void sendZzCommand() {
		if (zzlock.tryLock()) {
			if (!ObjectUtils.isEmpty(zzService)) {
				zzlock.unlock();
	    		return;
	    	}
	    	Runnable runnable = new Runnable() {
	            public void run() {
	                try {
	                	boolean isSend = false;
	                	do {
		                		isSend = true;
		                		if (connetOk) {
		                			byte[] recNum = new byte[2];
//				                    recNum[0] = (byte) (client.getReceiveSeqNum() << 1);
//				                    recNum[1] = (byte) (client.getReceiveSeqNum() >> 7);
//				                    String recStr = ChangeUtils.toHexString(recNum);
//				                    byte[] sendNum = new byte[2];
//				                    sendNum[0] = (byte) (client.getSendSeqNum() << 1);
//				                    sendNum[1] = (byte) (client.getSendSeqNum() >> 7);
//				                    client.setSendSeqNum(client.getSendSeqNum() + 1);
//				                    String sendStr = ChangeUtils.toHexString(sendNum);
//				                    String commonAddress = client.getCommonAddress();
//				                    String zzPackate = "680E"+sendStr+recStr+"64010600"+commonAddress+"00000014";
//				                    client.sendMessage(zzPackate.replace(" ", "").toUpperCase());
		                		}
	                	} while(!isSend);
	                } catch (Exception e) {
	                    e.printStackTrace();
	                } 
	            }
	        };
	        zzService = Executors.newSingleThreadScheduledExecutor();
	        // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间
	        zzService.scheduleAtFixedRate(runnable, Constant.Z_Z_INITIALDELAY, Constant.Z_Z_PREIOD, TimeUnit.SECONDS);
	        zzlock.unlock();
		}
    }
	
	public void startTest() {
		boolean start = false;
		do {
			try {
				if (lock.tryLock()) {
					if (!ObjectUtils.isEmpty(testService)) {
						lock.unlock();
			    		return;
			    	}
			    	Runnable runnable = new Runnable() {
			            public void run() {
			    			ctx.channel().writeAndFlush("680443000000");
			            }
			        };
			        testService = Executors.newSingleThreadScheduledExecutor();
			        // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间
			        testService.scheduleAtFixedRate(runnable, Constant.Z_Z_INITIALDELAY, MAX_INTERVAL_T3, TimeUnit.SECONDS);
			        lock.unlock();
			        if ( start == false) {
			        	 start = true;
			        }
			       
				}
			} catch (Exception e) {
			}
		} while(!start);
		
		
	}
	

    Thread recordTimeThread = new Thread(new Runnable() {
		
		@Override
		public void run() {
			running = true;
			while(running) {
				long interval = (new Date().getTime() - recordTime);
				long IInterval = 0;
				if (lastTimeReviceI == 0) {
					IInterval = 0;
				} else {
					IInterval = new Date().getTime() - lastTimeReviceI;
				}
				if (startSystem && interval >= MAX_INTERVAL_T1) {
					ctx.disconnect();
			    }
				if (interval >= MAX_INTERVAL_T) {
					ctx.close();
			    }
				if (!ObjectUtils.isEmpty(startService) && ObjectUtils.isEmpty(testService) && interval > MAX_INTERVAL_T3 * 1000) {
					ctx.channel().writeAndFlush("680443000000");
					startTest();
				}
				if (reviceIPackage && IInterval > MAX_INTERVAL_T2) {
//					reviceIPackage = false;
//	                //  返回S确认命令 
//	                String recStr = client.sendACKMessage();
//	                if (recStr == null) {
//	                	reviceIPackage = true;
//	                } else {
//	                	lastTimeReviceI = new Date().getTime();
//	                }
//	                Logger.getLogger(this.getClass()).debug("确认消息，S类型，下一条的接受序号：" + recStr);
				}
			}
		}
	});
}
