package com.szpg.plc.util;

public class ByteUtil {

	/* BCD码转换为数值或字符 */

	/**
	 * 单一字节中选择指定位bcd码转换为整数
	 * 如ByteUtil.bcdToInt((byte) 0x33, 5, 4) = 3
	 * 
	 * @param b
	 * @param highBit 高位,最大7
	 * @param lowBit 低位,从0开始
	 * @return
	 */
	public static int bcdToInt(byte b, int highBit, int lowBit) {
		int g = highBit - lowBit + 1;
		int a = ((int) Math.pow(2, g) - 1) << lowBit;
		int b2 = (b & a) >> lowBit;
		if (b2 < 0 || b2 >= 10) {
			return -1;
		}
		return b2;
	}

	/**
	 * bcd码转换为整数 错误则返回-1
	 * 如ByteUtil.bcdToInt((byte) 0x73) = 73
	 * 
	 * @param b 输入字节,默认4位一组,先高后低
	 * @return
	 */
	public static int bcdToInt(byte b) {
		int pl = 0x0f;
		int ph = 0xf0;

		int h = (ph & b) >> 4;
		int l = (pl & b);

		if (h >= 10 || l >= 10) {
			return -1;
		}
		return h * 10 + l;
	}

	/**
	 * bcd码转换为long型整数 
	 * 如字节数组{0x25, 0x23}转换为2523
	 * 
	 * @param b
	 * @return
	 */
	public static long bcdToLong(byte[] bytes) {
		if (ByteUtil.bcdToString(bytes).equals("") == false)
			return Long.valueOf(ByteUtil.bcdToString(bytes)).longValue();
		else 
			return -1;
	}


	/**
	 * bcd码转换为字符串 按字节顺序 高位在前低位在后 
	 * 如字节数组{0x01, 0x02, 0x03}转换为"010203"
	 * 
	 * @param bytes
	 * @return
	 */
	public static String bcdToString(byte[] bytes) {
		StringBuilder sb = new StringBuilder();

		for (int i = 0; i < bytes.length; i++) {
			if (ByteUtil.bcdToInt(bytes[i], 7, 4) != -1 && ByteUtil.bcdToInt(bytes[i], 3, 0) != -1) {
				sb.append(ByteUtil.bcdToInt(bytes[i], 7, 4));
				sb.append(ByteUtil.bcdToInt(bytes[i], 3, 0));
			}
		}

		return sb.toString();
	}

	
	/* BIN码转换为数值或字符 */
	
	/**
	 * 单一字节中选择指定位bin码转换为整数
	 * 如ByteUtil.binToInt((byte) 0xA3, 7, 7) = 1
	 * 
	 * @param b
	 * @param highBit 高位,最大7
	 * @param lowBit 低位,从0开始
	 * @return
	 */
	public static int binToInt(byte b, int highBit, int lowBit) throws RuntimeException {
		int g = highBit - lowBit + 1;
		int a = ((int) Math.pow(2, g) - 1) << lowBit;
		int b2 = (b & a) >> lowBit;
		if (b2 < 0 || b2 >= 16) {
			throw new RuntimeException();
		}
		return b2;
	}
	
	/**
	 * BIN字节转换为整数
	 * 如ByteUtil.bcdToInt((byte) 0x7B) = 123
	 * 
	 * @param b
	 * @return
	 */
	public static int binToInt(byte b) {
		int i1 = 0x80 & b;
		if (i1 == 0x80) {
			int i2 = 0x7f & b;
			return 128 + i2;
		} else {
			return b;
		}
	}

	/**
	 * BIN码转换为整数 高位在前低位在后
	 * 如ByteUtil.bcdToInt(new byte[] {(byte) 0x7B, 0x22}) = 31522
	 * 
	 * @param bytes
	 * @return
	 */
	public static int binToInt(byte[] bytes) {
		int i10 = 0;
		if (null != bytes && bytes.length != 0) {
			for (int i = 0; i < bytes.length; i++) {
				i10 = i10 + new Double(Math.pow(16, (bytes.length - i - 1) * 2)).intValue() * ByteUtil.binToInt(bytes[i]);
			}
		}
		return i10;
	}

	/**
	 * BIN码转换为LONG型整数 高位在前低位在后
	 * 如ByteUtil.bcdToLong(new byte[] {(byte) 0x7B, 0x22, 0x32, 0x9A}) = 2065838746
	 * 
	 * @param bytes
	 * @return
	 */
	public static int binToLong(byte[] bytes) {
		int l10 = 0;
		if (null != bytes && bytes.length != 0) {
			for (int i = 0; i < bytes.length; i++) {
				l10 = l10 + new Double(Math.pow(16, (bytes.length - i - 1) * 2)).intValue() * ByteUtil.binToInt(bytes[i]);
			}
		}
		return l10;
	}

