package com.jsowell.common.util;

import com.google.common.primitives.Bytes;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Stack;

public class BytesUtil {

	static final long fx = 0xffl;

	/**
	 * 将int数值转换为占两个字节的byte数组，本方法适用于(高位在前，低位在后)的顺序。
	 */
	public static byte[] intToBytes(int value) {
		//limit 传入2
		return intToBytes(value, 2);
	}

	public static byte[] intToBytes(int value, int limit) {
		byte[] src = new byte[limit];
		for (int i = 0; i < limit; i++) {
			int x = 8 * (limit - i - 1);
			if (x == 0) {
				src[i] = (byte) (value & 0xFF);
			} else {
				src[i] = (byte) ((value >> x) & 0xFF);
			}
		}
		return src;
	}

	public static int bytesToInt(byte[] src) {
		return bytesToInt(src, 0);
	}

	/**
	 * byte数组中取int数值，本方法适用于(低位在后，高位在前)的顺序。
	 */
	public static int bytesToInt(byte[] src, int offset) {
		if (src == null) {
			return 0;
		}
		while (src.length > 0 && src[0] == 0x00) {
			src = BytesUtil.copyBytes(src, 1, src.length - 1);
		}
		if (src.length == 0) {
			return 0;
		}
		int len = src.length;
		if (len == 0) {
			return 0;
		}
		int value = 0;
		for (int i = 0; i < len; i++) {
			if (i == (len - 1)) {
				value = value | ((src[i] & 0xFF));
			}
			value = value | ((src[i] & 0xFF) << (8 * (len - i - 1)));
		}
		return value;
	}

	/**
	 * long转字节，大端模式
	 *
	 * @param number
	 * @return
	 */
	public static byte[] long2Byte(long number) {
		long temp = number;
		byte[] b = new byte[8];
		for (int i = (b.length - 1); i >= 0; i--) {
			b[i] = new Long(temp & 0xff).byteValue();//
			//将最低位保存在最低位
			temp = temp >> 8;// 向右移8位
		}
		return b;
	}

	/**
	 * 字节转long 大端模式
	 *
	 * @param b
	 * @return
	 */
	public static long byte2Long(byte[] b) {
		long s = 0;
		long s0 = b[7] & 0xff;
		long s1 = b[6] & 0xff;
		long s2 = b[5] & 0xff;
		long s3 = b[4] & 0xff;
		long s4 = b[3] & 0xff;
		long s5 = b[2] & 0xff;
		long s6 = b[1] & 0xff;
		long s7 = b[0] & 0xff;

		// s0不变
		s1 <<= 8;
		s2 <<= 16;
		s3 <<= 24;
		s4 <<= 8 * 4;
		s5 <<= 8 * 5;
		s6 <<= 8 * 6;
		s7 <<= 8 * 7;
		s = s0 | s1 | s2 | s3 | s4 | s5 | s6 | s7;
		return s;
	}

	/**
	 * 从一个byte数组中拷贝一部分出来
	 *
	 * @param oriBytes
	 * @param startIndex
	 * @param length
	 * @return
	 */
	public static byte[] copyBytes(byte[] oriBytes, int startIndex, int length) {
		int endIndex = startIndex + length;
		byte[] bts = new byte[length];
		int index = 0;
		for (int i = 0; i < oriBytes.length; i++) {
			if (i >= startIndex && i < endIndex) {
				bts[index] = oriBytes[i];
				index++;
			}
		}
		return bts;
	}

	/**
	 * 将byte[]转为各种进制的字符串
	 *
	 * @param bytes byte[]
	 * @param radix 基数可以转换进制的范围，从Character.MIN_RADIX到Character.MAX_RADIX，超出范围后变为10进制
	 * @return 转换后的字符串
	 */
	public static String binary(byte[] bytes, int radix) {
		return new BigInteger(1, bytes).toString(radix);// 这里的1代表正数
	}

