package fr.zng.xxzx.netty.dispatcher;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.swing.JComponent;


import fr.zng.xxzx.biz.WebSessionDto;
import fr.zng.xxzx.common.cacheData.ZngCacheData;
import fr.zng.xxzx.common.consts.FrBizConst;
import fr.zng.xxzx.common.dao.EquipWsdDao;
import fr.zng.xxzx.common.dao.PdtDao;
import fr.zng.xxzx.common.dao.TdFlowDao;
import fr.zng.xxzx.common.dao.UnoDao;
import fr.zng.xxzx.common.dao.WeatherDao;
import fr.zng.xxzx.common.dao.impl.EquipWsdDaoImpl;
import fr.zng.xxzx.common.dao.impl.PdtDaoImpl;
import fr.zng.xxzx.common.dao.impl.TdFlowDaoImpl;
import fr.zng.xxzx.common.dao.impl.UnoDaoImpl;
import fr.zng.xxzx.common.dao.impl.WeatherDaoImpl;
import fr.zng.xxzx.common.entity.EquipWsdEntity;
import fr.zng.xxzx.common.entity.PdtEntity;
import fr.zng.xxzx.common.entity.TdFlowEntity;
import fr.zng.xxzx.common.entity.UnoEntity;
import fr.zng.xxzx.common.entity.WeatherEntity;
import fr.zng.xxzx.common.util.CRC;
import fr.zng.xxzx.common.util.CommUtil;
import fr.zng.xxzx.common.util.ConvertUtil;
import fr.zng.xxzx.common.util.DesUtil;
import fr.zng.xxzx.util.StringUtil;
import io.netty.channel.ChannelHandlerContext;

public class InboundDispatcher {

	private String cData = "";

	private ChannelHandlerContext cCtx = null;

	private JComponent cJc = null;

	private String cKeyAddr = null;

	/**
	 * 秘钥
	 */
	public static final String PASSWORD = "2019000000000001";

	/**
	 * 心跳
	 */
	public static final String ORDER_1001 = "1001";
	
	/**
	 * 心跳回复
	 */
	public static final String ORDER_1002 = "1002";

	/**
	 * 设备发送的轮询？命令
	 */
	public static final String ORDER_0002 = "0002";

	/**
	 * 刷卡扫码请求命令：2001
	 */
	public static final String ORDER_2001 = "2001";
	
	/**
	 * 刷卡扫码回复命令：2002
	 */
	public static final String ORDER_2002 = "2002";
	/**
	 * 海启开门关门回复
	 */
	public static final String ORDER_2004 = "2004";
	
	/**
	 * 投放垃圾请求命令：3001
	 */
	public static final String ORDER_3001 = "3001";
	
	/**
	 * 投放垃圾回复命令：3002
	 */
	public static final String ORDER_3002 = "3002";
	
	/**
	 * GPRS/天气请求命令：4001
	 */
	public static final String ORDER_4001 = "4001";
	
	/**
	 * GPRS/天气回复命令：4002
	 */
	public static final String ORDER_4002 = "4002";
	
	/**
	 * 礼品兑换请求命令：5101
	 */
	public static final String ORDER_5101 = "5101";
	
	/**
	 * 礼品兑换回复命令：5102
	 */
	public static final String ORDER_5102 = "5102";
	
	/**
	 * 重启：61
	 */
	public static final String ORDER_61 = "61";
	
	/**
	 * 换ip：62
	 */
	public static final String ORDER_62 = "62";
	/**
	 * ip请求：6201
	 */
	public static final String ORDER_6201 = "6201";
	/**
	 * ip回复：6202
	 */
	public static final String ORDER_6202 = "6202";
	/**
	 * 设备3001命令缓存  用于去重
	 * */
	public static Map<String, String> map3001 =  new ConcurrentHashMap<String, String>();
	/**
	 * 设备3001命令缓存时间  用于去重
	 * */
	public static Map<String, Integer> mapT3001 =  new ConcurrentHashMap<String, Integer>();
	public InboundDispatcher(JComponent jc, String data, String cKeyAddr, ChannelHandlerContext ctx) {
		this.cData = data;
		this.cCtx = ctx;
		this.cJc = jc;
		this.cKeyAddr = cKeyAddr;
	}

