package com.its.api.xnetudp.thread;

import com.its.api.xnetudp.protocol.CENTER_COMM_DEFINE;
import com.its.api.xnetudp.protocol.CENTER_COMM_MESSAGE;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

@Slf4j
@Service
public class CenterCommServerReceiver {

    @Async("centerCommExecutor")
    public void run(CENTER_COMM_MESSAGE data) {
        if (data == null) {
            log.error("CenterCommServerReceiver: RECV Data Packet NULL");
            return;
        }

        if (CENTER_COMM_DEFINE.INT_ID_TRAFFIC_SERVER == data.getSendId()) {
            if (CENTER_COMM_DEFINE.INT_OP_TRAFFIC_CHANGE == data.getOpCode()) {
                log.error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ RECV Traffic server job completed.");
            }
            return;
        }

        // VMS 통신 서버는 Sender, Receiver 위치가 바뀌었음. ==> 서버 수정했음.
        //if (CENTER_COMM_DEFINE.INT_ID_VMS_OPER == data.getSendId() && CENTER_COMM_DEFINE.INT_ID_VMS_SERVER == data.getRecvId()) {
        if (CENTER_COMM_DEFINE.INT_ID_VMS_SERVER == data.getSendId()) {
            log.error("RECV VMS Server Message[0xFF]: Length: {} Bytes.", data.getLength());
            //log.error("VMS PACKET: {}", SysUtils.byteArrayToHex(data.getBody()));
            if (data.getLength() > 0) {
                ByteBuffer byteBuffer = ByteBuffer.wrap(data.getBody());
                byteBuffer.order(ByteOrder.BIG_ENDIAN);

                byte[] vmsId;
                byte count;
                byte opCode = byteBuffer.get();
                byte msgSeq = byteBuffer.get();
                log.error("OP CODE: {}, MsgSeq: {}", opCode, msgSeq);
                switch(opCode) {
                    case CENTER_COMM_DEFINE.INT_OP_VMS_FORM_DOWNLOAD:
                        count = byteBuffer.get();
                        log.error("INT_OP_VMS_FORM_DOWNLOAD: Count: {} EA", count);
                        for (int ii = 0; ii < count; ii++) {
                            vmsId = new byte[CENTER_COMM_DEFINE.INT_VMS_MAX_ID];
                            byte[] downloadDt  = new byte[CENTER_COMM_DEFINE.INT_VMS_MAX_DATETIME];
                            byteBuffer.get(vmsId);
                            byteBuffer.get(downloadDt);
                            byte result = byteBuffer.get();

                            for (int jj = 0; jj < vmsId.length; jj++) {
                                if (vmsId[jj] < '0' || vmsId[jj] > '9') {
                                    vmsId[jj] = ' ';
                                }
                            }
                            //log.error("{}, {}, {}, {}", ii+1, new String(vmsId).trim(), new String(downloadDt), result);
                        }
                        break;
                    case CENTER_COMM_DEFINE.INT_OP_VMS_FORM_SAVE:
                        byte[] saveDt  = new byte[CENTER_COMM_DEFINE.INT_VMS_MAX_DATETIME];
                        byteBuffer.get(saveDt);
                        log.error("INT_OP_VMS_FORM_SAVE: SaveTime: {}", new String(saveDt));
                        break;
                    case CENTER_COMM_DEFINE.INT_OP_VMS_STATE_RES:
                        short total = byteBuffer.getShort();
                        short error = byteBuffer.getShort();
                        short normal = byteBuffer.getShort();
                        short module = byteBuffer.getShort();
                        count = byteBuffer.get();
                        log.error("INT_OP_VMS_STATE_RES: total({}), error({}), normal({}), module({}), count: {} EA.", total, error, normal, module, count);
                        for (int ii = 0; ii < count; ii++) {
                            vmsId = new byte[CENTER_COMM_DEFINE.INT_VMS_MAX_ID];
                            byteBuffer.get(vmsId);
                            byte  OprMode = byteBuffer.get();                                      /* VMS운영모드, 0:auto, 1:Fix */
                            byte  Comm = byteBuffer.get();                                         /* 유선통신상태, 0:정상 1:장애 */
                            byte  Wcomm = byteBuffer.get();                                        /* 무선통신상태, 0:정상 1:장애 */

                            byte  DoorStatus = byteBuffer.get();                                   /* 도어상태정보코드,     0:열림 1:닫힘 2:알수없음 */
                            byte  ModulePowerStatus = byteBuffer.get();                            /* 모듈전원상태정보코드, 0:켜짐 1:꺼짐 2:알수없음 */
                            short BodyTemp = byteBuffer.getShort();                                     /* 함체온도값(℃), 범위(-128~127) */
                            byte  LuminanceStatus = byteBuffer.get();                              /* 화면의 밝기값 (최대 휘도값을 100으로 했을 때의 백분율 값), 범위(0~100) */
                            byte  FanStatus = byteBuffer.get();                                    /* Fan 동작상태정보코드,    0:켜짐, 1:꺼짐 2:알수없음 */
                            byte  HeaterStatus = byteBuffer.get();                                 /* Heater 동작상태정보코드, 0:켜짐, 1:꺼짐 2:알수없음 */

                            byte  ExternalLightStatus = byteBuffer.get();                          /* 선택 외부조명 동작상태정보코드 0:켜짐, 1:꺼짐, 2:자동(공단은 미사용) */
                            byte  AlarmLightStatus = byteBuffer.get();                             /* 선택 경광등 동작상태정보코드   0:켜짐, 1:꺼짐 */
                            byte  SpeakerStatus = byteBuffer.get();                                /* 선택 스피커 동작상태정보코드   0:켜짐, 1:꺼짐 */
                            byte[] ControllerCurrentTime  = new byte[CENTER_COMM_DEFINE.INT_VMS_MAX_DATETIME];
                            byteBuffer.get(ControllerCurrentTime);
                            byte  Voltage = byteBuffer.get();                                      /* 전압, 범위(0~255), 사용안함 */

                            byte  ModuleState = byteBuffer.get();                                  /* 모듈 상태, 0:정상 1:장애 2:알수없음 */
                            byte  ModuleHorizontal = byteBuffer.get();                             /* 가로 모듈수 */
                            byte  ModuleVertical = byteBuffer.get();                               /* 세로 모듈수 */
                            byte[]  ModuleStatus = new byte[CENTER_COMM_DEFINE.INT_VMS_MAX_MODULE_BIT];         /* 모듈 개별 상태, 0:정상 1:장애 2:알수없음 */
                            byteBuffer.get(ModuleStatus);
                            byte  PowerCount = byteBuffer.get();                                   /* 전원 갯수 */
                            byte[]  PowerStatus = new byte[CENTER_COMM_DEFINE.INT_VMS_MAX_POWER_BIT];           /* 전원 개별 상태, 0:켜짐 1:꺼짐 2:알수없음 */
                            byteBuffer.get(PowerStatus);
                            byte[]  Dummy = new byte[CENTER_COMM_DEFINE.INT_VMS_STATUE_DUMMY];                  /* protocol dummy bytes */
                            byteBuffer.get(Dummy);
                            short ScheduledMessageOperatingTime = byteBuffer.getShort();                /* 필수 계획된 메시지의 동작시간(초) */
                            short ModuleOperatingTemperature = byteBuffer.getShort();                   /* 필수 모듈 전원이 꺼지는 온도값(℃) */
                            short FanOperatingTemperature = byteBuffer.getShort();                      /* 필수 Fan 동작 기준 온도값(℃) */
                            short HeaterOperatingTemperature = byteBuffer.getShort();                   /* 필수 Heater 동작 기준 온도값(℃) */
                            short ExternalLightOperatingLuminance = byteBuffer.getShort();              /* 선택 외부전등 동작 기준 휘도값 */
                            short ModuleBasicFailureRate = byteBuffer.getShort();                       /* 선택 모듈 장애율 (한 개의 모듈을 장애로 처리하기 위한 픽셀의 백분율값) */
                            short MaximumRetry = byteBuffer.getShort();                                 /* 선택 최대 재시도 횟수(회) */
                            short ResponseTimeOut = byteBuffer.getShort();                              /* 선택 최대응답대기시간 (초) */
                            short BlinkingCycleTime = byteBuffer.getShort();                            /* 선택 점멸시간 주기 ( 1/10초단위) */

                            for (int jj = 0; jj < vmsId.length; jj++) {
                                if (vmsId[jj] < '0' || vmsId[jj] > '9') {
                                    vmsId[jj] = ' ';
                                }
                            }
                            log.error("{}, VmsId: {}, ModuleHor: {}, ModuleVer: {}", ii+1, new String(vmsId).trim(), ModuleHorizontal, ModuleVertical);
                        }
                        break;
                    default:
                        log.error("Other opCode: {}", opCode);
                        break;
                }
            }
        }

        String reqIpAddr = data.getSenderIp();
        int reqPort = 4603;
        /*UnitSystService unitSystService = (UnitSystService) AppUtils.getBean(UnitSystService.class);
        ConcurrentHashMap<String, voUnitSyst> untiSystMap = unitSystService.getUntiSystMap();
        for (Map.Entry<String, voUnitSyst> e : untiSystMap.entrySet()) {
            if (reqIpAddr.equals(e.getValue().getSYST_IP_1())) {
                reqPort = e.getValue().getPRGM_PORT();
                break;
            }
        }*/

        /*byte opCode = data.getOpCode();
        if (opCode == CENTER_COMM_DEFINE.INT_OP_DSRC_CONTROL_REQ) {

            CENTER_DSRC_REQ_CONTROL req = new CENTER_DSRC_REQ_CONTROL(data.getBody());
            log.info("DSRC REQ CONTROL: [{}] [{},{},{},{}], {}",
                    req.getCtlrNmbr(), req.getOperId(), req.getCmdTime(), req.getDeviceType(), req.getControlType(), Thread.currentThread().getName());

            int devcType = req.getDeviceType();
            int cntlType = req.getControlType();
            voDsrcCtlrCntl cntl = new voDsrcCtlrCntl();
            cntl.setReq(req);
            cntl.setReqIpAddress(data.getSender().getAddress().getHostAddress());
            cntl.setReqPort(data.getSender().getPort());
            cntl.setID(req.getCtlrNmbr());
            cntl.setCNTL_DT(SysUtils.getSysTime());
            cntl.setDEVC_TYPE(String.valueOf(devcType));
            cntl.setCNTL_TYPE(String.valueOf(cntlType));

            voDsrcCtlr dsrcCtlr = AppRepository.getInstance().getCtlrMap().get(String.valueOf(req.getCtlrNmbr()).toString());
            if (dsrcCtlr == null) {
                log.info("DSRC REQ CONTROL Unknown DSRC ID: [{}] [{},{},{},{}]",
                        req.getCtlrNmbr(), req.getOperId(), req.getCmdTime(), req.getDeviceType(), req.getControlType());
                responseOperator(null, cntl, (byte)0x01);
                return;
            }
            if (dsrcCtlr.getChannel() == null || dsrcCtlr.getNetState() != NET.LOGINED) {
                // 여기 들어오면 안된다. 운영단말에서 통신이 정상인 것만 제어를 내릴수 있도록 한다.
                log.error("DSRC REQ CONTROL Not Connect: [{}] [{},{},{},{}]",
                        req.getCtlrNmbr(), req.getOperId(), req.getCmdTime(), req.getDeviceType(), req.getControlType());
                responseOperator(dsrcCtlr, cntl, (byte)0x01);
                return;
            }

            // 제어요청 패킷을 만든다
            eControlDeviceId controlDeviceId = eControlDeviceId.getByValue(devcType);
            eControlCommand commandType = eControlCommand.getByValue(cntlType);
            if (controlDeviceId == null || commandType == null) {
                log.error("DSRC REQ CONTROL Value Error: [{}] [{},{},{},{}]",
                        req.getCtlrNmbr(), req.getOperId(), req.getCmdTime(), req.getDeviceType(), req.getControlType());
                responseOperator(dsrcCtlr, cntl, (byte)0x01);
                return;
            }
            log.warn("{}, {}, controlDeviceId: {}, commandType: {}", dsrcCtlr.getID(), dsrcCtlr.getRSE_ID(), controlDeviceId.toString(), commandType.toString());
            boolean res = ControlDeviceService.getInstance().requestSubscriptionDeviceCommand(true, dsrcCtlr, dsrcCtlr.getChannel(), controlDeviceId.getValue(), commandType.getValue());
            if (res) {
                log.info("DSRC REQ CONTROL SEND OK: [{}] [{},{},{},{}]",
                        req.getCtlrNmbr(), req.getOperId(), req.getCmdTime(), req.getDeviceType(), req.getControlType());
                responseOperator(dsrcCtlr, cntl, (byte)0x00);
            } else {
                log.error("DSRC REQ CONTROL SEND Error: [{}] [{},{},{},{}]",
                        req.getCtlrNmbr(), req.getOperId(), req.getCmdTime(), req.getDeviceType(), req.getControlType());
                responseOperator(dsrcCtlr, cntl, (byte)0x01);
            }
        }
        else {
            log.error("UDP RECV UNKNOWN MESSAGE: {}", opCode);
        }*/
    }
/*
    private int responseOperator(voDsrcCtlr obj, voDsrcCtlrCntl cntl, byte error) {
        CenterCommResponseService responseService = (CenterCommResponseService) AppUtils.getBean(CenterCommResponseService.class);
        return responseService.response(obj, cntl, error);
    }*/
}
