package com.its.vms.domain;

import com.its.app.utils.ItsUtils;
import com.its.vms.config.ApplicationConfig;
import com.its.vms.domain.enums.eVmsScheduleType;
import com.its.vms.dto.*;
import com.its.vms.entity.TbVmsDsplPrst;
import com.its.vms.service.VmsFontService;
import com.its.vms.service.VmsFormService;
import com.its.vms.service.VmsIfscService;
import com.its.vms.service.VmsSymbService;
import com.its.vms.xnettcp.vms.protocol.VmsProtocolConst;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 *  DTO Class
 */
@Slf4j
@Data
public class VmsForm implements Serializable {
    private static final long serialVersionUID = 1L;

    private int     scenarioSeq;        // 폼 표출순서
    private Integer vmsFormId;          // TB_VMS_FORM - VMS FORM ID
    private int     width;              // 폼넓이
    private int     height;             // 폼높이

    private int     dsplHh;             // TB_VMS_FORM - 표출시간(초)
    private int     vmsFormDsplDrctCd;  // TB_VMS_FORM - VMS 메시지 표출 방향 코드
    private int     vmsFormDsplMthdCd;  // TB_VMS_FORM - VMS 메시지 표출 방법 코드
    private int     vmsFormTypeCd;      // TB_VMS_FORM - 폼 종류
    private int     vmsFormColrCd;      // TB_VMS_FORM - 배경색상

    private Integer trfBakImgId;

    private String  vmsSchType;
    int             vmsSchFormType;
    private String  symbLibNmbr;
    private String  strmAddr;

    private boolean success;
    private boolean svcRes;             // 제공결과
    private boolean ftpRes;             // 제공결과

    private String  ftpFileName;
    private String  localFileName;

    // 프로토콜 적용을 위해서
    private byte    fileType;           // 0x01 : 이미지 (JPG)
                                        // 0x02 : 동영상 (AVI)
                                        // 0x03 : URL(스트리밍)
                                        // 0x04 : 소통 이미지
                                        // 0x05 : 표출문구 이미지

    private int     totalCount;
    private int     objectCount;
    private BufferedImage formImage;
    private List<VmsFormObject> objects;
    private byte[] imageData;
    private String vmsDsplMsgData;
    private String vmsDsplMsgTxt;
    private int dnldFormNo;

    public VmsForm(Integer vmsFormId) {
        this.vmsFormId = vmsFormId;
        this.totalCount = 0;
        this.objectCount = 0;

        this.success = false;
        this.svcRes = false;
        this.ftpRes = false;
        this.trfBakImgId = 0;

        this.ftpFileName = "";
        this.localFileName = "";
        this.formImage = null;
        this.objects = new ArrayList<>();
        this.imageData  = null;
        this.vmsDsplMsgData = "";
        this.vmsDsplMsgTxt = "";
    }

    public void clear() {
        this.svcRes = false;
        this.ftpRes = false;
        this.objectCount = 0;
    }

    public void init(int width, int height) {
        this.width = width;
        this.height = height;
        this.formImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    }
    public void initDownload(TbVmsCtlrDto vmsObj, TbVmsFormDto vmsForm, TbVmsScheduleDto schedule) {
        setSuccess(false);
        setSvcRes(false);
        setFtpRes(false);
        setFtpFileName(vmsForm.getFtpFileName());
        setLocalFileName(vmsForm.getLocalFileName());
        setVmsSchType(schedule.getVmsSchType());
        setVmsSchFormType(schedule.getVmsSchFormType());
        setSymbLibNmbr(schedule.getSymbLibNmbr()+"0");
        setStrmAddr(schedule.getStrmAddr());

        setScenarioSeq(vmsObj.getFormManager().count());
        setVmsFormId(vmsForm.getVmsFormId());
        setDsplHh(schedule.getDsplHh());
        setVmsFormDsplDrctCd(vmsForm.getVmsFormDsplDrctCd());
        setVmsFormDsplMthdCd(vmsForm.getVmsFormDsplMthdCd());
        setVmsFormTypeCd(vmsForm.getVmsFormTypeCd());
        setVmsFormColrCd(vmsForm.getVmsFormColrCd());
        setWidth(vmsObj.getVmsWidth());
        setHeight(vmsObj.getVmsHeight());
    }