	/**
	 * 字节数组转换为16进制字符串 按字节数组顺序转换
	 * 如字节数组{0x21, 0x06, 0x01, 0x04, 0x40, (byte) 0xE2, 0x01}转换为"2106010440E201"
	 * 
	 * @param bytes
	 * @return
	 */
	public static String binToHexString(byte[] bytes) {
		StringBuilder sb = new StringBuilder();

		for (int i = 0; i < bytes.length; i++) {
			sb.append(Integer.toHexString(binToInt((byte) ((bytes[i] & 0xf0) >> 4))).toUpperCase());
			sb.append(Integer.toHexString(binToInt((byte) (bytes[i] & 0x0f))).toUpperCase());
		}

		return sb.toString();
	}
	
	/**
	 * 字节数组转换位16进制字符串
	 * 按字节数组顺序转换
	 * 如字节数组{0x21, 0x06, 0x01, 0x04, 0x40, (byte) 0xE2, 0x01}转换为"2106010440E201"
	 * start和end为substring方法的参数，表示从起始字符开始，截取到不包括结束字符的子串
	 * 
	 * @param bytes
	 * @param start
	 * @param end
	 * @return
	 */
	public static String binToHexString(byte[] bytes, int start, int end) {
		String str = binToHexString(bytes);
		
		if (null != str && str.equals("") == false && str.length() >= end) 
			return str.substring(start, end);
		
		return "";
	}
	
	
	/**
	 * BIN输出为二进制字符串
	 * 如字节数组{0x01, 0x38}转换为字符串"0000000100111000"
	 * 
	 * @param bytes
	 * @return
	 */
	public static String binToBinString(byte[] bytes) {
		StringBuilder sb = new StringBuilder();

		for (int i = 0; i < bytes.length; i++) {
			String s = Integer.toBinaryString(binToInt(bytes[i]));
			while (s.length() < 8) {
				s = "0" + s;
			}
			sb.append(s);
		}

		return sb.toString();
	}
	
	
	/* int转换为BCD码或BIN码 */
	/**
	 * 两位整数转换成一个字节的BCD码 
	 * 大于100的整数取其十位和个位 十位在前个位在后
	 * 如79转换为0x79
	 * 
	 * @param i
	 * @return
	 */
	public static byte intToBcd(int i) {
		byte b = 0x00;
		while (i > 99) {
			i = i % 100;
		}

		int l = i % 10;
		int h = i / 10;

		b = (byte) (h << 4 | l);

		return b;
	}

	/**
	 * 整数转换为字节数组 高位在前低位在后
	 * 如 2379转换为0x23, 0x79
	 * 
	 * @param i
	 * @return
	 */
	public static byte[] intToBcds(long l) {
		String str = String.valueOf(l);
		Bytes bytes = new Bytes();

		if (str.length() % 2 == 1) {
			str = "0" + str;
		}

		for (int i = 0; i < str.length() - 1; i = i + 2) {
			String s = str.substring(i, i + 2);
			bytes.append(ByteUtil.intToBcd(Integer.parseInt(s)));
		}

		return bytes.toBytes();
	}

	/**
	 * 整数转换为指定字节数的BCD码数组 高位在前低位在后 从低位开始计算长度 超出部分忽略 不足部分在高位补0
	 * 如 3013479指定2字节转换为0x34, 0x79, 指定6字节转换为0x00, 0x00, 0x03, 0x01, 0x34, 0x79
	 * 
	 * @param i
	 * @param length
	 * @return
	 */
	public static byte[] intToBcds(long l, int length) {
		byte[] bts = intToBcds(l);
		if (bts.length == length) {
			return bts;
		} else {
			byte[] bytes = new byte[length];
			for (int j = length - 1; j >= 0; j--) {
				if (j + bts.length - length >= 0) {
					bytes[j] = bts[j + bts.length - length];
				} else {
					bytes[j] = 0x00;
				}
			}
			
			return bytes;
		}
	}
	
	/**
	 * 整数转换为指定字节数的BCD码数组 低位在前高位在后 从低位开始计算长度 超出部分忽略 不足部分在高位补0
	 * 如 3013479指定2字节转换为0x79, 0x34, 指定6字节转换为0x79, 0x34, 0x01, 0x03, 0x00, 0x00
	 * 
	 * @param i
	 * @param length
	 * @return
	 */
	public static byte[] intToBcdsHL(long l, int length) {
		Bytes bs = new Bytes();
		
		for (int i = 0; i < length; i++) {
			int low = (int) (l % 100);
			bs.append(ByteUtil.intToBcd(low));
			l = l / 100;
		}
		
		return bs.toBytes();
	}

