package com.pingpang.websocketchat;

import java.net.InetSocketAddress;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.pingpang.websocketchat.send.impl.ChatSendUtil;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;

/** 
 * 处理TextWebSocketFrame
 */
public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

	private int count=0;

	//日志操作
	private Logger logger = LoggerFactory.getLogger(TextWebSocketFrameHandler.class);
	
	@Override
	protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { // (1)
		InetSocketAddress ipSocket = (InetSocketAddress)ctx.channel().remoteAddress();
	    String clientIp = ipSocket.getAddress().getHostAddress();
	    StringBuilder acceptMsg=new StringBuilder(msg.text());
	    logger.info("客户端ip地址："+clientIp);
	    //logger.info("接收信息："+acceptMsg);
	    
		if("ping".equals(msg.text())) {
			ctx.channel().writeAndFlush(new TextWebSocketFrame("pong"));
			count=0;
			return;
		}
		
		if("Heartbeat".equals(msg.text())) {
			count=0;
			return;	
		}
		
		if(!acceptMsg.toString().endsWith("}")) {
			logger.error("非法数据:"+acceptMsg.toString());
			return;
		}
		
		ObjectMapper mapper = new ObjectMapper();
		Message message = null;
		try {
		     message=mapper.readValue(acceptMsg.toString(), Message.class);
		     logger.info("请求用户：{}指令：{}子指令：{}",message.getFrom().getUserCode(),message.getCmd(),message.getCmdChild());
		}catch(Exception e) {
			 logger.error(acceptMsg.toString());
			 logger.error("接收非法数据:", e);
			 return;
		}
		
		if(ChatType.BIND.equals(message.getCmd())) {
			ChatSendUtil.getChatSend(msg.text(), ctx);
			return;
		}
		
		ChartUser cu=ChannelManager.getChatUseByChannel(ctx.channel());
		if(null==cu.getUserCode()|| null==message.getFrom()) {
			logger.info("IP:[{}]非法请求。。。",ctx.channel().remoteAddress());
			ChartUser from=new ChartUser();
			from.setUserCode("admin");
			from.setUserName("管理员");
			message.setFrom(from);
			message.setCmd(ChatType.CANCEL);
			message.setMsg("连接服务端验证失败");
			ctx.channel().writeAndFlush(new TextWebSocketFrame(mapper.writeValueAsString(message)));
			return;
		}
		
		if(!cu.equals(message.getFrom())){
			logger.info("IP[{}],用户[{}]非法请求。。。",ctx.channel().remoteAddress(),message.getFrom().getUserCode());
			ChartUser from=new ChartUser();
			from.setUserCode("admin");
			from.setUserName("管理员");
			message.setFrom(from);
			message.setCmd(ChatType.CANCEL);
			message.setMsg("连接服务端验证失败");
			ctx.channel().writeAndFlush(new TextWebSocketFrame(mapper.writeValueAsString(message)));
			return;
		}
		
		ChatSendUtil.getChatSend(msg.text(), ctx);
		
	}

	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		if (evt instanceof IdleStateEvent) {
			IdleStateEvent event = (IdleStateEvent) evt;
			logger.info(ctx.channel().remoteAddress()+"超时次数:"+count);
			String type = "";
			if (event.state() == IdleState.READER_IDLE) {
				type = "read idle";
				count++;
				if(count>5) {
					 logger.info("超时次数达到最大值了，断开连接");
		              ChannelManager.removeChannelByChannel(ctx.channel());
		              ctx.channel().close();
					}
			} else if (event.state() == IdleState.WRITER_IDLE) {
				type = "write idle";
				count=0;
			} else if (event.state() == IdleState.ALL_IDLE) {
				type = "all idle";
				count=0;
			}
			ctx.writeAndFlush(new TextWebSocketFrame("Heartbeat")).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
			logger.info( ctx.channel().remoteAddress()+"超时类型：" + type);
		}
		super.userEventTriggered(ctx, evt);
	}
	
	@Override
	public void handlerAdded(ChannelHandlerContext ctx) throws Exception { // (2)
		Channel incoming = ctx.channel();
		// Broadcast a message to multiple Channels
		// channels.writeAndFlush(new TextWebSocketFrame("[SERVER] - " +
		// incoming.remoteAddress() + " 加入"));

		// channels.add(incoming);
		logger.info("Client:" + incoming.remoteAddress() + "加入");
	}

	@Override
	public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { // (3)
		Channel incoming = ctx.channel();

		// Broadcast a message to multiple Channels
		// channels.writeAndFlush(new TextWebSocketFrame("[SERVER] - " +
		// incoming.remoteAddress() + " 离开"));

		logger.info("Client:" + incoming.remoteAddress() + "离开");
		ChannelManager.removeChannelByChannel(incoming);
		// A closed Channel is automatically removed from ChannelGroup,
		// so there is no need to do "channels.remove(ctx.channel());"
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception { // (5)
		Channel incoming = ctx.channel();
		logger.info("Client:" + incoming.remoteAddress() + "在线");
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception { // (6)
		Channel incoming = ctx.channel();
		logger.info("Client:" + incoming.remoteAddress() + "掉线");
		ChannelManager.removeChannelByChannel(incoming);
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) // (7)
			throws Exception {
		Channel incoming = ctx.channel();
		logger.info("Client:" + incoming.remoteAddress() + "异常");
		
		ChannelManager.removeChannelByChannel(incoming);
		// 当出现异常就关闭连接
		cause.printStackTrace();
		ctx.close();
		logger.info("EEEEEEEEEEEEEEEEEEEERRRRRRRRRRRRRRRRRROOOOOOORRRRR");
	}

}
