package org.ts.ddcs.tool;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.security.MessageDigest;
import java.util.Calendar;

public class BytesUtil {

    /**
     * bcd码转int
     *
     * @param bs  cbcd16进制数组
     * @param off 起始位置
     * @param len 长度
     * @return int
     */
    public static int cbcd2int(byte[] bs, int off, int len) {
        int v = 0;
        for (int i = off; i < (off + len); i++) {
            v = (v * 100) + (((bs[i] & 0xFF) >> 4) * 10) + (bs[i] & 0x0F);
        }
        return v;
    }

    /**
     * 字节数组转成二进制字符串
     */
    public static String bytesToBinStr(byte[] bytes) {
        String binStr = "";
        if (null != bytes && bytes.length > 0) {
            for (int i = 0; i < bytes.length; i++) {
                byte b = bytes[i];
                String tmpStr = Integer.toBinaryString((b & 0xFF) + 0x100).substring(1);
                binStr += tmpStr;
            }
        }
        return binStr;
    }


    /**
     * 字节数组转成二进制字符串,反转字节
     */
    public static String bytesToBinStr2(byte[] bytes) {
        String binStr = "";
        if (null != bytes && bytes.length > 0) {
            for (int i = bytes.length; i > 0; i--) {
                byte b = bytes[i - 1];
                String tmpStr = Integer.toBinaryString((b & 0xFF) + 0x100).substring(1);
                binStr += tmpStr;
            }
        }
        return binStr;
    }

    /**
     * 二进制字符串转成字节数组
     */
    public static byte[] binStrToBytes(String binStr) {
        byte[] b = new byte[binStr.length() / 8];
        for (int i = 0; i < b.length; i++) {
            String bin = binStr.substring(i * 8, i * 8 + 8);
            b[i] = Integer.valueOf(bin, 2).byteValue();
        }
        return b;
    }

    /**
     * int转bcd码
     *
     * @param i   int数值
     * @param len (bcd长度)
     * @return byte[] cbcd16进制数组
     */
    public static byte[] int2cbcd(int i, int len) {
        byte[] bs = new byte[len];
        int temp;
        for (int j = len - 1; j >= 0; j--) {
            temp = i % 100;
            bs[j] = (byte) (((temp / 10) << 4) + ((temp % 10) & 0x0F));
            i /= 100;
        }
        return bs;
    }

    /**
     * 数值类型转byte数组(long(8),int(4),short(2))
     *
     * @param num (long,int,short)
     * @param len (8, 4, 2)
     * @return
     */
    public static byte[] number2bytes(long num, int len) {
        byte[] bs = new byte[len];
        for (int j = 0; j < len; j++) {
            bs[len - j - 1] = (byte) (num >> (j * 8));
        }
        return bs;
    }

    /**
     * byte数组转short
     *
     * @param bs
     * @return
     */
    public static short bytes2short(byte[] bs) {
        short s = (short) (bs[1] & 0xFF);
        s |= (bs[0] << 8) & 0xFF00;
        return s;
    }

    /**
     * short转byte数组
     *
     * @param s
     * @return
     */
    public static byte[] short2bytes(short s) {
        byte[] bs = new byte[2];
        for (int i = 1; i >= 0; i--) {
            bs[i] = (byte) (s % 256);
            s >>= 8;
        }
        return bs;
    }

    /**
     * String转bcd byte数组
     *
     * @param s
     * @return
     */
    public static byte[] string2cbcd(String s) {
        if (s.length() % 2 != 0) {
            s = "0" + s;
        }
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        char[] cs = s.toCharArray();
        for (int i = 0; i < cs.length; i += 2) {
            int high = cs[i] - 48;
            int low = cs[i + 1] - 48;
            baos.write(high << 4 | low);
        }
        return baos.toByteArray();
    }