	/**
	 * 整数转换为BIN码字节数组 高位在前低位在后
	 * 如113479转换为0x01, 0xBB, 0x47
	 * 
	 * @param l
	 * @return
	 */
	public static byte[] intToBins(long l) {
		String str = Long.toHexString(l);
		if (str.length() % 2 == 1) {
			str = "0" + str;
		}
		
		Bytes bytes = new Bytes();
		for (int i = 0; i < str.length() - 1; i = i + 2) {
			String s = str.substring(i, i + 2);
			bytes.append((byte) Integer.parseInt(s, 16));
		}
		
		return bytes.toBytes();
	}

	/**
	 * 整数转换为指定字节数的BIN码数组 高位在前低位在后 从低位开始计算长度 超出部分忽略 不足部分在高位补0
	 * 如 3013479指定2字节转换为0xFB, 0x67, 指定6字节转换为0x00, 0x00, 0x00, 0x2D, 0xFB, 0x67
	 * 
	 * @param l
	 * @param length
	 * @return
	 */
	public static byte[] intToBins(long l, int length) {
		byte[] bts = intToBins(l);
		if (bts.length == length) {
			return bts;
		} else {
			byte[] bytes = new byte[length];
			for (int j = length - 1; j >= 0; j--) {
				if (j + bts.length - length >= 0) {
					bytes[j] = bts[j + bts.length - length];
				} else {
					bytes[j] = 0x00;
				}
			}
			
			return bytes;
		}
	}

	
	/* 16进制字符串转换为字节数组 */
	/**
	 * 16进制字符串顺序转换为字节数组
	 * 如字符串"13810411703"转换为字节数组{0x01, 0x38, 0x10, 0x41, 0x17, 0x03}
	 * 
	 * @param str
	 * @return
	 */
	public static byte[] hexStringToBytes(String str) {
		if (str.length() % 2 == 1) {
			str = "0" + str;
		}
		
		Bytes bytes = new Bytes();
		for (int i = 0; i < str.length() - 1; i = i + 2) {
			String s = str.substring(i, i + 2);
			bytes.append((byte) Integer.parseInt(s, 16));
		}

		return bytes.toBytes();
	}

	/**
	 * 16进制字符串顺序转换为指定字节数的BIN码数组 从低位开始计算长度 超出部分忽略 不足部分在高位补0
	 * 如字符串"13810411703"转换为3字节数组{0x41, 0x17, 0x03}, 指定8字节转换为{0x00, 0x00, 0x01, 0x38, 0x10, 0x41, 0x17, 0x03}
	 * 
	 * @param str
	 * @param length
	 * @return
	 */
	public static byte[] hexStringToBytes(String str, int length) {
		byte[] bts = hexStringToBytes(str);
		if (bts.length == length) {
			return bts;
		} else {
			byte[] bytes = new byte[length];
			for (int j = length - 1; j >= 0; j--) {
				if (j + bts.length - length >= 0) {
					bytes[j] = bts[j + bts.length - length];
				} else {
					bytes[j] = 0x00;
				}
			}
			
			return bytes;
		}
	}

	
	/* 十进制BCD码字符串转换为字节数组 */
	/**
	 * 十进制BCD码字符串顺序转换为字节数组
	 * 如字符串"13810411703"转换为字节数组{0x01, 0x38, 0x10, 0x41, 0x17, 0x03}
	 * 
	 * @param str
	 * @return
	 */
	public static byte[] bcdStringToBytes(String str) {
		if (str.length() % 2 == 1) {
			str = "0" + str;
		}

		Bytes bytes = new Bytes();
		for (int i = 0; i < str.length() - 1; i = i + 2) {
			String s = str.substring(i, i + 2);
			bytes.append(ByteUtil.intToBcd(Integer.parseInt(s)));
		}

		return bytes.toBytes();
	}
	
	/**
	 * 十进制BCD码字符串顺序转换为指定字节数的BCD码数组 从低位开始计算长度 超出部分忽略 不足部分在高位补0
	 * 如字符串"13810411703"转换为3字节数组{0x41, 0x17, 0x03}, 指定8字节转换为{0x00, 0x00, 0x01, 0x38, 0x10, 0x41, 0x17, 0x03}
	 * 
	 * @param str
	 * @param length
	 * @return
	 */
	public static byte[] bcdStringToBytes(String str, int length) {
		byte[] bts = bcdStringToBytes(str);
		if (bts.length == length) {
			return bts;
		} else {
			byte[] bytes = new byte[length];
			for (int j = length - 1; j >= 0; j--) {
				if (j + bts.length - length >= 0) {
					bytes[j] = bts[j + bts.length - length];
				} else {
					bytes[j] = 0x00;
				}
			}
			
			return bytes;
		}
	}
}