    public int count() { return this.objectCount; }
    public int total() { return this.totalCount; }

    public VmsFormObject getItem(int idx) {
        if (this.objects.size() > idx) {
            return this.objects.get(idx);
        }
        return null;
    }

    public int addFormObject(VmsFormObject formObj) {
        this.objects.add(formObj);
        this.objectCount = this.objects.size();
        return this.objectCount;
    }

    public VmsFormObject addFormObject(int vmsFormObjectId) {
        VmsFormObject formObj = null;
        if (this.objectCount < this.totalCount) {
            formObj = getItem(this.objectCount);
        }
        else {
            formObj = new VmsFormObject(this.vmsFormId, vmsFormObjectId);
            this.objects.add(formObj);
            this.totalCount++;
        }
        this.objectCount++;
        return formObj;
    }

//    private void formClear(Color bkColor) {
//        if (this.formImage == null || this.g2d == null) {
//            this.formImage = new BufferedImage(this.width, this.height, BufferedImage.TYPE_INT_RGB);
//            this.g2d = formImage.createGraphics();
//        }
//        //this.g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//        this.g2d.setColor(bkColor);
//        this.g2d.fillRect(0, 0, this.width, this.height);
//    }

    /**
     * 폼 이미지를 그린다.
     *
     * @param formService
     * @param fontService
     * @param config
     */
    public void drawForm(VmsFormService formService, VmsFontService fontService, ApplicationConfig config) {
        //formClear(formService.getFormColor(this.vmsFormColrCd));
        if (this.formImage == null) {
            this.formImage = new BufferedImage(this.width, this.height, BufferedImage.TYPE_INT_RGB);
        }
        Graphics2D g2d = this.formImage.createGraphics();
        g2d.setColor(formService.getFormColor(this.vmsFormColrCd));
        g2d.fillRect(0, 0, this.width, this.height);

        // 폼에 속한 객체를 모두 그린다.
        int objCnt = count();
        for (int jj = 0; jj < objCnt; jj++) {
            VmsFormObject pFormObj = getItem(jj);
            pFormObj.drawObject(g2d, formService, fontService, this.vmsFormColrCd, config.getFontSizeRatio());
        } // 폼의 객체수 만큼 객체를 폼에 그린다.

        // 이미지를 바이트배열로 변환
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            ImageIO.write(this.formImage, "bmp", out);
        } catch (IOException e) {
            log.error("VmsForm.drawForm: Image to byte array failed: {}, {}", this.vmsFormId, e.getMessage());
        }
        this.imageData = out.toByteArray();
        g2d.dispose();
    }

    /**
     * 폼의 스케쥴 유형에 따라 폼 파일 형식을 결정한다.
     */
    public void calVmsSchFormType() {
        this.success = true;
        switch (eVmsScheduleType.getValue(this.vmsSchFormType)) {
            case eSchTp_traffic:    //  = 0,    //0:교통,
            case eSchTp_incident:   //  = 1,    //1:돌발,
            case eSchTp_gongsa:     //  = 2,    //2:공사행사,
            case eSchTp_deture:     //  = 4,    //4:우회,
            case eSchTp_congest:    //  = 5,    //5:정체,
                this.fileType = VmsProtocolConst.P_FILE_TYPE_TRAFFIC;
                break;
            case eSchTp_hongbo:     //  = 3,    //3:홍보,
            case eSchTp_safe:       //  = 6,    //6:안전,
            case eSchTp_atmp:       //  = 9,    //9:대기환경
            case eSchTp_park:       //  = 10,   //10:주차정보
            case eSchTp_evehicle:   //  = 11,   //11:긴급차량우선신호
                this.fileType = VmsProtocolConst.P_FILE_TYPE_TEXT;
                break;
            case eSchTp_video:      //  = 7,    //7:동영상,
                this.fileType  = VmsProtocolConst.P_FILE_TYPE_VIDEO;
                this.ftpFileName = ApplicationConfig.FTP_VIDEO + File.separator + this.strmAddr;
                //폼디렉토리에 동영상파일을 복사해서 처리하도록 수정해야지..........
                break;
            case eSchTp_stream:     //  = 8,    //8:스트리밍영상
                this.fileType    = VmsProtocolConst.P_FILE_TYPE_STREAM;
                this.ftpFileName = this.strmAddr;
                break;
            default:
                this.fileType = VmsProtocolConst.P_FILE_TYPE_TEXT;
                this.success = false;
                break;
        }
    }

    /**
     * 폼 이미지를 파일로 저장
     */
    public void saveToFile() {
        File formFile = new File(this.localFileName);
        if (formFile.exists()) {
            formFile.delete();
        }
        if (this.imageData != null) {
            ItsUtils.saveByteArrayToFile(this.localFileName, this.imageData);
        }
        else {
            log.error("VmsForm.saveToFile: Image data is null: {}", this.vmsFormId);
        }
    }

    /**
     * 데이터베이스에 저장할 표출메시지 데이터 문자열 생성
     */
    public void makeVmsDsplMsgData(VmsFormService formService, VmsSymbService symbService, VmsIfscService ifscService) {
        int vms_obj_none   = 0; // 0:정보없음
        int vms_obj_text   = 1; // 1:문자열
        int vms_obj_bitmap = 2; // 2:Bitmap ID
        int vms_obj_draw   = 3; // 3:Draw

        this.vmsDsplMsgData = "";
        this.vmsDsplMsgTxt = "";
        StringBuilder msgData = new StringBuilder();
        StringBuilder msgText = new StringBuilder();
        String sTmp  = "";
        String sCont = "";

        //폼종류/표출시간/배경색상
        sCont = String.format("%02X%02X%02X|", this.vmsFormTypeCd, this.dsplHh, this.vmsFormColrCd);
        msgData.append(sCont);

        // 폼에 속한 객체
        int objType = vms_obj_none;
        int objCnt = count();
        for (int jj = 0; jj < objCnt; jj++) {
            VmsFormObject pFormObj = getItem(jj);


            if (StringUtils.isEmpty(pFormObj.getMemSymbLibNmbr())) pFormObj.setMemSymbLibNmbr("1"); //이력저장용
            if (StringUtils.isEmpty(pFormObj.getTextData())) pFormObj.setTextData(" "); //이력저장용

            switch(pFormObj.getObjectType())
            {
                case   1: //심볼
                case   2: //이미지
                case 167: //@우회소통정보이미지
                case 200: //동영상
                case 300: //스티리밍영상
                case 406: //@통합대기등급 이미지
                case 407: //@미세먼지등급 이미지
                case 408: //@초미세먼지등급 이미지
                case 413: //@오존등급이미지
                    objType = vms_obj_bitmap;
                    sTmp = String.format("%02X%04X%04X%02X%04X%04X%s|",
                            pFormObj.getBlinking(),
                            pFormObj.getPosX(),
                            pFormObj.getPosY(),
                            pFormObj.getBkColor(),
                            pFormObj.getDsplWidth(),
                            pFormObj.getDsplHeight(),
                            pFormObj.getMemSymbLibNmbr());

                    sCont = String.format("%02X%02X%s", objType, sTmp.length(), sTmp);
                    msgData.append(sCont);
                    break;
                case  3: //소통정보배경이미지
                case 17: //1단,소통정보이미지1
                case 27: //2단,소통정보이미지2
                case 37: //3단,소통정보이미지3
                case 47: //4단,소통정보이미지4
                    objType = vms_obj_draw;
                    sTmp = String.format("%02X%04X%04X%02X%04X%04X%s+",
                            pFormObj.getBlinking(),
                            pFormObj.getPosX(),
                            pFormObj.getPosY(),
                            pFormObj.getBkColor(),
                            pFormObj.getDsplWidth(),
                            pFormObj.getDsplHeight(),
                            pFormObj.getMemSymbLibNmbr());

                    sCont = String.format("%02X%02X%s", objType, sTmp.length(), sTmp);
                    msgData.append(sCont);

                    String sVertex = "";
                    TbVmsSymbLibDto pSymbol = symbService.find(pFormObj.getMemSymbLibNmbr());
                    if (pSymbol != null) {
                        int nCnt = 0;
                        StringBuilder msgTemp = new StringBuilder();
                        for (Map.Entry<Integer, TbVmsSymbIfscDto> e : pSymbol.getCellMap().entrySet()) {
                            TbVmsSymbIfscDto pCell = e.getValue();
                            TbVmsIfscTrafDto pIfsc = null;
                            if (pFormObj.getObjectType() == 3) {
                                pIfsc = ifscService.find(pCell.getVmsIfscId());
                            }
                            else {
                                pIfsc = ifscService.find(pFormObj.getIfscId());
                            }
                            if (pIfsc != null) {
                                sVertex = String.format("%03d%03d%d", pCell.getPosX(), pCell.getPosY(), pIfsc.getCmtrGradCd());
                                msgTemp.append(sVertex);
                                nCnt++;
                            }
                        }
                        sTmp = msgTemp.toString();
                        sCont = String.format("%02X%s|", nCnt, sTmp);
                        msgData.append(sCont);
                    }
                    else {
                        sCont = "X|";
                        msgData.append(sCont);
                    }
                   break;
                default://기타 문자열
                    objType = vms_obj_text;

                    msgText.append(pFormObj.getTextData());
                    msgText.append(" ");

                    sTmp = String.format("%02X%04X%04X%02X%02X%02X%02X%02X%02X%s|",
                            pFormObj.getBlinking(),
                            pFormObj.getPosX(),
                            pFormObj.getPosY(),
                            pFormObj.getBkColor(),
                            pFormObj.getFontSize(),
                            pFormObj.getFontColor(),
                            pFormObj.getFontNameCd(),
                            pFormObj.getFontBold(),
                            pFormObj.getTextData().length(),
                            pFormObj.getTextData());

                    sCont = String.format("%02X%02X%s", objType, sTmp.length(), sTmp);
                    msgData.append(sCont);
                    break;
            }
        }

        this.vmsDsplMsgData = msgData.toString();
        this.vmsDsplMsgTxt = msgText.toString();

        /*
         *  웹접근성에서 홍보이미지도 alt 로 내용을 지원해야 하기때문에
         *  폼의 설명이 우선적으로 설정되도록 프로그램 수정(20210615)
         */
        if (StringUtils.isEmpty(this.vmsDsplMsgTxt)) {
            TbVmsFormDto pCDSForm = formService.find(this.vmsFormId);
            if (pCDSForm != null) {
                if (pCDSForm.getVmsFormExpl() != null && (pCDSForm.getVmsFormExpl().length() > pCDSForm.getVmsFormNm().length())) {
                    this.vmsDsplMsgTxt = pCDSForm.getVmsFormExpl();
                }
                else {
                    this.vmsDsplMsgTxt = pCDSForm.getVmsFormNm();
                }
            }
        }

        if (this.vmsDsplMsgData.length() > 1500) this.vmsDsplMsgData = this.vmsDsplMsgData.substring(0, 1499);
        if (this.vmsDsplMsgTxt.length()  > 400) this.vmsDsplMsgTxt  = this.vmsDsplMsgTxt.substring(0, 399);
    } // 폼의 객체수 만큼

    /**
     * VMS 폼 정보를 이용하여 표출메시지 데이터베이스 입력 객체를 생성한다.
     * @param vmsObj
     * @param phase
     * @param dsplDt
     * @param dnldYn
     * @return
     */
    public TbVmsDsplPrst toDsplPrstEntity(TbVmsCtlrDto vmsObj, int phase, String dsplDt, String dnldYn) {
        return TbVmsDsplPrst.builder()
                .vmsCtlrNmbr(vmsObj.getVmsCtlrNmbr())
                .phase(phase)
                .dsplDt(dsplDt)
                .vmsSchType(this.vmsSchType)
                .vmsSchFormType(this.vmsSchFormType)
                .vmsFormId(this.vmsFormId)
                .dsplHh(this.dsplHh)
                .vmsDsplMsgData(this.vmsDsplMsgData)
                .vmsDsplMsgImag(this.imageData)
                .vmsDsplMsgTxt(this.vmsDsplMsgTxt)
                .vmsFormDsplDrctCd(this.vmsFormDsplDrctCd)
                .vmsFormDsplMthdCd(this.vmsFormDsplMthdCd)
                .dnldYn(dnldYn)
                .build();

    }
}