    /**
     * 转数据为字符串
     *
     * @param bs
     * @param off
     * @param len
     * @return
     */
    public static String getHexString(byte[] bs, int off, int len) {
        StringBuffer sb = new StringBuffer();
        for (int i = off; i < (off + len); i++) {
            String hex = Integer.toHexString(bs[i] & 0xFF);
            if (hex.length() == 1) {
                sb.append('0').append(hex);
            } else {
                sb.append(hex);
            }
            // sb.append(' ');
        }
        return sb.toString();
    }

    /**
     * byte数组转String
     *
     * @param bs
     * @param off
     * @param len
     * @return
     */
    public static String bytes2String(byte[] bs, int off, int len) {
        return new String(bs, off, len).trim();
    }

    /**
     * String 转 byte[]
     *
     * @param str
     * @param len
     * @return
     */
    public static byte[] string2bytes(String str, int len) {
        byte[] bs;
        if (str != null) {
            bs = str.getBytes();
        } else {
            bs = new byte[len];
        }
        return bs;
    }

    /**
     * int 转 byte数组
     *
     * @param i
     * @return
     */
    public static byte[] int2Bytes(int i) {
        return int2Bytes(i, 4);
    }

    /**
     * int 转 byte数组
     *
     * @param i
     * @return
     */
    public static byte[] intToBytes(int i, int length) {
        return int2Bytes(i, length);
    }

    /**
     * int 转 byte数组
     *
     * @param i
     * @param len
     * @return
     */
    public static byte[] int2Bytes(int i, int len) {
        byte[] bs = new byte[len];
        for (int j = 0; j < len; j++) {
            bs[len - j - 1] = (byte) (i >> (j * 8));
        }
        return bs;
    }


    public static int byteslowbitToInt(byte[] bytes, int off) {

        byte[] tmpbuf = new byte[4];
        tmpbuf[2] = (byte) (bytes[off] & 0x0f);
        tmpbuf[3] = bytes[off + 1];
        int v = 0;
        for (int ii = 0; ii < 4; ii++) {
            int shi = (4 - 1 - ii) * 8;
            v += (tmpbuf[ii] & 0x000000FF) << shi;
        }
        return v;
    }

    /**
     * byte数组转int(命令字专用)
     *
     * @param bytes
     * @return
     */
    public static int bytes2Int(byte[] bytes, int off, int len) {
        int v = 0;
        int pos = off + len - 1;
        if (pos >= 0) {
            v |= (bytes[pos] & 0xFF);
        }
        pos--;
        if (pos >= 0) {
            v |= ((bytes[pos] << 8) & 0xFF00);
        }
        pos--;
        if (pos >= 0) {
            v |= ((bytes[pos] << 16) & 0xFF0000);
        }
        pos--;
        if (pos >= 0) {
            v |= ((bytes[pos] << 24) & 0xFF000000);
        }
        return v;
    }

    // bytes补位用
    public static byte[] string2Bytes(String src, int len, int max) {
        byte[] dest = new byte[max];

        if (src == null) {
            return dest;
        }
        while (src.length() < len) {
            src += " ";
        }
        byte[] temp = src.getBytes();

        System.arraycopy(temp, 0, dest, 0, temp.length >= len ? len
                : temp.length);

        return dest;
    }

    public static byte[] getBytesFromFile(File file) {
        byte[] ret = null;
        try {
            if (file == null) {
                return null;
            }
            FileInputStream in = new FileInputStream(file);
            ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
            byte[] b = new byte[4096];
            int n;
            while ((n = in.read(b)) != -1) {
                out.write(b, 0, n);
            }
            in.close();
            out.close();
            ret = out.toByteArray();
        } catch (Exception e) {
            return null;
        }
        return ret;
    }

    public static String getMD5Digest(String str) {
        return getMD5Digest(str.getBytes());
    }

