package client;

import com.alibaba.fastjson.JSON;
import com.fazecast.jSerialComm.SerialPort;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import server.TcpServer;

import java.io.IOException;
import java.util.Date;

/**
 * @author yuli
 * @ClassName TcpClientHandler
 **/
public class TcpClientHandler extends SimpleChannelInboundHandler<Object> {

    public static  String serverUrl;

    private static Logger logger = LoggerFactory.getLogger(TcpClientHandler.class);

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("client receive msg from server:" + msg);
                String writeData = msg.toString();  //要发送的字符串
        byte[] bytes = writeData.getBytes();//将字符串转换为字节数组
        int flag = writeComm(serialPort, bytes);
        if(-2 == flag){
            openComm();
        }
        Thread.sleep(200);//休眠0.02秒，等待下位机传送数据到串口。如果不休眠，直接再次使用port.bytesAvailable()函数会因为下位机还没有返回数据而返回-1，并跳出循环导致数据没读完。休眠时间可以自行调试，时间越长，单次读取到的数据越多。
        String result =  readComm(serialPort);
        if(null  == result){
            openComm();
        }
        logger.info("**COM口读出数据<<start:" + result  +">>end");
        sendGnss(result);
    }

    private void sendGnss(String msg) {
        try {
            if(null == msg || "".equals(msg)){
                logger.info("COM口未读出数据");
                return;
            }
            String[] gnss = msg.split("\\r\\n");
            logger.info("gnss[0]" + gnss[0]);
            logger.info("gnss[1]" + gnss[1]);
            SimplePoint simplePoint = new SimplePoint();
            GpsDto gpsDto = new GpsDto();
            for(int i = 0; i < gnss.length; i++ ){
                if("$".equals(gnss[i].substring(0,1)) && gnss[i].contains("GGA")){   //GNSS 定位信息
                    String[] gga = gnss[i].split(",");
                    logger.info("gga" + gga.toString());
                    if(gga.length == 15){
                        if("".equals(gga[2])){
                            return;
                        }
                        double y =  Double.parseDouble(gga[2].substring(0,2)) + Double.parseDouble(gga[2].substring(2,gga[2].length() -2)) / 60d ;
                        double x = Double.parseDouble(gga[4].substring(0, 3)) + Double.parseDouble(gga[4].substring(3, gga[4].length() - 3)) / 60d;
                        double elevation = Double.parseDouble(gga[9]) + Double.parseDouble(gga[11]);
                        logger.info( "接收当前的经度" + x + "纬度" + y + "海拔" + elevation);

                        simplePoint.setX(x);
                        simplePoint.setY(y);
                        gpsDto.setName(TcpServer.deviceId);
                        gpsDto.setTime(new Date());
                        gpsDto.setLocation(simplePoint);

                    }
                }else if("$".equals(gnss[i].substring(0,1)) && gnss[i].contains("VTG")){  //地面速度信息
                    String[] vtg = gnss[i].split(",");
                    if(vtg.length == 10){
                        if("".equals(vtg[5])){
                            return;
                        }
                        double sulv0 = Double.parseDouble(vtg[5].toString());
                        double sulv1 =  Double.parseDouble(vtg[7].toString());
                        gpsDto.setGndRate(sulv1);
                        logger.info( "接收当前的地面速率" + sulv0 + "节" + sulv1 + "km/h");
                    }
                }
            }
            String jsonObject = JSON.toJSONString(gpsDto);
            String result =  post(serverUrl,jsonObject);
            logger.info(result);
        } catch (IOException e) {
            e.printStackTrace();
            logger.error(e.getMessage());
        }
    }

    private OkHttpClient client = new OkHttpClient();

    String post(String url, String json) throws IOException {

        RequestBody body = RequestBody.create(json, MediaType.get("application/json; charset=utf-8"));
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();
        try (Response response = client.newCall(request).execute()) {
            return response.body().string();
        }
    }

    private static SerialPort serialPort;

    public static SerialPort openComm() {
        SerialPort[] serialPorts = SerialPort.getCommPorts();//查找所有串口
        for(SerialPort port:serialPorts){
            System.out.println("PortName:"+port.getSystemPortName());//打印串口名称，如COM4
            System.out.println("PortDesc:"+port.getPortDescription());//打印串口类型，如USB Serial
            System.out.println("PortDescriptivePortName:"+port.getDescriptivePortName());//打印串口的完整类型，如USB-SERIAL CH340(COM4)
            if(port.getSystemPortName().equalsIgnoreCase("COM1")){
                serialPort = port;
            }
        }
        serialPort.setBaudRate(115200);//设置波特率为112500
        serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING | SerialPort.TIMEOUT_WRITE_BLOCKING, 1000, 1000);//设置超时
        serialPort.setRTS();//设置RTS。也可以设置DTR
        serialPort.setFlowControl(SerialPort.FLOW_CONTROL_DISABLED);//设置串口的控制流，可以设置为disabled，或者CTS, RTS/CTS, DSR, DTR/DSR, Xon, Xoff, Xon/Xoff等
        serialPort.setComPortParameters(115200, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY);//一次性设置所有的串口参数，第一个参数为波特率，默认9600；第二个参数为每一位的大小，默认8，可以输入5到8之间的值；第三个参数为停止位大小，只接受内置常量，可以选择(ONE_STOP_BIT, ONE_POINT_FIVE_STOP_BITS, TWO_STOP_BITS)；第四位为校验位，同样只接受内置常量，可以选择 NO_PARITY, EVEN_PARITY, ODD_PARITY, MARK_PARITY,SPACE_PARITY。
        if(!serialPort.isOpen()){
            boolean isCommOpeded = serialPort.openPort();//判断串口是否打开，如果没打开，就打开串口。打开串口的函数会返回一个boolean值，用于表明串口是否成功打开了
            logger.info("COM口是否打开: "+ isCommOpeded);
        }
//        serialPort.closePort();//关闭串口。该函数同样会返回一个boolean值，表明串口是否成功关闭
        return serialPort;
    }

    public static void closeComm(){
        if(null != serialPort)
            serialPort.closePort();
    }
    private int writeComm(SerialPort serialPort, byte[] data) throws InterruptedException {
//        if(serialPort == null || !serialPort.isOpen()){
//            logger.info("COM口未打开");
//          return -2;
//        }
        int result =  serialPort.writeBytes(data,data.length);//将字节数组全部写入串口
        if(result != -1){
            logger.info("COM口已成功写入数据");
        }else{
            logger.error("COM口写数据失败");
        }
        return result;
    }

    private String readComm(SerialPort serialPort) {
//        if (serialPort == null || !serialPort.isOpen()) {
//            logger.error("COM口未打开");
//            return null;
//        }
        String readData = "";
        while(serialPort.bytesAvailable()>0){ //循环读取所有的返回数据。如果可读取数据长度为0或-1，则停止读取
            byte[] newData = new byte[serialPort.bytesAvailable()];//创建一个字节数组，长度为可读取的字节长度
            int numRead = serialPort.readBytes(newData, newData.length);//将串口中可读取的数据读入字节数组，返回值为本次读取到的字节长度
            String newDataString = new String(newData);//将新数据转为字符串
            readData = readData + newDataString;//组合字符串
        }
        return readData;
    }
}
