package cn.estsh.i3plus.ext.mes.pcn.apiservice.util.reader;


import org.apache.http.annotation.Contract;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.charset.Charset;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ns
 * @create 2021/11/26 0026 下午 14:23
 */
public class ReaderUtil {

    private  static  DatagramChannel channel;
    private static DatagramSocket socket;
    private ReaderUtil() {
    }

    /**
     * 初始化bind Sokcet
     */
    static {
        try {
             channel = DatagramChannel.open();
             socket = channel.socket();
            channel.configureBlocking(false);
            socket.bind(new InetSocketAddress(5057));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static class ReaderUtilHolder {
        private static final ReaderUtil INSTANCE = new ReaderUtil();
    }

    public static ReaderUtil getInstance() {
        return ReaderUtilHolder.INSTANCE;
    }

    public static boolean connecte() {

        return true;
    }

    public static void bcd2AscEx(byte asc[], byte bcd[], int len) {
        int i, j;
        int k;

        j = (len + len % 2) / 2;
        k = 3 * j;
        for (i = 0; i < j; i++) {
            asc[3 * i] = (byte) ((bcd[i] >> 4) & 0x0f);
            asc[3 * i + 1] = (byte) (bcd[i] & 0x0f);
            asc[3 * i + 2] = 0x20;
        }
        for (i = 0; i < k; i++) {
            if ((i + 1) % 3 == 0) {
                continue;
            }
            if (asc[i] > 0x09) {
                asc[i] = (byte) (0x41 + asc[i] - 0x0a);
            } else {
                asc[i] += 0x30;
            }
        }

        asc[k] = 0;

    }

    /**
     * @param hexString
     * @return
     */
    public static byte[] convert2HexArray(String hexString) {
        int len = hexString.length() / 2;
        char[] chars = hexString.toCharArray();
        String[] hexes = new String[len];
        byte[] bytes = new byte[len];
        for (int i = 0, j = 0; j < len; i = i + 2, j++) {
            hexes[j] = "" + chars[i] + chars[i + 1];
            bytes[j] = (byte) Integer.parseInt(hexes[j], 16);
        }

        return bytes;
    }

    /**
     * @param b
     * @param count convert number
     * @return
     */
    public static String bytes2HexString(byte[] b, int count) {
        String ret = "";
        for (int i = 0; i < count; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            ret += hex.toUpperCase();
        }
        return ret;
    }

    public static String bytes2HexString(byte[] b) {
        String ret = "";
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            ret += hex.toUpperCase();
        }
        return ret;
    }

    public static byte bYTE(int i) {
        return (byte) i;
    }

    /**
     * check whether the str is a hex str
     *
     * @param str  str
     * @param bits bits
     * @return true or false
     */
    public static boolean isHexString(String str, int bits) {
        String patten = "[abcdefABCDEF0123456789]{" + bits + "}";
        if (str.matches(patten)) {
            return true;
        } else {
            return false;
        }
    }

    public static boolean isHexString(String str) {
        String patten = "[abcdefABCDEF0123456789]{1,}";
        if (str.matches(patten)) {
            return true;
        } else {
            return false;
        }
    }

    public static boolean isNumber(String str) {
        String patten = "[-]{0,1}[0123456789]{0,}";
        return str.matches(patten);
    }

    /**
     * 判断请求返回是否成功
     * @param result
     * @return
     */
    public static boolean isSuccess(byte[] result){
        if(null == result || result.length == 0){
            return false;
        }
        if(result[0] != ReaderConstWords.RESPONSE_BOOT_CODE_SUCCESS){
            return false;
        }
        return true;
    }

    public static byte[] getTagsId(byte[] result){
        if(!isSuccess(result)){
            return new byte[]{};
        }
        if(result.length < 7){
            return new byte[]{};
        }
        return Arrays.copyOfRange(result,5,result.length-1);
    }

    /**
     * 获取请求结果中的标签
     * @param result
     * @return
     */
    public static byte[] getTags(byte[] result){
        if(!isSuccess(result)){
            return new byte[]{};
        }
        if(result.length < ReaderConstWords.RESPONSE_BYTE_ARRAY_MIN_LENGTH){
            return new byte[]{};
        }
        return Arrays.copyOfRange(result,3,result.length-1);
    }

    /**
     * 发送命令
     * @param requestPacketModel
     * @param ipAddress
     * @param port
     * @return
     */
    public static byte[] sendCommand(RequestPacketModel requestPacketModel, String ipAddress, Integer port) {

        Selector selector = null;
        byte[] result = new byte[]{};
        try {
//            DatagramChannel channel = DatagramChannel.open();
//            DatagramSocket socket = channel.socket();
//            channel.configureBlocking(false);
//            socket.bind(new InetSocketAddress(5057));

            selector = Selector.open();
            channel.register(selector, SelectionKey.OP_READ);
            //byte[] chTemp = new byte[] {0x40, 0x03, 0x0F, 0x00, (byte)0xAE};
            //byte[] chTemp = new byte[] {0x40, 0x02, 0x02, (byte)0xBC};
            //cb9f
            // 0 1 2 3 4 5 6 7 8 9 a b c d e f
            // 读取数据
            //  40        0c        ec       01       cb9f      03      00          01             00 00 00 00           59
            //固定长度   包有效长度   命令码   命令参数1    标签      数据区   起始地址   一个字节数据长度    accessPassword密码     Check Sum
            //读取数据
            //    byte[] chTemp = new byte[]{0x40, 0x0c, (byte) 0xec,  , (byte) 0xcb, (byte) 0x9f,0x03,0x00,0x01,0x00,0x00,0x00,0x00,0x59};

            //列出标签
            //40  06  EE  mem  addr  LEN  Mask  CheckSum
            //40  06  ee   03  00    00    00    c9
//            byte[] chTemp = new byte[]{0x40  ,0x06, (byte) 0xee,  0x03 ,0x00 ,0x00,0x00, (byte) 0xc9};
            byte[] chTemp = requestPacketModel.toByteArray();
            //chTemp[0] = 0x40;
            //chTemp[1] = 0x03;
            //chTemp[2] = 0x0F;
            //chTemp[3] = 0x00;
            //chTemp[4] = (byte)0xAE;


            ByteBuffer bb = ByteBuffer.allocate(chTemp.length);
            bb.put(chTemp);
            bb.flip();
            String[] ips = ipAddress.split("\\.");
            byte[] bs =new byte[ips.length];
            for(int i=0;i<ips.length;i++){
                int temp = Integer.parseInt(ips[i]);
                bs[i] =(byte) temp;
            }
//            byte[] bs = new byte[]{(byte) 192, (byte) 168, 31, 100};
            InetAddress address = InetAddress.getByAddress(bs);
//                        SocketAddress sa = new InetSocketAddress(address, 8080);
//            SocketAddress sa = new InetSocketAddress(address, 1969);
            SocketAddress sa = new InetSocketAddress(address, port);
            channel.send(bb, sa);


        } catch (Exception e) {
            e.printStackTrace();
        }

        ByteBuffer byteBuffer = ByteBuffer.allocate(65535);

        //while (true) {
        if (true) {
            try {
                int iRecvLen = 0;
                byte[] chTemp = new byte[4096];
                int eventsCount = selector.select(5000);
                if (eventsCount > 0) {
                    Set selectedKeys = selector.selectedKeys();
                    Iterator iterator = selectedKeys.iterator();
                    while (iterator.hasNext()) {
                        SelectionKey sk = (SelectionKey) iterator.next();
                        iterator.remove();
                        if (sk.isReadable()) {
                            DatagramChannel datagramChannel = (DatagramChannel) sk
                                    .channel();
                            byteBuffer.clear();
                            SocketAddress sa = datagramChannel.receive(byteBuffer);
                            byteBuffer.flip();

                            iRecvLen = byteBuffer.limit();
                            // 测试：通过将收到的ByteBuffer首先通过缺省的编码解码成CharBuffer 再输出
                            CharBuffer charBuffer = Charset.forName("UTF-8").decode(byteBuffer);
                            Bcd2AscEx(chTemp, byteBuffer.array(), iRecvLen * 2);
                            //System.out.println("receive message:"+ charBuffer.toString());
                            String s = new String(chTemp, "UTF-8");
                            System.out.println("receive message[" + iRecvLen + "]: " + s.trim());
//                            result = convert2HexArray(s);
                            result = convert2HexArray(StringUtils.trimAllWhitespace(s.trim()));
                            byteBuffer.clear();
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }


        System.out.println("TestOrm end!\n");
        return result;
    }


    public static void Bcd2AscEx(byte asc[], byte bcd[], int len) {
        int i, j;
        int k;

        j = (len + len % 2) / 2;
        k = 3 * j;
        for (i = 0; i < j; i++) {
            asc[3 * i] = (byte) ((bcd[i] >> 4) & 0x0f);
            asc[3 * i + 1] = (byte) (bcd[i] & 0x0f);
            asc[3 * i + 2] = 0x20;
        }
        for (i = 0; i < k; i++) {
            if ((i + 1) % 3 == 0) {
                continue;
            }
            if (asc[i] > 0x09) {
                asc[i] = (byte) (0x41 + asc[i] - 0x0a);
            } else {
                asc[i] += 0x30;
            }
        }

        asc[k] = 0;

    }

    public static void Bcd2AscEy(char asc[], char bcd[], int len) {
        int i, j;
        int k;

        j = (len + len % 2) / 2;
        k = 3 * j;
        for (i = 0; i < j; i++) {
            asc[3 * i] = (char) ((bcd[i] >> 4) & 0x0f);
            asc[3 * i + 1] = (char) (bcd[i] & 0x0f);
            asc[3 * i + 2] = 0x20;
        }
        for (i = 0; i < k; i++) {
            if ((i + 1) % 3 == 0) {
                continue;
            }
            if (asc[i] > 0x09) {
                asc[i] = (char) (0x41 + asc[i] - 0x0a);
            } else {
                asc[i] += 0x30;
            }
        }

        asc[k] = 0;

    }

    public static byte checkSum(byte[] bytes) {
        byte result = 0;
        if (null == bytes || bytes.length == 0) {
            return result;
        }

        for (int i = 0; i < bytes.length; i++) {
            result += bytes[i];
        }
        result = (byte) (~result + 1);
        return result;
    }
}