    public static String getMD5Digest(byte[] bytes) {
        MessageDigest messageDigest = null;
        try {
            messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.reset();
            messageDigest.update(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }

        byte[] byteArray = messageDigest.digest();
        StringBuffer md5StrBuff = new StringBuffer();

        for (int i = 0; i < byteArray.length; i++) {
            if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)
                md5StrBuff.append("0").append(
                        Integer.toHexString(0xFF & byteArray[i]));
            else
                md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
        }

        return md5StrBuff.toString();
    }

    public static String leftFill(String src, int len, char fillChar) {

        int length = src.length();
        if (src == null || len < length)
            return src;

        String result = src;
        for (int i = length; i < len; i++) {
            result = String.valueOf(fillChar) + result;
        }

        return result;
    }

    /**
     * 将字符串拼接成指定长度的字符串,不足的补空格
     *
     * @param str    字符串
     * @param length
     * @return
     */
    public static String spliceSpaces(String str, int length) {
        int strLen = str.length();
        if (strLen > length) {
            str = "";
            for (int i = 0; i < length; i++) {
                str += " ";
            }
        } else {
            for (int i = 0; i < (length - strLen); i++) {
                str += " ";
            }
        }
        return str;
    }

    /**
     * 将字符串拼接成指定长度的字符串,不足的补0
     *
     * @param str    字符串
     * @param length
     * @return
     */
    public static String spliceZero(String str, int length) {
        int strLen = str.length();
        if (strLen > length) {
            str = "";
            for (int i = 0; i < length; i++) {
                str += "0";
            }
        } else {
            for (int i = 0; i < (length - strLen); i++) {
                str = "0" + str;
            }
        }
        return str;
    }

    public static byte[] arrayApend(byte[] a, byte[] b) {
        int a_len = (a == null ? 0 : a.length);
        int b_len = (b == null ? 0 : b.length);
        byte[] c = new byte[a_len + b_len];
        if (a_len == 0 && b_len == 0) {
            return null;
        } else if (a_len == 0) {
            System.arraycopy(b, 0, c, 0, b.length);
        } else if (b_len == 0) {
            System.arraycopy(a, 0, c, 0, a.length);
        } else {
            System.arraycopy(a, 0, c, 0, a.length);
            System.arraycopy(b, 0, c, a.length, b.length);
        }
        return c;
    }


    public static byte[] arrayApendbyte(byte[] a, byte b) {
        int a_len = (a == null ? 0 : a.length);

        byte[] c = new byte[a_len + 1];
        if (a_len == 0) {
            return null;
        } else {
            System.arraycopy(a, 0, c, 0, a.length);
            System.arraycopy(b, 0, c, a.length, 1);
        }
        return c;
    }


    /**
     * 获取字符Ascii值
     *
     * @param str
     * @return
     */
    public static int getAsciiValue(String str) {
        if (str.length() != 1) {
            return 0;
        }
        char[] ch = str.toCharArray();

        return ch[0];
    }

    /**
     * 获取字符Ascii值 16
     *
     * @param str
     * @return
     */
    public static String getAsciiHexValueS(String str) {
        char[] ch = str.toCharArray();
        StringBuffer retStr = new StringBuffer();
        for (int i = 0; i < ch.length; i++) {
            retStr.append(Integer.toHexString(ch[i]));
        }
        return retStr.toString();
    }

    /**
     * 获取字符Ascii值
     *
     * @param str
     * @return
     */
    public static String getAsciiValueS(String str) {
        char[] ch = str.toCharArray();
        StringBuffer retStr = new StringBuffer();
        for (int i = 0; i < ch.length; i++) {
            retStr.append((int) ch[i]);
        }
        return retStr.toString();
    }

    public static String getAsciiStr(int d) {
        char e = (char) d;
        return e + "";
    }


    public static String byte2HexStr(byte[] b) {
        String stmp = "";
        StringBuilder sb = new StringBuilder("");
        for (int n = 0; n < b.length; n++) {
            stmp = Integer.toHexString(b[n] & 0xFF);
            sb.append((stmp.length() == 1) ? "0" + stmp : stmp);
            //sb.append(" ");
        }
        return sb.toString().toUpperCase().trim();
    }

