package kr.gmtc.gw.asderecv.controller;

import kr.gmt.so.state.StateManager;
import kr.gmt.so.state.callback.IState;
import kr.gmtc.gw.asderecv.asde.parser.AsterixParserThread;
import kr.gmtc.gw.asderecv.rest.ServiceQueManager;
import kr.gmtc.gw.asderecv.rest.vo.ServiceAsdeData;
import kr.gmtc.gw.asderecv.utils.CmmnUtil;
import kr.gmtc.gw.comp.socket.udp.UDPEventListener;
import kr.gmtc.gw.comp.socket.udp.UDPManager;
import kr.gmtc.gw.comp.socket.utils.SocketUtil;
import kr.gmtc.gw.comp.socket.vo.MsgObjVO;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Queue;

import javax.annotation.Resource;

@Component("controller")
public class MainController implements ApplicationListener<ContextClosedEvent>{

    Queue<String> packetQ;
    HashMap<Integer, Queue<ServiceAsdeData>> serviceQueue;

    @Value("${root}") 
    String path;

    @Value("${asde.service.queueCount}")
    private Integer scvQcount;

    @Value("${asde.service.clearQ.maxCount}")
    private Integer scvQmaxCount;

    @Value("${asde.service.clearQ.diffTime}")
    private Integer scvQdiffTime;

    @Value("${asde.service.clearQ.clearTime}")
    private Integer scvQclearTime;

    @Value("${dev.debug.debugLogMode}")
    private String debugLogMode = "none";

    @Resource(name = "serviceRunnig")
    private boolean serviceRunnig = false;

    protected UDPManager udpManager;
    private UDPEventListener udpListener;

    private AsterixParserThread asterixParserThread;

    private ServiceQueManager serviceQueManager;

    protected Logger logger;

    @Autowired
    private StateManager stateMgr;

    protected MainController(Queue<String> packetQ, HashMap<Integer, Queue<ServiceAsdeData>> serviceQueue){

        this.packetQ = packetQ;
        this.serviceQueue = serviceQueue;
        
        logger = LoggerFactory.getLogger(this.getClass());
    }

    @Order(0)
    @EventListener(ApplicationReadyEvent.class)
    public void initialize() {

        udpListener = createUDPEventListener();
        udpManager  = new UDPManager(path, udpListener);

        asterixParserThread = new AsterixParserThread(packetQ, serviceQueue);
        asterixParserThread.setScvQcount(scvQcount);
        asterixParserThread.setDebugLogMode(debugLogMode);

        serviceQueManager = new ServiceQueManager(serviceQueue, serviceRunnig);
        serviceQueManager.setScvQclearTime(scvQclearTime);
        serviceQueManager.setScvQcount(scvQcount);
        serviceQueManager.setScvQdiffTime(scvQdiffTime);
        serviceQueManager.setScvQmaxCount(scvQmaxCount);
       
    }

    @Order(1)
    @EventListener(ApplicationReadyEvent.class)
    public void start() {
        
        udpManager.startClient();
        serviceQueManager.start();
        asterixParserThread.start();    
    }


    public void stop() {}

    //////////////////////////////////////////////////////////////////////

    protected UDPEventListener createUDPEventListener() {
        UDPEventListener listener = new UDPEventListener() {

            @Override
            public void udpDataIn(MsgObjVO vo) {
                recvPacketAdd(vo);
                stateMgr.updateState();
            }

            @Override
            public void udpSendData(MsgObjVO vo) {
                throw new UnsupportedOperationException("Unimplemented method 'udpSendData'");
            }

            @Override
            public void udpSendData(String ip, int port, MsgObjVO vo) {
                throw new UnsupportedOperationException("Unimplemented method 'udpSendData'");
            }

            @Override
            public void connected(String ip, int port, int statusCode, String description) {
                throw new UnsupportedOperationException("Unimplemented method 'connected'");
            }

            @Override
            public void disconnected(String ip, int port, int statusCode, String description) {
                throw new UnsupportedOperationException("Unimplemented method 'disconnected'");
            }

            @Override
            public void connectionStatus(String ip, int port, String connEvent, int statusCode, String description) {
                throw new UnsupportedOperationException("Unimplemented method 'connectionStatus'");
            }

        };
        return listener;
    }

    protected void recvPacketAdd(MsgObjVO vo) {
        
        if (vo.getMsg().length < 1) {
            return;
        }

        try {

            String msg = SocketUtil.byteArrayToHexString(vo.getMsg());

            String recvDate = vo.getRecvDT().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"));

            msg = msg.concat("*").concat(recvDate);

            packetQ.add(msg);

            //logger.debug("[UDPDataIn] : " + msg);

        } catch (Exception e) {

            logger.error("[MainController] recvPacketAdd Exception " + CmmnUtil.getStatckTrace(e) );

        }
    }

    @Override
    public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
        this.stop();
        logger.info("====================== SYSTEM STOPED ======================");
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

}
