package com.its.vds.xnettcp.vds.process.response.impl;

import com.its.app.AppUtils;
import com.its.vds.dto.TbVdsCtlrDto;
import com.its.vds.dto.TbVdsDtctDto;
import com.its.vds.entity.TbVdsDtctClct;
import com.its.vds.process.DbmsData;
import com.its.vds.process.DbmsDataProcess;
import com.its.vds.process.DbmsDataType;
import com.its.vds.xnettcp.vds.process.response.VdsResponse;
import com.its.vds.xnettcp.vds.protocol.VdsFramePacket;
import com.its.vds.xnettcp.vds.protocol.enums.eVdsOpCode;
import com.its.vds.xnettcp.vds.protocol.impl.andong.VdsAndongResFrameHead;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Slf4j
@RequiredArgsConstructor
public class VdsResDataTraffic implements VdsResponse {

    private final TbVdsCtlrDto vdsObj;
    private final VdsFramePacket resFramePacket;
    private int frameNo;
    private int detectLanes;
    private byte[] errorCode;

    @Override
    public boolean process() {
        // VDS 교통데이터(교통량, 점유율, 차량길이)
        this.vdsObj.getVdsDtctMap().forEach((lane, dtct) -> {
            dtct.getClct().initVal();
        });

        byte[] body = this.resFramePacket.getBody();
        log.info("VdsResDataTraffic.process: VDS {}, body length: {}.", this.vdsObj.getVdsCtlrNmbr(), body != null ? body.length : 0);
        if (body == null || body.length < 18) {
            log.error("VdsResDataTraffic.process: VDS {}, body length error: {}.", this.vdsObj.getVdsCtlrNmbr(), body != null ? body.length : 0);
            return false;
        }

        this.frameNo = body[0] & 0xFF;
        this.detectLanes = body[1] & 0xFF;

        this.errorCode = new byte[16];
        for (int ii = 0; ii < 16; ii++) {
            this.errorCode[ii] = (byte)(body[2+ii] & 0xFF);
        }

        VdsAndongResFrameHead head = (VdsAndongResFrameHead)this.resFramePacket.getHead();
        int length = head.getLength();
        int dataLength = length - 2 - 18;   // status1, status2, frameNo, detectLanes, errorCode
        int bodyLength = body.length - 18;
        int laneCnt = dataLength / 12;
        if (dataLength != bodyLength) {
            log.error("VdsResDataTraffic.process: VDS {}, body length error: {}.", this.vdsObj.getVdsCtlrNmbr(), body != null ? body.length : 0);
            return false;
        }
        if (laneCnt != this.detectLanes) {
            log.warn("VdsResDataTraffic.process: VDS {}, Lane Count error: detectLanes {}, laneCnt {}.", this.vdsObj.getVdsCtlrNmbr(), this.detectLanes, laneCnt);
        }

        // 차로별 교통정보
        int   idx, tTfvl, sTfvl, mTfvl, lTfvl, spd, occ1, occ2, lngt, hdwy, spc_occ1, spc_occ2, spc_spd;
        float occ, spc_occ;
        for (int ii = 0; ii < laneCnt; ii++) {
            idx = (ii * 12) + 18;

            tTfvl    = Byte.toUnsignedInt(body[idx]);
            sTfvl    = Byte.toUnsignedInt(body[idx+1]);
            mTfvl    = Byte.toUnsignedInt(body[idx+2]);
            lTfvl    = Byte.toUnsignedInt(body[idx+3]);
            spd      = Byte.toUnsignedInt(body[idx+4]);

            occ1     = Byte.toUnsignedInt(body[idx+5]);
            occ2     = Byte.toUnsignedInt(body[idx+6]);

            lngt     = Byte.toUnsignedInt(body[idx+7]);
            hdwy     = Byte.toUnsignedInt(body[idx+8]);

            spc_occ1 = Byte.toUnsignedInt(body[idx+9]);
            spc_occ2 = Byte.toUnsignedInt(body[idx+10]);

            spc_spd  = Byte.toUnsignedInt(body[idx+11]);

            occ  = (float)(occ1 + (occ2 * 0.01));
            spc_occ  = (float)(spc_occ1 + (spc_occ2 * 0.01));

            Integer DETECT_LANE = ii+1;

            log.info("[{}]. Job_Data: Lane:{}, T-TFVL:{}, S-TFVL:{}, M-TFVL:{}, L-TFVL:{}, SPED:{}, OCPY:{}, LNGT:{}, HDWY:{}, SPCE_OCPY:{}, SPCE_SPED:{}",
                    this.vdsObj.getVdsCtlrNmbr(), DETECT_LANE, tTfvl, sTfvl, mTfvl, lTfvl, spd, occ, lngt, hdwy, spc_occ, spc_spd);

            TbVdsDtctDto dtct = this.vdsObj.getVdsDtctMap().get(DETECT_LANE);
            if (dtct == null) {
                log.error("[{}]. Job_Data: Unknown Lane No {}.", this.vdsObj.getVdsCtlrNmbr(), DETECT_LANE);
            } else {
                if (tTfvl > dtct.getMaxTfvl() || tTfvl < dtct.getMinTfvl()) {
                    log.error("[{}]. Job_Data: TFVL Error Lane No {}. {}/{}/{}", this.vdsObj.getVdsCtlrNmbr(), DETECT_LANE, tTfvl, dtct.getMaxTfvl(), dtct.getMinTfvl());
                    continue;
                }

                dtct.getClct().setTfvl(tTfvl);
                dtct.getClct().setSTfvl(sTfvl);
                dtct.getClct().setMTfvl(mTfvl);
                dtct.getClct().setLTfvl(lTfvl);

                if (spd > dtct.getMaxSped() || spd < dtct.getMinSped()) {
                    log.error("[{}]. Job_Data: SPED Error Lane No {}. {}/{}/{}", this.vdsObj.getVdsCtlrNmbr(), DETECT_LANE, spd, dtct.getMaxSped(), dtct.getMinSped());
                    continue;
                }
                dtct.getClct().setSped(spd);

                if (occ > dtct.getMaxOcpyRate() || spd < dtct.getMinOcpyRate()) {
                    log.error("[{}]. Job_Data: OCPY Error Lane No {}. {}/{}/{}", this.vdsObj.getVdsCtlrNmbr(), DETECT_LANE, occ, dtct.getMaxOcpyRate(), dtct.getMinOcpyRate());
                    continue;
                }

                dtct.getClct().setAvrgOcpyRate((double) occ);
                dtct.getClct().setHdwy(hdwy);
                dtct.getClct().setAvrgLngt(lngt);
                dtct.getClct().setSpceOcpyRate((double) spc_occ);
                dtct.getClct().setSpceAvrgSped(spc_spd);
                dtct.getClct().setValid(true);
            }
        }

        //수집한 교통정보를 데이터베이스에 저장
        List<TbVdsDtctClct> dtctClctList = Collections.synchronizedList(new ArrayList<>());
        this.vdsObj.getVdsDtctMap().forEach((lane, dtct) -> {
            if (!dtct.getClct().isValid()) {
                return;
            }
            dtctClctList.add(dtct.getClct().toEntity());
        });

        if (!dtctClctList.isEmpty()) {
            DbmsDataProcess dbmsDataProcess = (DbmsDataProcess) AppUtils.getBean(DbmsDataProcess.class);
            dbmsDataProcess.add(new DbmsData(DbmsDataType.DBMS_DATA_DTCT_CLCT, false, dtctClctList));
        }

        if (this.vdsObj.getDebug().isDebug()) {
            log.info("{}", toString());
        }

        return true;
        // 제어기 전원모듈상태 요청
        //return this.vdsObj.addRequestData(new TcpServerSendData(eVdsOpCode.OP_VDS_DATA_VEHICLE, null));
    }

    public String toString() {
        StringBuilder data = new StringBuilder();
        data.append(String.format("RESPONSE-%s. VDS %d", eVdsOpCode.OP_VDS_DATA_TRAFFIC, this.vdsObj.getVdsCtlrNmbr()));
        data.append(System.getProperty("line.separator"));
        data.append(String.format("FrameNo(%d), 검지차로수 %d", this.frameNo, this.detectLanes));
        for (int ii = 0; ii < 16; ii++) {
            data.append(String.format(", 0x%02X", this.errorCode[ii]));
        }
        return data.toString();
    }

}
