package org.springblade.openinterface.iot.utils;

import java.util.HashMap;
import java.util.Map;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;


/**
 * 银河智能电表数据解析工具
 */
public class Ddzy251_NB_Util {
	public static final class DIDef{
		public static final String di_energy				="00000000";//电量(组合有功总电量)
		public static final String di_date					="04000101";//日期
		public static final String di_time					="04000102";//时间
		public static final String di_voltage				="02010100";//电压
		public static final String di_current				="02020100";//电流
		public static final String di_activepower			="02030000";//有功功率
		public static final String di_wattlesspower			="02040000";//无功功率
		public static final String di_powerfactor			="02060000";//功率因数
		public static final String di_voltage_block			="0201FF00";//C电压//B电压//A电压
		public static final String di_current_block			="0202FF00";//C电流//B电流//A电流
		public static final String di_activepower_block		="0203FF00";//C有功功率//B有功功率//A有功功率//有功功率
		public static final String di_wattlesspower_block	="0204FF00";//C无功功率//B无功功率//A无功功率//无功功率
		public static final String di_powerfactor_block		="0206FF00";//C功率因数//B功率因数//A功率因数//功率因数
		public static final String di_energy_block			="00FF0000";//电量	//正向有功电量//反向有功电量//无功电量1//无功电量2
		public static final String di_energy_block2			="0000FF00";//电量	总有功电量	费率1有功电量	费率2有功电量	费率3有功电量	费率4有功电量
	}
	public static String operatorcode = "????????";//与电表内置一致
	public static String password = "????????";    //与电表内置一致
	/**
	 *  @param data
	 *  @return 返回参数(MAP)
		devicecode 	表号
		typecode   	00:电表，10:水表
		typename   	仪表类型，电表或水表
		c		   	控制码
		dl			数据长度
		resp        响应结果 ok:正确,其它出错
		error	           错误描述
		dtdi 		数据标识

	           电量	(总有功电量)
		日期
		时间
		电压
		电流
		功率
		无功功率
		功率因数
		C电压 			B电压			A电压			电压
		C电流			B电流			A电流			电流
		C有功功率		B有功功率		A有功功率		有功功率
		C无功功率		B无功功率		A无功功率		无功功率
		C功率因数		B功率因数		A功率因数		功率因数
		电量(总有功电量)	正向有功电量		反向有功电量		无功电量1		无功电量2
		电量(总有功电量)	费率1有功电量	费率2有功电量	费率3有功电量	费率4有功电量
	 */
	public static Map<String, String> decode(byte[] data) {
		//从二进制数据解析，将所有信息作为参数返回，其中devicecode 必须，意指设备地址
		if(null==data) {
			return null;
		}
		Map<String,String> r=new HashMap<String,String>();
		//将十六进制字串转换成字节数组，如
		//String str="FE FE FE FE 68 20 64 31 32 03 00 68 93 06 53 97 64 65 36 33 6F 16"//转换前
		//Byte[] data=[0xFE,0xFE,0xFE,0xFE,0x68,0x20,0x64,0x31,0x32,0x03,0x00,0x68,0x93,0x06,0x53,0x97,0x64,0x65,0x36,0x33,0x6F,0x16];//转换后
		r.put("hdata", tohex(data));
		int offset=0;
		int dl=data.length;
		boolean invaliddata=false;
		//检查有效性，排除前导FE
		while(data[offset]!=((byte)0x68)) {
			if(data[offset]!=(byte)0xfe) {
				invaliddata=true;
			}
			offset++;
			dl--;
			if(dl<=0) {
				//数据完了没找到0x68
				return r;
			}
		}
		//无效，
		if(invaliddata) {
			offset-=7;
			return r;
		}

		if(dl>=12||invaliddata) {
			// 电表
			//FE FE FE FE 68 20 64 31 32 03 00 68 91 08 33 33 33 33 33 33 33 33 EB 16
			if(data[offset+7]==((byte)0x68)){//检查第二个0x68
				r.put("typecode", "00");
				r.put("typename","电表");

				if(!invaliddata) {
				String devcecode=tohex(data,offset+1,6,true);
				r.put("devicecode", devcecode);
				}else {
					r.put("devicecode", "0");
				}
				//这里为了简化 调试
				/*if(1==1) {
					return r;
				}*/
				int c=toint(data[offset+8]);
				int dlen=toint(data[offset+9]);
				r.put("c", ""+tohex(c));
				r.put("dl",""+dlen);
				if(dlen>0) {
					String dataitems;
					r.put("di", dataitems=tohex33(data,offset+10,dlen,true));
					if(c==0x93&&dlen>=6) {
						//电表地址
					}else if((c==0x91||c==0x11||c==0x14||c==0x1c)&&dlen>=4) {
						//读数据
						String dtdi=tohex33(data,offset+10,4,true);//每个字节减去0x33,再逆序转成十六进制字符串
						//String dtvalues=tohex33(data,offset+14,dlen-4,true);
						r.put("dtdi", dtdi);
						r.put("parsenum", "1");
						//r.put("dtvalues", dtvalues);
						//进一步解析
						if(c==0x91) {
							if("00000000".equalsIgnoreCase(dtdi)) {
								//组合有功总电量
								r.put("电量",dataitems.substring(0,6)+"."+dataitems.substring(6,8));
							}else if("04000101".equalsIgnoreCase(dtdi)) {
								r.put("日期","20"+dataitems.substring(0,2)+"-"+dataitems.substring(2,4)+"-"+dataitems.substring(4,6));
							}else if("04000102".equalsIgnoreCase(dtdi)) {
								r.put("时间",dataitems.substring(0,2)+":"+dataitems.substring(2,4)+":"+dataitems.substring(4,6) );
							}else if("02010100".equalsIgnoreCase(dtdi)) {
								r.put("电压",dataitems.substring(0,3)+"."+dataitems.substring(3,4));
							}else if("02020100".equalsIgnoreCase(dtdi)) {
								r.put("电流",dataitems.substring(0,3)+"."+dataitems.substring(3,6));
							}else if("02030000".equalsIgnoreCase(dtdi)) {
								r.put("功率",dataitems.substring(0,2)+"."+dataitems.substring(2,6));
							}else if("02040000".equalsIgnoreCase(dtdi)) {
								r.put("无功功率",dataitems.substring(0,2)+"."+dataitems.substring(2,6));
							}else if("02060000".equalsIgnoreCase(dtdi)) {
								r.put("功率因数",dataitems.substring(0,1)+"."+dataitems.substring(1,4) );
							}else if("0201FF00".equalsIgnoreCase(dtdi)) {
								if(dl>=10) {
									//三相
									r.put("C电压",dataitems.substring(0,3)+"."+dataitems.substring(3,4));
									r.put("B电压",dataitems.substring(4,7)+"."+dataitems.substring(7,8));
									r.put("A电压",dataitems.substring(8,11)+"."+dataitems.substring(11,12));

									r.put("parsenum", "3");
								}else {
									//单相
									r.put("电压",dataitems.substring(0,3)+"."+dataitems.substring(3,4));
								}
							}else if("0202FF00".equalsIgnoreCase(dtdi)) {
								if(dl>=13) {
									//三相
									r.put("C电流",dataitems.substring(0,3)+"."+dataitems.substring(3,6));
									r.put("B电流",dataitems.substring(6,9)+"."+dataitems.substring(9,12));
									r.put("A电流",dataitems.substring(12,15)+"."+dataitems.substring(15,18));

									r.put("parsenum", "3");
								}else {
									//单相
									r.put("电流",dataitems.substring(0,3)+"."+dataitems.substring(3,6));
								}
							}else if("0203FF00".equalsIgnoreCase(dtdi)) {
								if(dl>=16) {
									//功率
									r.put("C有功功率",dataitems.substring(0,2)+"."+dataitems.substring(2,6));
									r.put("B有功功率",dataitems.substring(6,8)+"."+dataitems.substring(8,12));
									r.put("A有功功率",dataitems.substring(12,14)+"."+dataitems.substring(14,18));
									r.put("有功功率",dataitems.substring(18,20)+"."+dataitems.substring(20,24));
									r.put("parsenum", "3");
								}else {
									//单相
									r.put("功率",dataitems.substring(0,2)+"."+dataitems.substring(2,6));
								}
							}else if("0204FF00".equalsIgnoreCase(dtdi)) {
								if(dl>=16) {
									//功率
									r.put("C无功功率",dataitems.substring(0,2)+"."+dataitems.substring(2,6));
									r.put("B无功功率",dataitems.substring(6,8)+"."+dataitems.substring(8,12));
									r.put("A无功功率",dataitems.substring(12,14)+"."+dataitems.substring(14,18));
									r.put("无功功率",dataitems.substring(18,20)+"."+dataitems.substring(20,24));
									r.put("parsenum", "3");
								}else {
									//单相
									r.put("无功功率",dataitems.substring(0,2)+"."+dataitems.substring(2,6));
								}
							}else if("0204FF00".equalsIgnoreCase(dtdi)) {
								if(dl>=12) {
									r.put("C功率因数",dataitems.substring(0,1)+"."+dataitems.substring(1,4));
									r.put("B功率因数",dataitems.substring(4,5)+"."+dataitems.substring(5,8));
									r.put("A功率因数",dataitems.substring(8,9)+"."+dataitems.substring(9,12));
									r.put("功率因数",dataitems.substring(12,13)+"."+dataitems.substring(13,16));
									r.put("parsenum", "3");
								}else {
									r.put("功率因数",dataitems.substring(0,1)+"."+dataitems.substring(1,4) );
								}
							}else if("00FF0000".equalsIgnoreCase(dtdi)) {
								if(dl>=24) {
									int l=dataitems.length()-8;
									r.put("电量",dataitems.substring(l-8,l-2)+"."+dataitems.substring(l-2,l));
									l-=8;
									r.put("正向有功电量",dataitems.substring(l-8,l-2)+"."+dataitems.substring(l-2,l));
									l-=8;
									r.put("反向有功电量",dataitems.substring(l-8,l-2)+"."+dataitems.substring(l-2,l));
									l-=8;
									r.put("无功电量1",dataitems.substring(l-8,l-2)+"."+dataitems.substring(l-2,l));
									l-=8;
									r.put("无功电量2",dataitems.substring(l-8,l-2)+"."+dataitems.substring(l-2,l));
									r.put("parsenum", "3");
								}else {
									r.put("电量",dataitems.substring(0,6)+"."+dataitems.substring(6,8));
								}
							}else if("0000FF00".equalsIgnoreCase(dtdi)) {
								if(dl>=24) {
									int l=dataitems.length()-8;
									r.put("电量",dataitems.substring(l-8,l-2)+"."+dataitems.substring(l-2,l));
									l-=8;
									r.put("费率1电量",dataitems.substring(l-8,l-2)+"."+dataitems.substring(l-2,l));
									l-=8;
									r.put("费率2电量",dataitems.substring(l-8,l-2)+"."+dataitems.substring(l-2,l));
									l-=8;
									r.put("费率3电量",dataitems.substring(l-8,l-2)+"."+dataitems.substring(l-2,l));
									l-=8;
									r.put("费率4电量",dataitems.substring(l-8,l-2)+"."+dataitems.substring(l-2,l));

								}else {
									r.put("电量",dataitems.substring(0,6)+"."+dataitems.substring(6,8));
								}
							}
							/*
		System.out.println(tohex(encode("332316420","dtdi","04000101")));//日期
		System.out.println(tohex(encode("332316420","dtdi","04000102")));//时间
		System.out.println(tohex(encode("332316420","dtdi","02010100")));//电压 A相
		System.out.println(tohex(encode("332316420","dtdi","02020100")));//电流
		System.out.println(tohex(encode("332316420","dtdi","02030000")));//有功功率
		System.out.println(tohex(encode("332316420","dtdi","02060000")));//功率因数
							 */

						}
					}else if(c==0xdc||c==0xd1||c==0xd4) {
						r.put("error", "电表否认");
						r.put("resp", "error");
					}else if((c>>4)==9) {
						r.put("resp", "ok");
					}else {
						r.put("error", "电表否认");
						r.put("resp", "error");
					}

				}
				return r;
			}else {
				//水表，只解析出表号，并需要通过水表协议解析程序进一步解析
				String devcecode=tohex(data,offset+2,7,true);
				r.put("devicecode", devcecode);
			}
		}
		return r;
	}