    public static String byte2HexStr(byte[] b, int pos, int length) {
        String stmp = "";
        StringBuilder sb = new StringBuilder("");
        for (int n = 0; n < length; n++) {
            stmp = Integer.toHexString(b[n + pos] & 0xFF);
            sb.append((stmp.length() == 1) ? "0" + stmp : stmp);
        }
        return sb.toString().toUpperCase().trim();
    }

    public static byte[] hexStr2Bytes(String hexString) {
        hexString = hexString.toLowerCase();
        int remainder = hexString.length() % 2;
        if (remainder > 0) {
            hexString = "0" + hexString;
        }
        final byte[] byteArray = new byte[hexString.length() / 2];
        int k = 0;
        for (int i = 0; i < byteArray.length; i++) {
            //因为是16进制，最多只会占用4位，转换成字节需要两个16进制的字符，高位在先
            //将hex 转换成byte   "&" 操作为了防止负数的自动扩展
            // hex转换成byte 其实只占用了4位，然后把高位进行右移四位
            // 然后“|”操作  低四位 就能得到 两个 16进制数转换成一个byte.
            //
            byte high = (byte) (Character.digit(hexString.charAt(k), 16) & 0xff);
            byte low = (byte) (Character.digit(hexString.charAt(k + 1), 16) & 0xff);
            byteArray[i] = (byte) (high << 4 | low);
            k += 2;
        }
        return byteArray;
    }

    public static byte[] subBytes(byte[] src, int begin, int count) {
        byte[] bs = new byte[count];
        for (int i = begin; i < begin + count; i++) bs[i - begin] = src[i];
        return bs;
    }

    //CRC校验运算
    public static byte GetCRCByte(byte[] data) {
        int crc = 0x0; // 初始值为0
        for (byte bt : data) {
            crc = crc ^ bt;
            for (int j = 1; j <= 8; j++) {
                if ((crc & 0x80) == 0x80)
                    crc = (crc << 1) ^ 0xE5;// 多项式值为E5,被校验值左移
                else
                    crc = crc << 1;
            }
        }
        return (byte) crc;
    }

    //将16进制字符串转换为16进制byte数组
    public static byte[] HexString2Bytes(String src) {
        byte[] ret = new byte[8];
        byte[] tmp = src.getBytes();
        for (int i = 0; i < 8; i++) {
            ret[i] = uniteBytes(tmp[i * 2], tmp[i * 2 + 1]);
        }
        return ret;
    }

    public static byte uniteBytes(byte src0, byte src1) {
        byte _b0 = Byte.decode("0x" + new String(new byte[]{src0})).byteValue();
        _b0 = (byte) (_b0 << 4);
        byte _b1 = Byte.decode("0x" + new String(new byte[]{src1})).byteValue();
        byte ret = (byte) (_b0 ^ _b1);
        return ret;
    }


    //16进制字符串转换为2进制字符串
    public static String hexString2binaryString(String hexString) {
        if (hexString == null || hexString.length() % 2 != 0)
            return null;
        String bString = "", tmp;
        for (int i = 0; i < hexString.length(); i++) {
            tmp = "0000"
                    + Integer.toBinaryString(Integer.parseInt(
                    hexString.substring(i, i + 1), 16));
            bString += tmp.substring(tmp.length() - 4);
        }
        return bString;
    }

