package com.yeejoin.amos.uart.business.service.impl;

import com.yeejoin.amos.connect.dao.entity.TransmitMapper;
import com.yeejoin.amos.connect.dao.entity.UartVo;
import com.yeejoin.amos.transmit.business.dao.TransmitMapperDao;
import com.yeejoin.amos.transmit.tcp.RpcRecvListener;
import com.yeejoin.amos.transmit.tcp.TcpQueue;
import com.yeejoin.amos.transmit.tcp.TcpTransmitParam;
import com.yeejoin.amos.uart.business.dao.UartDao;
import com.yeejoin.amos.uart.business.service.intfc.UartService;
import com.yeejoin.amos.uart.rxtx.DefaultSerialDataListener;
import com.yeejoin.amos.uart.rxtx.SerialContext;
import com.yeejoin.amos.uart.rxtx.SerialUtils;
import com.yeejoin.amos.uart.rxtx.parse.HexStringSerialDataParser;
import com.yeejoin.amos.uart.rxtx.processor.SerialByteDataProcessor;
import com.yeejoin.amos.uart.rxtx.reader.AnyDataReader;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Service("uartService")
public class UartServiceImpl implements UartService {

    @Resource
    UartDao uartDao;
    @Resource
    private TransmitMapperDao transmitMapperDao;

    private static ScheduledExecutorService initUartService = null;
    private static HashSet<UartVo> notInitUart = new HashSet<UartVo>();

    public UartServiceImpl() {
        initUartService = Executors.newSingleThreadScheduledExecutor();

        initUartService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                Iterator<UartVo> iterator = notInitUart.iterator();
                while (iterator.hasNext()) {
                    UartVo uart = iterator.next();
                    List<TransmitMapper> tmList = transmitMapperDao.findAllByMapperTypeAndMapperId("UART", uart.getId());
                    SerialPort connect = null;
                    try {
                        connect = SerialUtils.connect(uart.getSerialPort(), uart.getBaudRate());
                    } catch (Exception e) {
                        e.printStackTrace();
                        continue;
                    }
                    SerialContext serialContext = SerialContext.build(connect);
                    serialContext.setSerialReader(new AnyDataReader(serialContext));
                    serialContext.getSerialDataParserSet().add(new HexStringSerialDataParser());
                    serialContext.setSerialPortEventListener(new DefaultSerialDataListener(serialContext));
                    serialContext.setSerialByteDataProcessor(new SerialByteDataProcessor() {

                        private List<TransmitMapper> uartTMList = tmList;
                        @Override
                        public void process(byte[] bytes) {
                            for (TransmitMapper tm : uartTMList) {
                                if ("TCP".equals(tm.getTransmitType())) {
                                    TcpTransmitParam p = new TcpTransmitParam();
                                    p.setIp(tm.getTransmitUrl());
                                    p.setData(bytes);
                                    TcpQueue.getInstance().addRecvData(p);
                                }
                            }
                        }
                    });
                    for (TransmitMapper tm : tmList) {
                        if ("TCP".equals(tm.getTransmitType())) {
                            TcpQueue.getInstance().register(tm.getTransmitIp(), new RpcRecvListener(){

                                @Override
                                public void recv(byte[] b) {
                                    UartVo uart = uartDao.findOne(tm.getMapperId());
                                    sendBytes("//./"+uart.getSerialPort(), b);
                                }
                            });
                        }
                    }
                    iterator.remove();
                }
            }
        }, 1, 1, TimeUnit.SECONDS);
    }

    @Override
    public void saveUart(UartVo vo) {

    }

    @Override
    public UartVo findById(Long id) {
        return null;
    }

    @Override
    public List<UartVo> findAll() {
        return uartDao.findAll();
    }

    @Override
    public void delete(Long ids) {

    }

    @Override
    public void sendData(String comPort, String message) {
        try {
            SerialContext serialContext = SerialContext.findSerialContextBySerialPort("//./"+comPort);
            if (ObjectUtils.isEmpty(serialContext)) {
                return;
            }
            serialContext.sendData(message.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void sendBytes(String serialPort, byte[] bytes) {
        try {
            SerialContext serialContext = SerialContext.findSerialContextBySerialPort("//./"+serialPort);
            if (ObjectUtils.isEmpty(serialContext)) {
                return;
            }
            serialContext.sendData(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public List<String> findAllSystemSerialPort() {
        Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();//获得所有串口

        ArrayList<String> portNameList = new ArrayList<>();
        //串口名字添加到List并返回
        while (portList.hasMoreElements()) {
            String portName = portList.nextElement().getName();
            portNameList.add(portName);
        }

        return portNameList;
    }

    @PostConstruct
    public void initSerial() {
        List<UartVo> list = findAll();

        for(UartVo uart : list) {
            List<TransmitMapper> tmList = transmitMapperDao.findAllByMapperTypeAndMapperId("UART", uart.getId());

            SerialPort connect = null;
            List<String> commNames = SerialUtils.getCommNames();
            if (!commNames.contains(uart.getSerialPort())) {
                notInitUart.add(uart);
            }
            try {
                connect = SerialUtils.connect(uart.getSerialPort(), uart.getBaudRate());
            } catch (Exception e) {
                e.printStackTrace();
                notInitUart.add(uart);
                continue;
            }
            SerialContext serialContext = SerialContext.build(connect);
            serialContext.setSerialReader(new AnyDataReader(serialContext));
            serialContext.getSerialDataParserSet().add(new HexStringSerialDataParser());
            serialContext.setSerialPortEventListener(new DefaultSerialDataListener(serialContext));
            serialContext.setSerialByteDataProcessor(new SerialByteDataProcessor() {

                private List<TransmitMapper> uartTMList = tmList;
                @Override
                public void process(byte[] bytes) {
                    for (TransmitMapper tm : uartTMList) {
                        if ("TCP".equals(tm.getTransmitType())) {
                            TcpTransmitParam p = new TcpTransmitParam();
                            p.setIp(tm.getTransmitUrl());
                            p.setData(bytes);
                            TcpQueue.getInstance().addRecvData(p);
                        }
                    }
                }
            });
            for (TransmitMapper tm : tmList) {
                if ("TCP".equals(tm.getTransmitType())) {
                    TcpQueue.getInstance().register(tm.getTransmitIp(), new RpcRecvListener(){

                        @Override
                        public void recv(byte[] b) {
                            UartVo uart = uartDao.findOne(tm.getMapperId());
                            sendBytes("//./"+uart.getSerialPort(), b);
                        }
                    });
                }
            }
        }
    }
}