	public static String zerodel(String dataitems){
		String datas = "";
		for(int i=0;i>dataitems.length();i++){
			if(Integer.parseInt(dataitems.substring(i)) == 0 || "0".equalsIgnoreCase(dataitems.substring(i, i+1))){
				continue;
			}
			datas = dataitems.substring(i);
		}
		return datas;
	}
	public static byte[] encode(String device,String...params) {
		Map<String, String> p=new HashMap<String,String>();
		boolean odd=true;
		String k="_";
		for(String s:params) {
			if(odd) {
				k=s;
			}else {
				p.put(k, s);
			}
			odd=!odd;
		}
		System.out.println("1、："+device+"；"+p.toString());
		return encode(device,p);

	}
	public static byte[] encode(String device, Map<String, String> params) {
		//将操作命令参数打包成二进制指令
		if(params.get("codetype")==null||"00".equalsIgnoreCase(params.get("codetype"))) {
			//电表
			String cmd=params.get("cmd");
			if(cmd!=null) {
				//2025年12月20号15点32分38
				String dtms="251220153238";
				if(cmd.equalsIgnoreCase("clear")) {
					//清零
					return encode_dlt645_2007(device,0x1a,""+password+operatorcode+"");
				}else if(cmd.equalsIgnoreCase("open")) {
					//合闸
					return encode_dlt645_2007(device,0x1C,dtms+"001C "+password+operatorcode+"");
				}else if(cmd.equalsIgnoreCase("close")) {
					//拉闸
					return encode_dlt645_2007(device,0x1C,dtms+"001A "+password+operatorcode+"");
				}else if(cmd.equalsIgnoreCase("warn")) {
					//告警
					return encode_dlt645_2007(device,0x1C,dtms+"002A "+password+operatorcode+"");
				}else if(cmd.equalsIgnoreCase("nowarn")) {
					//解除告警
					return encode_dlt645_2007(device,0x1C,dtms+"002B "+password+operatorcode+"");
				}else if(cmd.equalsIgnoreCase("setdate")) {
					//设置日期
					dtms="";//年月日周
					String strdtm=params.get("date");
					Calendar cl= Calendar.getInstance();
					//cl.setFirstDayOfWeek(java.Calendar.MONDAY);
					if(strdtm!=null) {
						try {
							cl.setTime(java.text.DateFormat.getDateInstance().parse(strdtm));
						} catch (Exception e) {
							// TODO Auto-generated catch block
							//e.printStackTrace();
						}
					}
					dtms=new SimpleDateFormat("yyMMdd").format(cl.getTime())+("0"+(cl.get(Calendar.DAY_OF_WEEK)+1));
					return encode_dlt645_2007(device,0x14,dtms+" "+password+operatorcode+" 04000101");
				}else if(cmd.equalsIgnoreCase("settime")) {
					//设置时间
					dtms="";//时分秒
					String strdtm=params.get("time");
					Calendar cl=Calendar.getInstance();
					if(strdtm!=null) {
						strdtm=strdtm.replace(":", "");
						if(strdtm.length()==6) {
							dtms=strdtm;
						}else {
							//格式错误
							dtms=new SimpleDateFormat("hhmmss").format(cl.getTime());
						}
					}else {
						dtms=new SimpleDateFormat("hhmmss").format(cl.getTime());
					}
					return encode_dlt645_2007(device,0x14,dtms+" "+password+operatorcode+" 04000102");
				}
			}
			String strc=params.get("c");
			String strdata=null;
			int c=0x11;
			try{
				c=Integer.parseInt(strc);
			}catch(Exception e) {

			}
			if(c==0x14||c==0x11) {
				//写数据
				String strdtdi=params.get("dtdi");
				if(strdtdi==null) {
					strdtdi="00000000";
				}else {
					while(strdtdi.length()<8) {
						strdtdi='0'+strdtdi;
					}
				}
				strdata=params.get("data");
				if(strdata==null) {
					strdata="";
				}
				strdata=strdata+strdtdi;
			}else {
				strdata=params.get("data");
			}
			return encode_dlt645_2007(device,c,strdata);
		}
		return null;
	}
	public static byte[] encode_dlt645_2007(String devicecode, int c, String strdata) {
		byte[] data=strdata==null?new byte[0]:fromhex(strdata);
		String tdev="0000000000000"+devicecode;
		byte[] addr=fromhex(tdev.substring(tdev.length()-12));
		int dl=data.length;
		for(int i=0;i<dl/2;i++) {
			byte b=(byte) (data[i]+0x33);
			data[i]=(byte) (data[dl-i-1]+0x33);
			data[dl-i-1]=b;
		}
		if(dl%2>0) {
			data[dl/2]+=0x33;
		}
		int fenum=4;
		int cc=0x68+0x68+c+dl;
		byte[] r=new byte[fenum+dl+12];
		for(int i=0;i<fenum;i++) {
			r[i]=(byte) 0xfe;
		}
		r[fenum+0]=r[fenum+7]=0x68;
		for(int i=0;i<6;i++) {
			r[fenum+6-i]=addr[i];
			cc+=addr[i];
		}
		r[fenum+8]=(byte) c;
		r[fenum+9]=(byte) dl;
		for(int i=0;i<data.length;i++) {
			r[fenum+10+i]=data[i];
			cc+=data[i];
		}
		r[fenum+dl+10]=(byte)cc;
		r[fenum+dl+11]=0x16;
		return r;
	}
	protected final static String[] HEXCHARS="0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F".split(",");
	public static final class Arrays{