	/**
	 * @函数功能: BCD码转为10进制串(阿拉伯数据)
	 * @输入参数: BCD码
	 * @输出结果: 10进制串
	 */
	public static String bcd2Str(byte[] bytes) {
		StringBuffer temp = new StringBuffer(bytes.length * 2);
		for (int i = 0; i < bytes.length; i++) {
			temp.append((byte) ((bytes[i] & 0xf0) >>> 4));
			temp.append((byte) (bytes[i] & 0x0f));
		}
		return temp.toString();
	}

	public static String bcd2StrContainA(byte[] bytes) {
		char temp[] = new char[bytes.length * 2], val;
		for (int i = 0; i < bytes.length; i++) {
			val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f);
			temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
			val = (char) (bytes[i] & 0x0f);
			temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
		}
		return new String(temp);
	}

	/**
	 * @函数功能: BCD码转为10进制串(阿拉伯数据) 小端模式
	 * @输入参数: BCD码
	 * @输出结果: 10进制串
	 */
	public static String bcd2StrLittle(byte[] bytes) {
		Stack<String> strings = new Stack<>();
		String temp = bcd2Str(bytes);
		for (int i = 0; i < temp.length(); i = i + 2) {
			strings.push(temp.substring(i, i + 2));
		}
		StringBuilder stringBuilder = new StringBuilder();
		while (!strings.isEmpty()) {
			stringBuilder.append(strings.pop());
		}
		return stringBuilder.toString();
	}

	/**
	 * @函数功能: BCD码转为10进制串(阿拉伯数据) 小端模式
	 * @输入参数: BCD码
	 * @输出结果: 10进制串
	 */
	public static String bcd2StrLittleContainA(byte[] bytes) {
		Stack<String> strings = new Stack<>();
		String temp = bcd2StrContainA(bytes);
		for (int i = 0; i < temp.length(); i = i + 2) {
			strings.push(temp.substring(i, i + 2));
		}
		StringBuilder stringBuilder = new StringBuilder();
		while (!strings.isEmpty()) {
			stringBuilder.append(strings.pop());
		}
		return stringBuilder.toString();
	}

	/**
	 * @函数功能: 10进制串转为BCD码
	 * @输入参数: 10进制串
	 * @输出结果: BCD码
	 */
	public static byte[] str2Bcd(String asc) {
		if (asc == null) {
			asc = "";
		}
		int len = asc.length();
		int mod = len % 2;
		if (mod != 0) {
			asc = "0" + asc;
			len = asc.length();
		}
		byte abt[] = new byte[len];
		if (len >= 2) {
			len = len / 2;
		}
		byte bbt[] = new byte[len];
		abt = asc.getBytes();
		int j, k;
		for (int p = 0; p < asc.length() / 2; p++) {
			if ((abt[2 * p] >= '0') && (abt[2 * p] <= '9')) {
				j = abt[2 * p] - '0';
			} else if ((abt[2 * p] >= 'a') && (abt[2 * p] <= 'z')) {
				j = abt[2 * p] - 'a' + 0x0a;
			} else {
				j = abt[2 * p] - 'A' + 0x0a;
			}
			if ((abt[2 * p + 1] >= '0') && (abt[2 * p + 1] <= '9')) {
				k = abt[2 * p + 1] - '0';
			} else if ((abt[2 * p + 1] >= 'a') && (abt[2 * p + 1] <= 'z')) {
				k = abt[2 * p + 1] - 'a' + 0x0a;
			} else {
				k = abt[2 * p + 1] - 'A' + 0x0a;
			}
			int a = (j << 4) + k;
			byte b = (byte) a;
			bbt[p] = b;
		}
		return bbt;
	}

	/**
	 * @函数功能: 10进制串转为BCD码
	 * @输入参数: 10进制串
	 * @输出结果: BCD码
	 */
	public static byte[] str2BcdLittle(String asc) {
		byte[] temp = str2Bcd(asc);
		return revert(temp);
	}

	/**
	 * 将int转为byte 小端模式
	 *
	 * @param value int值
	 * @return
	 */
	public static byte[] intToBytesLittle(int value) {
		//limit 传入2
		return intToBytes(value, 2);
	}

	/**
	 * 将int转换byte 小端模式
	 *
	 * @param value int值
	 * @param limit 保留长度
	 * @return
	 */
	public static byte[] intToBytesLittle(int value, int limit) {
		byte[] src = new byte[limit];
		for (int i = 0; i < limit; i++) {
			int x = 8 * i;
			if (x == 0) {
				src[i] = (byte) (value & 0xFF);
			} else {
				src[i] = (byte) ((value >> x) & 0xFF);
			}
		}
		return src;
	}

	/**
	 * byte数组中取int数值，本方法适用于(低位在前，高位在后 )的顺序。小端模式
	 */
	public static int bytesToIntLittle(byte[] src) {
		if (src == null) {
			return 0;
		}
		int len = src.length;
		if (len == 0) {
			return 0;
		}
		int value = 0;
		for (int i = 0; i < len; i++) {
			value = value | ((src[i] & 0xFF) << (8 * i));
		}
		return value;
	}

	/**
	 * long转字节，小端模式
	 *
	 * @param number
	 * @param limit  保留字节位
	 * @return
	 */
	public static byte[] long2ByteLittle(long number, int limit) {
		long temp = number;
		byte[] b = new byte[limit];
		for (int i = 0; i < b.length; i++) {
			b[i] = new Long(temp & 0xff).byteValue();//
			//将最低位保存在最前面
			temp = temp >> 8;// 向右移8位
		}
		return b;
	}


	/**
	 * 字节转long 小端模式
	 *
	 * @param src
	 * @return
	 */
	public static long byte2LongLittle(byte[] src) {
		long s = 0;
		for (int i = 0; i < src.length; i++) {
			//防止转为int
			long si = src[i] & 0xFF;
			si = si << (8 * i);
			s = s | si;
		}
		return s;
	}

	/**
	 * 使用字节数组替换目标数组从指定位置开始替换字节
	 *
	 * @param target     被替换的数组
	 * @param startIndex 开始位置
	 * @param replace    用于替换的数组
	 */
	public static void replaceBytes(byte[] target, int startIndex, byte[] replace) {
		// 暂时由外界保证不会出数组越界的异常
		for (int i = 0; i < replace.length; i++) {
			int targetIndex = startIndex + i;
			target[targetIndex] = replace[i];
		}
	}

	/**
	 * 创建数组
	 *
	 * @param bytes 用于替换的数组
	 */
	public static byte[] createByteArray(byte... bytes) {
		byte[] temp = new byte[bytes.length];
		for (int i = 0; i < bytes.length; i++) {
			temp[i] = bytes[i];
		}
		return temp;
	}

	public static byte[] rightPadBytes(byte[] target, int len, byte b) {
		int length = target.length;
		if (len <= length) {
			return target;
		}
		int addedLen = len - length;
		byte[] added = new byte[addedLen];
		for (int i = 0; i < addedLen; i++) {
			added[i] = b;
		}
		return Bytes.concat(target, added);
	}

	public static byte[] rightPadBytes(String targetStr, int len, byte b) {
		if (targetStr == null) {
			targetStr = "";
		}
		byte[] target = targetStr.getBytes();
		return rightPadBytes(target, len, b);
	}

	public static String ascii2StrLittle(byte[] ascs) {
		byte[] data = revert(ascs);
		String asciiStr = null;
		try {
			asciiStr = new String(data, "ISO8859-1");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return asciiStr;
	}

	public static String ascii2Str(byte[] ascs) {
		byte[] data = ascs;
		String asciiStr = null;
		try {
			asciiStr = new String(data, "ISO8859-1");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return asciiStr;
	}

	public static byte[] str2AscLittle(String str) {
		return revert(str2Asc(str));
	}

	public static byte[] str2Asc(String str) {
		byte[] bytes = null;
		try {
			bytes = str.getBytes("ISO8859-1");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return bytes;
	}

	/**
	 * 反转byte数组
	 *
	 * @param temp
	 * @return
	 */
	public static byte[] revert(byte[] temp) {
		byte[] ret = new byte[temp.length];
		for (int i = 0; i < temp.length; i++) {
			ret[temp.length - i - 1] = temp[i];
		}
		return ret;
	}

	/**
	 * cp56time2a 格式转date格式
	 */
	public static Date byteCp2Date(byte[] bytes) {
		if (bytes == null || bytes.length != 7) {
			return null;
		}
		int ms = bytesToIntLittle(copyBytes(bytes, 0, 2));
		int min = bytesToIntLittle(copyBytes(bytes, 2, 1));
		int hour = bytesToIntLittle(copyBytes(bytes, 3, 1));
		int day = bytesToIntLittle(copyBytes(bytes, 4, 1));
		int month = bytesToIntLittle(copyBytes(bytes, 5, 1));
		int year = bytesToIntLittle(copyBytes(bytes, 6, 1));
		if (month == 0 || day == 0 || year == 0) {
			return null;
		}
		LocalDateTime localDateTime = LocalDateTime.of(year + 2000, month, day, hour, min, ms / 1000);
		Date date = DateUtils.localDateTime2Date(localDateTime);
		return date;
	}

	private static String hexStr = "0123456789ABCDEF";
	private static String[] binaryArray = {
			"0000", "0001", "0010", "0011",
			"0100", "0101", "0110", "0111",
			"1000", "1001", "1010", "1011",
			"1100", "1101", "1110", "1111"
	};

	/**
	 * @param bArray
	 * @return 二进制数组转换为二进制字符串   2-2
	 */
	public static String bytes2BinStr(byte[] bArray) {
		String outStr = "";
		int pos = 0;
		for (byte b : bArray) {
			//高四位
			pos = (b & 0xF0) >> 4;
			outStr += binaryArray[pos];
			//低四位
			pos = b & 0x0F;
			outStr += binaryArray[pos];
		}
		return outStr;
	}

	/**
	 * @param bytes
	 * @return 将二进制数组转换为十六进制字符串  2-16
	 */
	public static String bin2HexStr(byte[] bytes) {
		String result = "";
		String hex = "";
		for (byte aByte : bytes) {
			//字节高4位
			hex = String.valueOf(hexStr.charAt((aByte & 0xF0) >> 4));
			//字节低4位
			hex += String.valueOf(hexStr.charAt(aByte & 0x0F));
			result += hex;  //+" "
		}
		return result;
	}

	public static void main(String[] args) {
		// byte[] a = new byte[] {0x0C, 0x00, 0x00, 0x00, 0x02, 0x20, 0x22, 0x12, 0x14, 0x00, 0x00, 0x01, 0x00};
		// byte[] bytes = intToBytes(CRC16Util.calcCrc16(a));
		// String binary = binary(bytes, 16);
		// System.out.println(binary);

		// String a = "10";
		// byte[] bytes = bigDecimal2Bcd(new BigDecimal(a));
		//
		// System.out.println(bytes);

		// byte[] startTimeByteArr = new byte[] {(byte) 0x98, (byte) 0xB7, 0x0E, 0x11, 0x10, 0x03, 0x14};
		// String binary = binary(startTimeByteArr, 16);
		// String s = DateUtils.decodeCP56Time2a(binary);
		// System.out.println(s);

		BigDecimal chargeAmount = new BigDecimal("10.5").setScale(2, BigDecimal.ROUND_HALF_UP);
		byte[] accountBalanceByteArr = BytesUtil.getFloatBytes(chargeAmount.floatValue());

		float aFloat = BytesUtil.getFloat(accountBalanceByteArr);

		System.out.println(aFloat);

	}

	/**
	 * @param hexString
	 * @return 将十六进制转换为二进制字节数组   16-2
	 */
	public static byte[] hexStr2BinArr(String hexString) {
		//hexString的长度对2取整，作为bytes的长度
		int len = hexString.length() / 2;
		byte[] bytes = new byte[len];
		byte high = 0;//字节高四位
		byte low = 0;//字节低四位
		for (int i = 0; i < len; i++) {
			//右移四位得到高位
			high = (byte) ((hexStr.indexOf(hexString.charAt(2 * i))) << 4);
			low = (byte) hexStr.indexOf(hexString.charAt(2 * i + 1));
			bytes[i] = (byte) (high | low);//高地位做或运算
		}
		return bytes;
	}

	/**
	 * @param src 16进制字符串
	 * @return 字节数组
	 * @Title hexString2Bytes
	 * @Description 16进制字符串转字节数组
	 */
	public static byte[] hexString2Bytes(String src) {
		int l = src.length() / 2;
		byte[] ret = new byte[l];
		for (int i = 0; i < l; i++) {
			ret[i] = (byte) Integer.valueOf(src.substring(i * 2, i * 2 + 2), 16).byteValue();
		}
		return ret;
	}

	/**
	 * @param hexString
	 * @return 将十六进制转换为二进制字符串   16-2
	 */
	public static String hexStr2BinStr(String hexString) {
		return bytes2BinStr(hexStr2BinArr(hexString));
	}

	/**
	 * 校验数据长度是否达到要求,如果够长，就直接返回，如果不够，则在数据 后补0 直至到达该长度
	 *
	 * @param msg byte类型数组
	 * @parm length 需要检验的数据长度（为实际字节数）
	 */
	public static byte[] checkLengthAndBehindAppendZero(byte[] msg, int length) {
		String s = BytesUtil.binary(msg, 16);
		int msgLen = msg.length;
		if (msgLen < length) {
			while (msgLen < length) {
				StringBuffer sb = new StringBuffer();
				// 后补零
				sb.append(s).append("0");
				s = sb.toString();
				msgLen = s.length();
			}
		} else {
			return msg;
		}
		return BytesUtil.str2Bcd(s);
	}

	/**
	 * 校验数据长度是否达到要求,如果够长，就直接返回，如果不够，则在数据 前补0 直至到达该长度
	 *
	 * @param msg byte类型数组
	 * @parm length 需要检验的数据长度（为实际字节数）
	 */
	public static byte[] checkLengthAndFrontAppendZero(byte[] msg, int length) {
		String s = BytesUtil.binary(msg, 16);
		int msgLen = msg.length;
		if (msgLen < length) {
			while (msgLen < length) {
				StringBuffer sb = new StringBuffer();
				// 前补零
				sb.append("0").append(s);
				s = sb.toString();
				msgLen = s.length();
			}
		} else {
			return msg;
		}
		return BytesUtil.str2Bcd(s);
	}

	/**
	 * 将金额转换成BCD数组
	 *
	 * @param bigDecimal
	 * @return
	 */
	public static byte[] bigDecimal2Bcd(BigDecimal bigDecimal) {
		int i = Float.floatToIntBits(bigDecimal.floatValue());
		String hexString = Integer.toHexString(i);
		return hexString2Bytes(hexString);

	}

	/**
	 * int 转 byte[]
	 * 小端
	 *
	 * @param data
	 * @return
	 */
	public static byte[] getIntBytes(int data) {
		int length = 4;
		byte[] bytes = new byte[length];
		for (int i = 0; i < length; i++) {
			bytes[i] = (byte) ((data >> (i * 8)) & fx);
		}
		return bytes;
	}

	/**
	 * float 转 byte[]
	 * 小端
	 *
	 * @param data
	 * @return
	 */
	public static byte[] getFloatBytes(float data) {
		int intBits = Float.floatToIntBits(data);

		byte[] bytes = getIntBytes(intBits);

		return bytes;
	}

	/**
	 * byte[] 转 int
	 *
	 * @param bytes
	 * @return
	 */
	public static int getInt(byte[] bytes) {
		int result = (int) ((fx & bytes[0])
				| ((fx & bytes[1]) << 8)
				| ((fx & bytes[2]) << 16)
				| ((fx & bytes[3]) << 24));

		return result;
	}

	/**
	 * byte[] 转 float
	 *
	 * @param b
	 * @return
	 */
	public static float getFloat(byte[] b) {
		int l = getInt(b);
		return Float.intBitsToFloat(l);
	}

	/**
	 * 将String转换为byte[]
	 *
	 * @param s String
	 * @return byte[]
	 */
	public static byte[] hexStringToByteArray(String s) {
		int len = s.length();
		byte[] data = new byte[len / 2];
		for (int i = 0; i < len; i += 2) {
			data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
		}
		return data;
	}
}