	public void dispatcher() {
		//  转义
		HashSet<String> list = CommUtil.Escape(this.cData);

		for (String d : list) {

			// 验证成功
			try {
				doAnalyse(d);
				// 消息ID
			} catch (Exception e) {
				CommUtil.doPrint(this.cJc, "==消息不合规范==", e.getMessage());
				e.printStackTrace();
			}
		}
	}

	/**
	 * 消息处理
	 * 
	 * @param data
	 */
	private void doAnalyse(String data) {
		// 7E 0002 FC16434CA2BA 00 10 15 7E
		// 根据消息ID判断命令类型，解析数据，显示在通讯日志中，插数据库，回应设备
		String replyData = "";
//		while(data.startsWith("0D0A41542B514953454E443D302C3138310D0A")){
//			data.substring(38);
//		}
		// 标识位：7E
		if (data.endsWith(FrBizConst.MKEY) && data.startsWith(FrBizConst.MKEY)) {
			// 标识位正确
			String recData = data.substring(2, data.length() - 2);
			//转义 7D02 -> 7E 7D01 -> 7D
			recData = CommUtil.doDecodeData(recData);
			// 校验码检验
			if (CommUtil.CheckXor(recData)) {
				// 校验成功
				CommUtil.doPrint(this.cJc, "校验码检验成功" ,"");
				// 消息id 2个字节
				String order = data.substring(2, 6);
				// 版本号 1个字节
				String version = data.substring(6, 8);
				// 设备号 12个字节
				String equipmentCode = data.substring(8, 32);
				// 时间戳 5个字节
				String time = data.substring(32, 42);
				// 加密值 8个字节
				String endata = data.substring(42, 58);
				// 密钥
				String passwordKey = equipmentCode+"00000000";
				// 时间戳加密
				String enTime = DesUtil.encryptDES(time + "000000", passwordKey);
				enTime = "0000000000000000";
				// 秘钥检验
				if (endata.equals(enTime)) {
					// 秘钥校验成功
					CommUtil.doPrint(this.cJc, "秘钥校验成功！ ","命令：" + order + " 设备号：" + equipmentCode + 
							" 时间戳:" + time + " 加密值：" + endata);
					if (ORDER_1001.equals(order)) {
						// 轮询命令场合不做任何事情
						//将通道按用户ip地址、设备号存入map
				    	if (!ZngCacheData.sessionCodeIP.containsKey(equipmentCode)) {
				    		 ZngCacheData.sessionCodeIP.put(equipmentCode, this.cKeyAddr);
				    		 ZngCacheData.sessionIPCode.put(this.cKeyAddr, equipmentCode);
				    	} else {
				    		 ZngCacheData.sessionCodeIP.put(equipmentCode, this.cKeyAddr);
				    		 ZngCacheData.sessionIPCode.put(this.cKeyAddr, equipmentCode);
				    	}
				    	//检查是否需要重启
				    	String orderPdt = "";
				    	if(getPdt(equipmentCode)!=null){
				    	PdtEntity pdt = getPdt(equipmentCode);
				    	System.out.println("restart:"+pdt.getRestart());
				    	System.out.println("1".equals(pdt.getRestart()));
					    	//发送命令  重启61  换ip62
					    	if("1".equals(pdt.getRestart()) ){
					    		orderPdt = ORDER_61;
					    		//更新重启状态为0
					    		updRestart(equipmentCode);
								ZngCacheData.sessionCodeVersion.put(equipmentCode,version);
								replyData = CommUtil.doMakeData(ORDER_1002,version, equipmentCode, time, endata,
										orderPdt);
								// 回复数据
								CommUtil.doPrint(this.cJc, ORDER_1002,replyData);
								ZngCacheData.sessionXtTime.put(equipmentCode,  System.currentTimeMillis()+"");
								doReply(replyData);
								return;
					    	}
					    	//检查是否需要换ip
					    	System.out.println("ChangeIp:"+pdt.getChangeIp());
					    	System.out.println("1".equals(pdt.getChangeIp()));
					    	if("1".equals(pdt.getChangeIp())){
					    		orderPdt = ORDER_62;
								ZngCacheData.sessionCodeVersion.put(equipmentCode,version);
								replyData = CommUtil.doMakeData(ORDER_1002,version, equipmentCode, time, endata,
										orderPdt);
								// 回复数据
								CommUtil.doPrint(this.cJc, ORDER_1002,replyData);
								doReply(replyData);
								return;
					    	}
				    	}
				    	//湿度 2个字节
				    	String humidity = data.substring(302,306);
				    	//风速 2个字节
				    	String windspeed = data.substring(306,310);
				    	//噪音 2个字节
				    	String noise = data.substring(310,314);
				    	//网络信号 1个字节
				    	String networksignal = data.substring(314,316);
				    	//报警状态 1个字节
				    	String alarmstatus = data.substring(316,318);
				    	//报警内容 20个字节
				    	String alarmcontent = data.substring(318,358);
				    	//温度
				    	String wd = data.substring(298,301)+"."+data.substring(301,302);
				    	//湿度
				    	String sd = data.substring(302,305)+"."+data.substring(305,306);
				    	//一小时插入一次温湿度
				    	if(checkWsd(equipmentCode)<=0){
					    	EquipWsdEntity en = new EquipWsdEntity();
							en.setImei(equipmentCode);
							en.setLsd(sd);
							en.setLwd(wd);
							en.setWifi(networksignal);
							insertWsd(en);
						}
						//设备号 + 版本号
						ZngCacheData.sessionCodeVersion.put(equipmentCode,version);
						replyData = CommUtil.doMakeData(ORDER_1002,version, equipmentCode, time, endata,
								ZngCacheData.sessionMap.get(this.cKeyAddr).getHeardRet());
						// 回复数据
						CommUtil.doPrint(this.cJc, ORDER_1002,replyData);
						doReply(replyData);
						
					} else if (ORDER_2001.equals(order)) {
						//银行卡号12个字节
						String bankno = CommUtil.doAscTowb(data.substring(58,106));
						//String userno = data.substring(58,82);
						//CRC校验值 2个字节
						//String crc = data.substring(82,86);
						//验证crc
						//String encrc = CRC.getCRC(userno);
						
						CommUtil.doPrint(this.cJc, "用户号:",bankno);
						//CommUtil.doPrint(this.cJc, "CRC校验值 :",crc);
						
						//是否通过
						String flag = "";
/*						if(encrc.equalsIgnoreCase(crc)){
							// 该用户是否注册
							if(checkUno(userno)){
								flag = "01";
							} else {
								flag = "02";
							}
							
						}else{
							// 未通过校验
							CommUtil.doPrint(this.cJc, ORDER_2001,"未通过CRC校验");
							flag = "02";
						}*/
						// 该卡号是否注册
						if(checkUno(bankno)!=null){
							flag = "01";
						} else {
							flag = "02";
						}
						ZngCacheData.sessionCodeVersion.put(equipmentCode,version);
						replyData = CommUtil.doMakeData(ORDER_2002,version, equipmentCode, time, endata,
								data.substring(58,106)+flag);
						// 回复数据
						CommUtil.doPrint(this.cJc, ORDER_2002,replyData);
						doReply(replyData);
						
					}else if (ORDER_3001.equals(order)) {
						//去重
						if(map3001==null||!data.equals(map3001.get(equipmentCode))){
							map3001.put(equipmentCode, data);
//							mapT3001.put(equipmentCode, (int) (System.currentTimeMillis()/1000));
						}else{
							//当前时间
//							int curtime = (int) (System.currentTimeMillis()/1000);
//							if(curtime-mapT3001.get(equipmentCode)<20){
//								return;
//							}
							return ;
						}
						//用户号 12个字节
						//String userno = data.substring(58,82);
						//银行卡号
						String bankno = CommUtil.doAscTowb(data.substring(58,106));
						//CRC校验值 2个字节
						//String crc = data.substring(82,86);
						//桶类型  1个字节
						String cno =  data.substring(108,110);
						//桶编号 1个字节
						String colno =  data.substring(106,108);
						//垃圾投入总量 4个字节    g克
						String gbmark =  data.substring(110,111);
						String garbage = data.substring(111,118);
						if("1".equals(gbmark)){
							garbage = "-"+garbage;
						}
						//小于10g的投递记为0
						if(Integer.parseInt(garbage)<10){
							garbage = "0";
						}
						//投入后垃圾高度 4个字节  mm毫米
						String heightmark = data.substring(118,119);
						String gbheight = data.substring(119,126);
						if("1".equals(heightmark)){
							gbheight = "-"+gbheight;
						}
						// 是否通过
						String flag = "";

						//获取用户信息
						UnoDao dao = new UnoDaoImpl();
						//通过银行卡号查找用户
						UnoEntity user = dao.getVillageUserCinfo(bankno);
						TdFlowEntity en = new TdFlowEntity();
						// 投递
						en.setDel("0");
						en.setImei(equipmentCode);
						en.setCno(cno);
						en.setColno(colno);
						en.setWeight(new BigDecimal(garbage));
						//当前桶垃圾高度  mm
						en.setCbhgt(new BigDecimal(gbheight));
						//积分 重量为0时给1个积分  10g等于1积分
						BigDecimal bg2 = new BigDecimal(10);
						en.setPoint(new BigDecimal(garbage).compareTo(BigDecimal.ZERO)==0?new BigDecimal("1.0"):
				        	new BigDecimal(garbage).divide(bg2,1,BigDecimal.ROUND_HALF_UP));
						en.setUno(user.getUno());
						en.setVno(user.getVno());
						en.setCreater(user.getUno());
						en.setUpdater(user.getUno());
						if(!StringUtil.isEmpty(user)){
							//投递前总量
							en.setBweight(user.getWeight());
							//投递后总量
							en.setAweight(user.getWeight().add(new BigDecimal(garbage)));
							//交易前积分
							en.setBpoint(user.getPoint());
							//交易后积分
							en.setApoint(user.getPoint().add(en.getPoint()));
							if(InsertTdFlow(en)>0){
								flag = "01";
							}else {
								flag = "02";
							}
						}else{
							//投递前总量
							en.setBweight(BigDecimal.ZERO);
							//投递后总量
							en.setAweight(new BigDecimal(garbage));
							//交易前积分
							en.setBpoint(BigDecimal.ZERO);
							//交易后积分
							en.setApoint(en.getPoint());
							if(InsertTdFlowErr(en)>0){
								flag = "01";
							}else {
								flag = "02";
							}
						}
						ZngCacheData.sessionCodeVersion.put(equipmentCode,version);
						replyData = CommUtil.doMakeData(ORDER_3002,version, equipmentCode, time, endata,
								data.substring(58,106)+flag);
						// 回复数据
						CommUtil.doPrint(this.cJc, ORDER_3002,replyData);
						doReply(replyData);
					}else if (ORDER_4001.equals(order)) {
						String jd = ConvertUtil.toStringHex1(data.substring(58,88).replace("00", ""));
						String wd = ConvertUtil.toStringHex1(data.substring(88,118).replace("00", ""));
						PdtEntity pdt = new PdtEntity();
						pdt.setImei(equipmentCode);
						pdt.setJd(jd);
						pdt.setWd(wd);
						UpdJwd(pdt);
						String weather = getWeather(equipmentCode);
						System.out.println("weather:"+weather);
						String str = ConvertUtil.convertStringToHex2(weather);
						System.out.println(str);
						ZngCacheData.sessionCodeVersion.put(equipmentCode,version);
						replyData = CommUtil.doMakeData(ORDER_4002,version, equipmentCode, time, endata,
								str);
						// 回复数据
						CommUtil.doPrint(this.cJc, ORDER_4002,replyData);
						doReply(replyData);
					}else if (ORDER_5101.equals(order)) {
						//用户号 16个字节
						String userno = data.substring(58,90);
						//CRC校验值 2个字节
						String crc = data.substring(90,94);
						//道号  2个字节
						String number = data.substring(94,98);
						
						//验证crc
						String encrc = CRC.getCRC(userno);
						
						//是否通过
						String flag = "";
						if(encrc.equalsIgnoreCase(crc)){
							flag = "01";
						}else{
							flag = "02";
						}
						
						ZngCacheData.sessionCodeVersion.put(equipmentCode,version);
						replyData = CommUtil.doMakeData(ORDER_5102,version, equipmentCode, time, endata,
								userno+crc+number+flag);
						doReply(replyData);
					}else if (ORDER_6201.equals(order)) {
						//获取ip及端口,分隔
						String ip = "";
						String port = "";
						//获取设备信息
						PdtEntity pdt = getPdt(equipmentCode);
						ip = pdt.getIp();
						port = pdt.getPort();
						
						String str = ip+","+port;
						if(ConvertUtil.toStringHex1(data.substring(58,data.length()-8)).equals(str)){
							//重置ip状态
							updIpFlag(equipmentCode);
							//通知设备重启
							restart(equipmentCode);
							return;
						}
						ZngCacheData.sessionCodeVersion.put(equipmentCode,version);
						replyData = CommUtil.doMakeData(ORDER_6202,version, equipmentCode, time, endata,
								ConvertUtil.convertStringToHex2(ip+","+port)+"0a0d");
						doReply(replyData);
					}else if(ORDER_2004.equals(order)){
						//海启交易记录上传
						String uuid = data.substring(60,92);
						//78
						String hight = data.substring(108,110);
						//56
						String hh = data.substring(106,108);
						//34
						String low = data.substring(104,106);
						//12
						String ll = data.substring(102,104);
						String sts = data.substring(92,94);
						if(!"02".equals(sts)){
							//开门直接返回开门成功
							ZngCacheData.sessionCodeVersion.put(equipmentCode,version);
							replyData = CommUtil.doMakeData(ORDER_2004,version, equipmentCode, time, endata,
									"01");
							doReply(replyData);
							return;
						}
						int weight = new BigInteger(hight+hh+low+ll, 16).intValue();
						//根据uuid更新投递记录
						TdFlowEntity tdFlowEn = new TdFlowEntity();
						TdFlowDao tdDao = new TdFlowDaoImpl();
						tdFlowEn.setUuid(uuid);
						//先查询是否有这条记录
						tdFlowEn = tdDao.getTdFlowByUuid(tdFlowEn);
						if(tdFlowEn!=null){
							tdFlowEn.setWeight(new BigDecimal(weight).divide(new BigDecimal("1000")));
							tdFlowEn.setPoint(new BigDecimal(weight));
							int p = tdDao.updateTd(tdFlowEn);
							if(p>0){
								ZngCacheData.sessionCodeVersion.put(equipmentCode,version);
								replyData = CommUtil.doMakeData(ORDER_2004,version, equipmentCode, time, endata,
										"01");
								doReply(replyData);
							}else{
								//更新失败
								ZngCacheData.sessionCodeVersion.put(equipmentCode,version);
								replyData = CommUtil.doMakeData(ORDER_2004,version, equipmentCode, time, endata,
										"02");
								doReply(replyData);
							}
						}else{
							//操作流水未找到对应记录
							ZngCacheData.sessionCodeVersion.put(equipmentCode,version);
							replyData = CommUtil.doMakeData(ORDER_2004,version, equipmentCode, time, endata,
									"02");
							doReply(replyData);
						}
					}
				} else {
					// 秘钥校验失败
					CommUtil.doPrint(this.cJc, "秘钥校验失败" ,"");
				}
			} else {
				// 校验码检验失败
				CommUtil.doPrint(this.cJc, "校验码检验失败" ,recData);
			}
		} else {
			
		}
	}
	