		public static String last(String[] ss, boolean allocempty) {
			int i=ss==null?-1:ss.length-1;
			while(i>=0) {
				if("".equalsIgnoreCase(ss[i])&&(!allocempty)) {
					i--;
					continue;
				}
				return ss[i];
			}
			return null;
		}

	}
	public static int checksum(byte[] data, int spos, int epos) {
		int r=0;
		for(int i=spos;i<epos;i++) {
			r+=0xff&data[i];
		}
		return r&0xff;
	}

	public static Date parsetime(String tm) {
		SimpleDateFormat utcFormater = new SimpleDateFormat("yyyyMMdd'T'hhmmss'Z'");//20180412T034306Z
	    utcFormater.setTimeZone(TimeZone.getTimeZone("UTC"));
		try {
			return utcFormater.parse(tm);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	public static String tohex(byte[] data) {
		if(data==null) {
			return "";
		}
		StringBuffer sb=new StringBuffer();
		for(byte b:data) {
			sb.append(tohex(b));
		}
		return sb.toString();
	}

	public static String tohex(byte b) {
		int iv=b;
		if(iv<0) {
			iv+=256;
		}
		return HEXCHARS[iv>>4]+HEXCHARS[iv&0x0f];
	}
	public static int toint(byte v) {
		int iv=v;
		if(iv<0) {
			iv+=256;
		}
		return iv;
	}
	public static String tohex(int v) {
		int iv=v;
		if(iv<0) {
			iv+=256;
		}
		return HEXCHARS[(iv>>4)]+HEXCHARS[iv&0x0f];
	}
	public static String tohex(byte[] data, int offset, int len, boolean revert) {
		if(data==null) {
			return "";
		}
		StringBuffer sb=new StringBuffer();
		if(revert) {
			for(int i=offset+len-1;i>=offset;i--) {
				sb.append(tohex(data[i]));
			}
		}else {
			for(int i=offset;i<offset+len;i++) {
				sb.append(tohex(data[i]));
			}
		}
		return sb.toString();
	}
	public static String tohex33(byte[] data, int offset, int len, boolean revert) {
		if(data==null) {
			return "";
		}
		StringBuffer sb=new StringBuffer();
		if(revert) {
			for(int i=offset+len-1;i>=offset;i--) {
				sb.append(tohex(data[i]-((byte)0x33)));
			}
		}else {
			for(int i=offset;i<offset+len;i++) {
				sb.append(tohex(data[i]-((byte)0x33)));
			}
		}
		return sb.toString();
	}

	public static double trim(double t, int i) {
		int p=(int)Math.pow(10,i);
		return ((double)Math.round(t*p))/p;
	}

	public static byte[] fromhex(String s) {
		int b=-1;
		int rl=0;
		byte[] r=new byte[s.length()];
		for(int i=0;i<s.length();i++) {
			int c=s.charAt(i);
			if('0'<=c&&c<='9') {
				c-='0';
			}else if('a'<=c&&c<='f') {
				c-='a';
				c+=10;
			}else if('A'<=c&&c<='F') {
				c-='A';
				c+=10;
			}else if(b<0){
				continue;
			}
			if(b<0) {
				b=c;
			}else{
				r[rl]=(byte) ((b<<4)+c);
				rl++;
				b=-1;
			}
		}
		return java.util.Arrays.copyOf(r, rl);
	}

	public static byte[] revert(byte[] buf) {
		int halfl=buf.length/2;
		for(int i=0;i<halfl;i++) {
			byte b=buf[i];
			buf[i]=buf[buf.length-1-i];
			buf[buf.length-1-i]=b;
		}
		return buf;
	}

	public static boolean[] tobin(int f, int c) {
		if(c<1) {
			return new boolean[0];
		}
		int n=f;
		boolean[] r=new boolean[c];
		for(int i=0;i<c;i++) {
			r[i]=(n&1)==1;
			n>>=1;
		}
		return r;
	}
	public static boolean[] tobin(byte[] data) {
		if(data==null) {
			return new boolean[0];
		}
		boolean[] r=new boolean[data.length*8];

		for(int i=0;i<data.length;i++) {
			int n=(256+data[i])%256;
			for(int j=0;j<8;j++) {
				r[i*8+j]=(n&1)==1;
				n>>=1;
			}
		}
		return r;
	}
	public static int toint(boolean[] b) {
		int r=0;
		for(int i=b.length-1;i>=0;i--) {
			r=r<<1;
			r+=b[i]?1:0;
		}
		return r;
	}

	public static long multiply_long(long...ls) {
		long r=1;
		for(long l0:ls) {
			r*=l0;
		}
		return r;
	}

	public static String tryutf8string(String s) {
		if(s!=null) {
			try {
				ByteBuffer bb = ByteBuffer.wrap(s.getBytes("iso-8859-1"));
				String s1=""+java.nio.charset.Charset.forName("iso-8859-1").decode(bb);
				if(java.util.Arrays.equals(s1.getBytes(),s.getBytes())) {
					return new String(s.getBytes("iso-8859-1"),"utf-8");
				}
			} catch (Exception e) {
			}
		}
		return s;
	}

	public static void fillbcd(int v, byte[] r, int offset, int len) {
		try {
		int t=v;
		for(int i=0;i<len;i++) {
			int b=t%100;
			t/=100;
			r[offset+i]=(byte)(((b/10)<<4)+b%10);
		}
		}catch(Exception e) {
			e.printStackTrace();
		}
	}

	public static int tryToInt(Object v, int defaultvalue) {
		if(null!=v) {
			if(v instanceof Number) {
				return ((Number)v).intValue();
			}
			if(v instanceof String) {
				int r=0;
				String sv = (String)v;
				String[] ssv=sv.split("\\D");
				for(int i=0;i<ssv.length;i++) {
					String sv0=ssv[i];
					if(sv0.length()<3) {
						r*=100;
					}else if(sv0.length()<5) {
						r*=10000;
					}else if(sv0.length()<7) {
						r*=1000000;
					}else{
						r*=1000000;
					}
					try{
						r+=Integer.parseInt(sv0);
					}catch(Exception e1) {

					}

				}
				return r;
			}
		}
		return defaultvalue;
	}

}