    /**
     * 获取时间戳位
     *
     * @return
     */
    public static byte[] getTPByte() {


        Calendar now = Calendar.getInstance();
        //String year = now.get(Calendar.YEAR)+"";
        String second = now.get(Calendar.SECOND) + "";
        String minute = now.get(Calendar.MINUTE) + "";
        String hour = now.get(Calendar.HOUR_OF_DAY) + "";
        String day = now.get(Calendar.DATE) + "";
        byte[] tpArea;

        if (second.length() == 1) {
            tpArea = BytesUtil.hexStr2Bytes("0" + second);
        } else {
            tpArea = BytesUtil.hexStr2Bytes(second);
        }

        if (minute.length() == 1) {
            tpArea = BytesUtil.arrayApend(tpArea,
                    BytesUtil.hexStr2Bytes("0" + minute));
        } else {
            tpArea = BytesUtil.arrayApend(tpArea,
                    BytesUtil.hexStr2Bytes(minute));
        }
        if (hour.length() == 1) {
            tpArea = BytesUtil.arrayApend(tpArea,
                    BytesUtil.hexStr2Bytes("0" + hour));
        } else {
            tpArea = BytesUtil.arrayApend(tpArea,
                    BytesUtil.hexStr2Bytes(hour));
        }
        if (day.length() == 1) {
            tpArea = BytesUtil.arrayApend(tpArea,
                    BytesUtil.hexStr2Bytes("0" + day));
        } else {
            tpArea = BytesUtil.arrayApend(tpArea,
                    BytesUtil.hexStr2Bytes(day));
        }

        tpArea = BytesUtil.arrayApend(tpArea,
                BytesUtil.hexStr2Bytes("00"));

        return tpArea;

    }


    /**
     * 单一字节中选择指定位bcd码转换为整数
     *
     * @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;
        return b2;
    }

    public static byte[] crcFun2014(byte[] packet, int pos, int length) {
        int n = length;
        int crc = 0xFFFF;
        for (int b = 0; b < n; b++) {
            crc = byteToInteger(packet[pos + b]) ^ crc;
            for (int c = 0; c < 8; c++) {
                int dd = crc & 0x0001;
                if (dd == 1) {
                    crc = crc >> 1;
                    crc ^= 0xA001;
                } else {
                    crc = crc >> 1;
                }
            }
        }
        return BytesUtil.int2Bytes(crc, 2);
    }

    public static byte[] crcFun2014(byte[] packet) {
        int n = packet.length;
        int crc = 0xFFFF;
        for (int b = 0; b < n; b++) {
            crc = byteToInteger(packet[b]) ^ crc;
            for (int c = 0; c < 8; c++) {
                int dd = crc & 0x0001;
                if (dd == 1) {
                    crc = crc >> 1;
                    crc ^= 0xA001;
                } else {
                    crc = crc >> 1;
                }
            }
        }
        return BytesUtil.int2Bytes(crc, 2);
    }

    public static int byteToInteger(byte b) {
        int value;
        value = b & 0xff;
        return value;
    }


    /**
     * 获取发报时间
     *
     * @return
     */
    public static byte[] getFBTm() {
        Calendar now = Calendar.getInstance();
        String year = now.get(Calendar.YEAR) + "";
        String month = now.get(Calendar.MONTH) + 1 + "";
        String day = now.get(Calendar.DATE) + "";
        String hour = now.get(Calendar.HOUR_OF_DAY) + "";
        String minute = now.get(Calendar.MINUTE) + "";
        String second = now.get(Calendar.SECOND) + "";
        byte[] tpArea;
        tpArea = BytesUtil.hexStr2Bytes(year.substring(2, year.length()));
        if (month.length() == 1) {
            tpArea = BytesUtil.arrayApend(tpArea,
                    BytesUtil.hexStr2Bytes("0" + month));
        } else {
            tpArea = BytesUtil.arrayApend(tpArea,
                    BytesUtil.hexStr2Bytes(month));
        }
        if (day.length() == 1) {
            tpArea = BytesUtil.arrayApend(tpArea,
                    BytesUtil.hexStr2Bytes("0" + day));
        } else {
            tpArea = BytesUtil.arrayApend(tpArea,
                    BytesUtil.hexStr2Bytes(day));
        }
        if (hour.length() == 1) {
            tpArea = BytesUtil.arrayApend(tpArea,
                    BytesUtil.hexStr2Bytes("0" + hour));
        } else {
            tpArea = BytesUtil.arrayApend(tpArea,
                    BytesUtil.hexStr2Bytes(hour));
        }
        if (minute.length() == 1) {
            tpArea = BytesUtil.arrayApend(tpArea,
                    BytesUtil.hexStr2Bytes("0" + minute));
        } else {
            tpArea = BytesUtil.arrayApend(tpArea,
                    BytesUtil.hexStr2Bytes(minute));
        }
        if (second.length() == 1) {
            tpArea = BytesUtil.arrayApend(tpArea, BytesUtil.hexStr2Bytes("0" + second));
        } else {
            tpArea = BytesUtil.arrayApend(tpArea, BytesUtil.hexStr2Bytes(second));
        }
        return tpArea;
    }