	/**
	 * 清理用户扫描
	 * 
	 * @param code
	 */
	public void doWebFize(String code) {
		
		String ip = ZngCacheData.sessionWebCodeIPDevice.get(code);
		if (ip == null) {
			ZngCacheData.sessionWebCodeIPDevice.remove(code);
			ZngCacheData.sessionWebCodeUsed.remove(code);
			return;
		}
		// 获取web对象
		WebSessionDto wsd = ZngCacheData.sessionWebMap.get(ip);
		if (wsd != null) {
			wsd.getChannel().writeAndFlush("{\"status\":\"73\",\"msg\":\"超时关闭\"}");
			wsd.getChannel().flush();
			wsd.getChannel().close();
		}
		ZngCacheData.sessionWebMap.remove(ip);
		ZngCacheData.sessionWebIPCodeDevice.remove(ip);
		ZngCacheData.sessionWebCodeIPDevice.remove(code);
		ZngCacheData.sessionWebCodeUsed.remove(code);
		try {
			finalize();
		} catch (Throwable e) {
			e.printStackTrace();
		}
		CommUtil.doPrint(this.cJc, "设备空闲1" ,"关闭清理");
	}
	/**
	 * 温湿度插入
	 * */
	private int insertWsd(EquipWsdEntity en){
		EquipWsdDao dao = new EquipWsdDaoImpl();
		return dao.insert(en);
	}
	/**
	 * 发送数据
	 * 
	 * @param ctx
	 *            ChannelHandlerContext
	 * @param data
	 *            数据
	 */
	private void doReply(String data) {

		if (StringUtil.isEmpty(data)) {
			return;
		}
		cCtx.channel().writeAndFlush(data);
		cCtx.flush();
		CommUtil.doPrint(this.cJc, "", " 发送数据 .." + data);
	}
	/**
	 * 发送数据
	 * 
	 * @param ctx
	 *            ChannelHandlerContext
	 * @param data
	 *            数据
	 */
	private void doReply(String ip,String data) {
		if (StringUtil.isEmpty(data)) {
			return;
		}
		ZngCacheData.sessionMap.get(ip).getChannel().writeAndFlush(data);
		ZngCacheData.sessionMap.get(ip).getChannel().flush();
		CommUtil.doPrint(this.cJc, "", " 发送数据 .." + data);
	}

