package com.nms.server.thread.netty;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.InetSocketAddress;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;

import com.nms.server.bean.MissionResult2;
import com.nms.server.common.Common;
import com.nms.server.common.Constants;
import com.nms.server.thread.file.UnZipManagerThread;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;

public class MessageHandler extends ChannelInboundHandlerAdapter {
	private final static Logger logger = Logger.getLogger(MessageHandler.class);
	private ChannelHandlerContext ctx;
	private String ip;
	private Integer port;
	
	@Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if(evt instanceof IdleStateEvent){
        	IdleStateEvent ise = (IdleStateEvent)evt;
        	if(IdleState.ALL_IDLE.equals(ise.state())){
				Common.saveHbInfo(ip, "online", false);
				logger.info("ip : "+ip+" 超时");
				ctx.close();
        	}
        }else{
        	ctx.fireUserEventTriggered(evt);
        }
    }

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		String res = "success\r\n";
		try {
			Message message = (Message)msg;
			byte[] data = null;
			switch (message.getBusinessType()) {
			case HeartBeat://监测zip文件
				// 启动并注册 解压文件线程
				data = message.getData();
				InetSocketAddress addr = (InetSocketAddress)ctx.channel().remoteAddress();
				String ip = addr.getAddress().getHostAddress();
				Common.saveHbInfo(ip, "dcTime", System.currentTimeMillis());
				Common.saveHbInfo(ip, "ncTime", Long.valueOf(new String(data)));
				Common.saveHbInfo(ip, "online", true);
				//logger.info(ip +" 心跳包 -> " + new Date(Long.valueOf(new String(data))).toLocaleString());
				break;
			case DetectData://监测消息
				handlerDetectData(message);
				break;
			case ObjTaskResult://任务结果
				handlerObjTaskResult(message);
				break;
			case FileTaskReturn://回传文件
				handlerFileTaskReturn(message);
				break;
			default:
				logger.warn("未知操作");
				break;
			}
		} catch (Exception e) {
			res = "fail\r\n";
			logger.error("",e);
		}
		ByteBuf resp = Unpooled.copiedBuffer(res.getBytes());
		ctx.writeAndFlush(resp);//给客户端返回成功标识
	}
	
	/**
	 * 处理监测数据
	 * @param message
	 */
	public void handlerDetectData(Message message){
		byte[] data = message.getData();
		Common.addDeteData(data);
		logger.info("clientIp : " + ip +",成功添加一条监测记录");
	}
	
	/**
	 * 处理任务结果
	 * @param message
	 * @throws Exception 
	 * @throws IOException 
	 * @throws ClassNotFoundException 
	 */
	public void handlerObjTaskResult(Message message) throws Exception {
		// 接收返回的任务结果：修改为receiveObject
		logger.info("数据类型：任务结果的List<String[]>");
		byte[] data = message.getData();
		ByteArrayInputStream bis = null;
		ObjectInputStream ois = null;
		try {
			bis = new ByteArrayInputStream(data);
			ois = new ObjectInputStream(bis);
			List<String> resultList = (List<String>) ois.readObject();
			for (String result : resultList) {
				logger.info("任务结果：" + result);
				String[] misRlt2 = result.split(Constants.COMMON_DATA_SPLIT);
				MissionResult2 result2 = Common.resoveMissionResult(misRlt2);
				Common.addResultToResultList(result2);// 没有addAll，因为传递的任务结果可能是不同类型的任务结果（1-6）
			}
		} catch (Exception e) {
			logger.error("handler ObjTaskResult error",e);
			throw e;
		}finally {
			
			if(ois != null){
				try { ois.close(); } catch (IOException e) {}
			}
			if(bis != null){
				try { bis.close(); } catch (IOException e) {}
			}	
		}
		
	}
	
	/**
	 * 处理任务回传文件
	 * @param message
	 * @throws Exception 
	 */
	public void handlerFileTaskReturn(Message message) throws Exception{
		File file = message.getFile();
		String fileName = message.getFileName();
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try {
			fis = new FileInputStream(file);
			byte[] headerLenbyte = new byte[4];
			fis.read(headerLenbyte);
			int headerLen = Common.byteArrayToInt(headerLenbyte);
			byte[] msgArr = new byte[headerLen];
			fis.read(msgArr);
			String msg1 = new String(msgArr);//消息头
			logger.info("length: " + headerLen+",msg : "+msg1);
			String[] result = msg1.split(Constants.COMMON_DATA_SPLIT);
			MissionResult2 result2 = Common.resoveMissionResult(result);
			File temp = new File(Constants.MISSION_FILE_UPLOAD_DIR + fileName + Constants.TEMP_SUFFIX);
			fos = new FileOutputStream(temp);
			byte[] buf = new byte[1024];
			int len = -1;
			while((len = fis.read(buf)) > 0){
				fos.write(buf, 0, len);
			}
			fos.flush();
			fos.close();
			logger.debug("回传文件临时文件完成");
			moveFile(temp, new File(Constants.MISSION_FILE_UPLOAD_DIR + fileName));
			logger.debug("回传文件完成");
			result2.setFileInfo(fileName);
			Common.addResultToResultList(result2);
			logger.debug("任务回传文件处理完成");
		} catch (Exception e) {
			logger.error("",e);
			throw e;
		} finally {
			if(fos != null){
				try {fos.close();} catch (IOException e) {}
			}
			if(fis != null){
				try {fis.close();} catch (IOException e) {}
			}
		}
	}
	
	/**
	 * 处理监测zip
	 * @param message
	 * @throws IOException
	 */
	public void handlerDetectZip(Message message) throws IOException{
		// 启动并注册 解压文件线程
		File file = message.getFile();
		String uploadPath = Constants.ZIP_FILE_DETECT_DATA_DIR;
		moveFile(file, new File(uploadPath+File.separator +file.getName()));
		Future<?> future = Common.getFutureMap().get(Constants.UNZIP_FILE_MANAGER);
		if (future == null) {
			future = Common.scheduled.scheduleWithFixedDelay( new UnZipManagerThread(), 0, 30,TimeUnit.SECONDS);
			Common.registRunnable(Constants.UNZIP_FILE_MANAGER, future);
		}
	}
	/**
	 * 移动文件
	 * @param src
	 * @param dest
	 * @throws IOException
	 */
	public static void moveFile(File src ,File dest) throws IOException{
		boolean f = src.renameTo(dest);
		if(!f){
			FileUtils.copyFile(src, dest);
		}
	}
	
	@Override
	public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
		this.ctx = ctx;
		InetSocketAddress addr = (InetSocketAddress)ctx.channel().remoteAddress();
		ip = addr.getAddress().getHostAddress();
		port = addr.getPort();
		logger.info("添加->" + ip);
		super.handlerAdded(ctx);
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		logger.error("error",cause);
		Common.saveHbInfo(ip, "online", false);
		ctx.close();
	}

	@Override
	public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
		Common.saveHbInfo(ip, "online", false);
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		Common.saveHbInfo(ip, "online", false);
		Common.saveHbInfo(ip, "offlineTime", new Date());
		ctx.close();
	}

	@Override
	public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
		Common.saveHbInfo(ip, "online", false);
	}

}