    //将16进制RTU编码改成10进制
    public static String byte2HexMpCdStr(byte[] b) {
        String stmp = "";
        StringBuilder sb = new StringBuilder("");
        for (int n = 0; n < 3; n++) {
            stmp = Integer.toHexString(b[n] & 0xFF);
            sb.append((stmp.length() == 1) ? "0" + stmp : stmp);
        }

        int mpcd = 0;
        if (sb.toString().startsWith("00")) {//00开头的站点编号按照10进制处理，99的按照16进制处理,为了满足威控的编码格式
            String str4 = Integer.toHexString(b[4] & 0xFF);
            String mpcdStr = Integer.toHexString(b[3] & 0xFF);
            if (str4.length() == 1) {
                mpcdStr += "0" + str4;
            } else {
                mpcdStr += str4;
            }
            //String mpcdStr = Integer.toHexString(b[3] & 0xFF)+Integer.toHexString(b[4] & 0xFF);
            mpcd = Integer.parseInt(mpcdStr);
        } else {
            mpcd = bytes2Int(BytesUtil.subBytes(b, 3, 2), 0, 2) % 10000;
        }
        sb.append(StringUtil.leftFill(mpcd + "", 4, '0'));
        return sb.toString().toUpperCase().trim();
    }


    //将16进制RTU编码改成10进制（东深厂商专用），编号最后俩个字节颠倒
    public static String byte2HexMpCdStrDS(byte[] b) {
        String stmp = "";
        StringBuilder sb = new StringBuilder("");
        for (int n = 0; n < 3; n++) {
            stmp = Integer.toHexString(b[n] & 0xFF);
            sb.append((stmp.length() == 1) ? "0" + stmp : stmp);
        }

        int mpcd = 0;
        if (sb.toString().startsWith("00")) {//00开头的站点编号按照10进制处理，99的按照16进制处理,为了满足威控的编码格式
            String mpcdStr = Integer.toHexString(b[3] & 0xFF) + Integer.toHexString(b[4] & 0xFF);
            mpcd = Integer.parseInt(mpcdStr);
        } else {
            byte[] mpCdTail = new byte[2];
            mpCdTail[0] = b[4];
            mpCdTail[1] = b[3];
            //mpcd =  bytes2Int( BytesUtil.subBytes(b, 3, 2),0,2) %10000;
            mpcd = bytes2Int(mpCdTail, 0, 2) % 10000;
        }
        sb.append(StringUtil.leftFill(mpcd + "", 4, '0'));
        return sb.toString().toUpperCase().trim();
    }

    //bdcd十六进字符串转成字节数组
    public static byte[] hstrToBytes(String str) {
        char[] ca = str.toCharArray();
        byte[] databuff = new byte[ca.length / 2];
        for (int j = 0; j < ca.length; j += 2) {

            byte bb = (byte) (charToByte(ca[j]) << 4 | charToByte(ca[j + 1]));
            databuff[j == 0 ? 0 : (j / 2)] = bb;
        }
        return databuff;
    }

    public static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

}