	/**
	 * 审核用户名
	 * @param uno
	 * @return
	 */
	private Boolean checkUno(String uno){
		UnoDao dao = new UnoDaoImpl();
		UnoEntity en = dao.getVillageUserCinfo(uno);
		if(en!=null){
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 插入投递记录
	 * @return
	 */
	private int InsertTdFlow(TdFlowEntity en ){
		TdFlowDao dao = new TdFlowDaoImpl();
		return dao.insert(en);
	}
	private int checkWsd(String imei){
		EquipWsdDao dao = new EquipWsdDaoImpl();
		return dao.checkWsd(imei);
	}
	/**
	 * 插入异常投递记录
	 * @return
	 */
	private int InsertTdFlowErr(TdFlowEntity en ){
		TdFlowDao dao = new TdFlowDaoImpl();
		return dao.insertErr(en);
	}
	private void UpdJwd(PdtEntity pdt) {
		PdtDao updt = new PdtDaoImpl();
		updt.updJwd(pdt);
	}
	private String getWeather(String imei){
		StringBuffer sb=new StringBuffer();
		WeatherDao dao = new WeatherDaoImpl();
		WeatherEntity we = dao.getWeather(imei);
		System.out.println(we.getDate1());
		sb.append(we.getDate1()).append(",");
		sb.append(we.getTmpMax1()).append(",");
		sb.append(we.getTmpMin1()).append(",");
		sb.append(we.getConCodeD1()).append(",");
		sb.append(we.getConCodeN1()).append(",");
		sb.append(we.getConTxtD1()).append(",");
		sb.append(we.getConTxtN1()).append(";");
		
		sb.append(we.getDate2()).append(",");
		sb.append(we.getTmpMax2()).append(",");
		sb.append(we.getTmpMin2()).append(",");
		sb.append(we.getConCodeD2()).append(",");
		sb.append(we.getConCodeN2()).append(",");
		sb.append(we.getConTxtD2()).append(",");
		sb.append(we.getConTxtN2()).append(";");
		
		sb.append(we.getDate3()).append(",");
		sb.append(we.getTmpMax3()).append(",");
		sb.append(we.getTmpMin3()).append(",");
		sb.append(we.getConCodeD3()).append(",");
		sb.append(we.getConCodeN3()).append(",");
		sb.append(we.getConTxtD3()).append(",");
		sb.append(we.getConTxtN3()).append(";");
		return sb.toString();
	}
	//查询设备状态信息
	private PdtEntity getPdt(String imei){
		PdtDao pdt = new PdtDaoImpl();
		return pdt.getPdt(imei);
	}
	//更新重启状态0
	private void updRestart(String imei){
		PdtDao pdt = new PdtDaoImpl();
		pdt.updRestart(imei);
	} 
	//更新重启状态1
	private void restart(String imei){
		PdtDao pdt = new PdtDaoImpl();
		pdt.restart(imei);
	} 
	//更新ip状态
	private void updIpFlag(String imei){
		PdtDao pdt = new PdtDaoImpl();
		pdt.updIpFlag(imei);
	}
}
