package com.yeejoin.amos.uart.rxtx;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.RXTXVersion;
import gnu.io.SerialPort;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;


public class SerialUtils {

    /**
     * 添加串口GUN.IO动态库
     */
    public static void initJavaLibraryPath() {
        String os = OSUtil.getOsName().split(" ")[0];
        String arch = OSUtil.getArch();

        Resource resource = new ClassPathResource("lib");
        try {
            String path = resource.getFile().getPath();
            path = path + File.separator +  os + File.separator;
            if (os.contains("Linux") && arch.contains("86")) {
                path += "i686-unknown-linux-gnu";
            } else if (os.contains("Linux") && arch.contains("64")) {
                path += "x86_64-unknown-linux-gnu";
            }
            System.out.println(path);
            addLibraryDir(path);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void addLibraryDir(String libraryPath) throws IOException {
        try {
            Field field = ClassLoader.class.getDeclaredField("usr_paths");
            field.setAccessible(true);
            String[] paths = (String[]) field.get(null);
            for (int i = 0; i < paths.length; i++) {
                if (libraryPath.equals(paths[i])) {
                    return;
                }
            }

            String[] tmp = new String[paths.length + 1];
            System.arraycopy(paths, 0, tmp, 0, paths.length);
            tmp[paths.length] = libraryPath;
            field.set(null, tmp);
        } catch (IllegalAccessException e) {
            throw new IOException(
                    "Failedto get permissions to set library path");
        } catch (NoSuchFieldException e) {
            throw new IOException(
                    "Failedto get field handle to set library path");
        }
    }

    /**
     * get all port list
     *
     * @return port list
     */
    public static ArrayList<String> getCommNames() {
        @SuppressWarnings("portIdentifiers")
        Enumeration<CommPortIdentifier> portIdentifiers = CommPortIdentifier.getPortIdentifiers();
        ArrayList<String> list = new ArrayList<String>();
        while (portIdentifiers.hasMoreElements()) {
            list.add(portIdentifiers.nextElement().getName());
        }
        return list.isEmpty() ? null : list;
    }



    /**
     * connect SerialPort
     *
     *  start --- data --- parity --- stop
     *    1      5~9       0-1        1-2
     * @param portName portName com口
     * @param baudRate baudRate 波特率
     * @param dataBits dataBits 数据占用位数
     * @param stopBits stopBits 停止位
     * @param parity   parity 奇偶校验位
     * @return SerialPort
     * @throws Exception SerialPort connect err
     */
    public static SerialPort connect(String portName, int baudRate, int dataBits, int stopBits, int parity) throws Exception {

        System.out.println(portName + "  " + baudRate + " " + dataBits + " " + stopBits + " " + parity);
        CommPortIdentifier portIdentifier = null;
        portIdentifier = CommPortIdentifier.getPortIdentifier(portName);

        if (portIdentifier.isCurrentlyOwned()) {
            System.err.println("Error: Port is currently in use");
        } else {
            CommPort commPort = portIdentifier.open(SerialUtils.class.getName(), 2000);

            if (commPort instanceof SerialPort) {
                SerialPort serialPort = (SerialPort) commPort;
                serialPort.setOutputBufferSize(40960);
                serialPort.setInputBufferSize(40960);
                serialPort.setSerialPortParams(baudRate, dataBits, stopBits, parity);
                return (SerialPort) commPort;
            } else {
                System.err.println("Error: Only serial ports are handled by this example.");
            }
        }
        return null;
    }


    /**
     * connect SerialPort
     *
     * @param portName port name
     * @param baudRate baudRate
     * @return SerialPort
     * @throws Exception SerialPort connect err
     */
    public static SerialPort connect(String portName, int baudRate) throws Exception {
        CommPortIdentifier portIdentifier = null;

        portIdentifier = CommPortIdentifier.getPortIdentifier(portName);

        if (portIdentifier.isCurrentlyOwned()) {
            System.err.println("Error: Port is currently in use");
        } else {
            CommPort commPort = portIdentifier.open(SerialUtils.class.getName(), 2000);
            CommPortIdentifier.getPortIdentifiers();
            if (commPort instanceof SerialPort) {
                SerialPort serialPort = (SerialPort) commPort;
                serialPort.setOutputBufferSize(40960);
                serialPort.setInputBufferSize(40960);
                serialPort.setSerialPortParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
                return (SerialPort) commPort;
            } else {
                System.err.println("Error: Only serial ports are handled by this example.");
            }
        }
        return null;
    }



}
