package com.its.dsrc.xnettcp.dsrc.process.service;

import com.beanit.asn1dsrc.dsrc.OBUGatherInfo;
import com.its.app.AppUtils;
import com.its.dsrc.entity.TbRseCtlr;
import com.its.dsrc.entity.TbRseObuClct;
import com.its.dsrc.global.AppRepository;
import com.its.dsrc.process.DbmsData;
import com.its.dsrc.process.DbmsDataProcess;
import com.its.dsrc.process.DbmsDataType;
import com.its.dsrc.service.RseSectService;
import com.its.dsrc.vo.voDsrcObuPassInfo;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

@Getter
@Slf4j
public class OBUGatherInfoService {

    private RseSectService rseSectService;
    private DbmsDataProcess dbmsDataProcess;

    private static OBUGatherInfoService _instance = null;

    public static OBUGatherInfoService getInstance() {
        if (_instance == null) {
            synchronized (OBUGatherInfoService.class) {
                if (_instance == null)
                    _instance = new OBUGatherInfoService();
            }
        }
        return _instance;
    }

    public OBUGatherInfoService() {
        this.dbmsDataProcess = (DbmsDataProcess) AppUtils.getBean(DbmsDataProcess.class);
        this.rseSectService = (RseSectService) AppUtils.getBean(RseSectService.class);
    }

    /*
     *  AI_Publication 메시지로 수신한 데이터중 OBU 수집 정보에 대한 데이터 Decoding
     *  decoding 한 OBU 수집 정보를 데이터베이스에 저장하고,
     *  OBU 가 지나온 RSE 를 이용하여 RSE 구간 소통정보를 생성한다.
     */
    public boolean decoding_OBUGatherInfo(TbRseCtlr obj, List<OBUGatherInfo> list) {

        List<TbRseObuClct> obuGatherInfos = Collections.synchronizedList(new ArrayList<>());

        log.debug("OBUGatherInfoService.decoding_OBUGatherInfo: {}, {}, {} EA", obj.getID(), obj.getRSE_ID(), list.size());

        String dsrcId = obj.getID();
        try {
            for (OBUGatherInfo obuGatherInfo : list) {
                String individualId = "";
                String manufacturerId = "";
                if (obuGatherInfo.getRseIDNumber().getIndividualid() == null) {
                    log.warn("{}, ObuGatherInfo.getIndividualid NULL", obj.getID());
                    return false;
                }
                if (obuGatherInfo.getRseIDNumber().getManufacturerid() == null) {
                    log.warn("{}, ObuGatherInfo.getManufacturerid NULL", obj.getID());
                }

                individualId = obuGatherInfo.getRseIDNumber().getIndividualid().toString();
                manufacturerId = obuGatherInfo.getRseIDNumber().getManufacturerid().toString();

                // individualid == rseId
                String obuType = "0";
                String vehicleType = "0";
                String obuIdNumber = "0";
                String generationDate = "0";
                String generationTime = "0";
                if (obuGatherInfo.getObuType() != null) {
                    obuType = obuGatherInfo.getObuType().toString();
                }
                if (obuGatherInfo.getVehicleType() != null) {
                    vehicleType = obuGatherInfo.getVehicleType().toString();
                }
                if (obuGatherInfo.getObuIdNumber() != null) {
                    obuIdNumber = obuGatherInfo.getObuIdNumber().toString();
                }
                if (obuGatherInfo.getGenerationDate() != null) {
                    generationDate = obuGatherInfo.getGenerationDate().toString();
                }
                if (obuGatherInfo.getGenerationTime() != null) {
                    generationTime = obuGatherInfo.getGenerationTime().toString();
                }

                // 이전 통과 RSE 를 찾는다
                //

                String generationTm = generationDate+generationTime;
                TbRseObuClct voObu = new TbRseObuClct(obj.getID(), generationTm, obuIdNumber, vehicleType, obuType);
                obuGatherInfos.add(voObu);

                log.debug("OBUGatherInfoService.decoding_OBUGatherInfo: {}, {}, {}, {}, voObu: {}",
                        obj.getID(), obj.getRSE_ID(), generationDate, generationTime, voObu.toString());

                // 시작 RSE 에 해당하는 모든 구간에 대하여
                Iterator<String> startDsrcSectIds = AppRepository.getInstance().rseSectStartMap.get(dsrcId).iterator();
                synchronized (this.rseSectService.getDsrcObuPassMap()) {
                    while (startDsrcSectIds.hasNext()) {
                        String startDsrcSectId = startDsrcSectIds.next();
                        if (startDsrcSectId == null || startDsrcSectId.equals("")) {
                            continue;
                        }
                        // 모든 SECT_ID에 대하여 무조건 추가한다.
                        voDsrcObuPassInfo obuStartPassInfo = new voDsrcObuPassInfo();
                        obuStartPassInfo.setObuId(obuIdNumber);
                        obuStartPassInfo.setStartDsrcPassTm(generationTm);
                        this.rseSectService.getDsrcObuPassMap().get(startDsrcSectId).put(obuIdNumber, obuStartPassInfo);
                    }
                }

                // 종료 RSE 에 해당하는 모든 구간에 대하여
                Iterator<String> endDsrcSectIds = AppRepository.getInstance().rseSectEndMap.get(dsrcId).iterator();
                synchronized (this.rseSectService.getDsrcObuPassMap()) {
                    while (endDsrcSectIds.hasNext()) {
                        String endDsrcSectId = endDsrcSectIds.next();
                        if (endDsrcSectId == null || endDsrcSectId.equals("")) {
                            continue;
                        }
                        // 종료 SECT_ID에 대하여 이전 통과정보가 존재하지 않으면 추가, 존재하면 통과종료시각 업데이트
                        Map<String, voDsrcObuPassInfo> passInfo = this.rseSectService.getDsrcObuPassMap().get(endDsrcSectId);
                        if (passInfo == null || !passInfo.containsKey(obuIdNumber)) {
                            // 존재하지 않으면 추가한다.
                            voDsrcObuPassInfo obuEndPassInfo = new voDsrcObuPassInfo();
                            obuEndPassInfo.setObuId(obuIdNumber);
                            obuEndPassInfo.setEndDsrcPassTm(generationTm);
                            this.rseSectService.getDsrcObuPassMap().get(endDsrcSectId).put(obuIdNumber, obuEndPassInfo);
                            continue;
                        }

                        // 존재하면 종료 DSRC 통과시각을 업데이트 한다.
                        passInfo.get(obuIdNumber).setEndDsrcPassTm(generationTm);
                    }
                }
            }
        }
        catch(Exception e) {
            log.error("{}", e.toString());
        }

        if (obuGatherInfos.size() > 0) {
            // OBU 수집정보를 데이터베이스에 저장
            this.dbmsDataProcess.add(new DbmsData(DbmsDataType.DBMS_DATA_OBU_GATHER_LOG, false, (Object)obuGatherInfos));
        }
        return true;
    }

}
