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

import com.its.app.utils.SysUtils;
import com.its.vms.dto.TbVmsCtlrDto;
import com.its.vms.xnettcp.vms.process.response.VmsResponse;
import com.its.vms.xnettcp.vms.protocol.impl.dle.VmsDleFramePacket;
import com.its.vms.xnettcp.vms.protocol.VmsFramePacket;
import com.its.vms.xnettcp.vms.protocol.VmsProtocolConst;
import com.its.vms.xnettcp.vms.protocol.enums.eVmsErrorCode;
import com.its.vms.xnettcp.vms.protocol.enums.eVmsFormObjectKind;
import com.its.vms.xnettcp.vms.protocol.enums.eVmsOpCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.nio.ByteBuffer;

@Slf4j
@RequiredArgsConstructor
public class VmsResUploadCurrentDisplayForm implements VmsResponse {

    private final TbVmsCtlrDto vmsObj;
    private final VmsFramePacket resFramePacket;
    private boolean success;
    private eVmsErrorCode error;
    private String content;

    @Override
    public boolean process() {
        /**
         * ACK/NAK 확인
         */
        byte[] body = this.resFramePacket.getBody();
        log.info("VmsResUploadCurrentDisplayForm.process: VMS {}, body length: {}.", this.vmsObj.getVmsCtlrNmbr(), body != null ? body.length : 0);
        if (body == null || body.length < 2) {
            log.error("VmsResUploadCurrentDisplayForm.process: VMS {}, body length error: {}.", this.vmsObj.getVmsCtlrNmbr(), body != null ? body.length : 0);
            return false;
        }

        byte result = body[0];
        if (result == VmsProtocolConst.VMS_ACK) {
            parsing(ByteBuffer.wrap(body, 1, body.length - 1));
        }
        else if (result == VmsProtocolConst.VMS_NAK) {
            this.success = false;
            this.error = eVmsErrorCode.getValue(result & 0xFF);
            if (this.error == null) {
                log.error("VmsResUploadCurrentDisplayForm.process: VMS {}, Unknown error code: {}.", this.vmsObj.getVmsCtlrNmbr(), String.format("0x%02X", result & 0xFF));
                this.error = eVmsErrorCode.ERROR_UNKNOWN;
            }
            this.content = "NONE";
        }
        else {
            parsing(ByteBuffer.wrap(body));
        }

        log.info("{}", toString());

        return true;
    }

    private void parsing(ByteBuffer byteBuffer) {
        this.success = true;
        this.error = eVmsErrorCode.ERROR_NONE;
        this.content = "";
        StringBuilder data = new StringBuilder();
        byteBuffer.order(VmsDleFramePacket.BYTE_ORDER);

        try {
            short formId = byteBuffer.getShort();
            short totalForms = byteBuffer.getShort();
            data.append(String.format("폼 ID: %d, 전체 폼의 수: %d", formId, totalForms));
            for (int ii = 0; ii < totalForms; ii++) {
                short formNo = byteBuffer.getShort();
                byte displayTm = byteBuffer.get();
                byte displayTp = byteBuffer.get();
                byte bkColor = byteBuffer.get();
                byte objects = byteBuffer.get();
                data.append(System.getProperty("line.separator"));
                data.append(String.format("순서: %d, 폼번호: %d, 표출시간: %d, 표출유형: %02X, 배경색상: %02X, 오브젝트수: %d",
                        ii+1, formNo, displayTm & 0xFF, displayTp & 0xFF, bkColor & 0xFF, objects & 0xFF));
                for (int jj = 0; jj < objects; jj++) {
                    byte objKind = byteBuffer.get();
                    short objSize = byteBuffer.getShort();
                    byte blinking = byteBuffer.get();
                    short x = byteBuffer.getShort();
                    short y = byteBuffer.getShort();
                    byte fontBkColor = byteBuffer.get();    // 문자열 배경색(도로공사-사용안함)
                    byte etc;
                    short width;
                    short height;
                    byte bitmapType;
                    eVmsFormObjectKind vmsObjKind = eVmsFormObjectKind.getValue(objKind);

                    data.append(System.getProperty("line.separator"));
                    data.append(String.format("    객체유형: %s, 크기: %d, 점멸: 0x%02X, X: %d, Y: %d, TextBkColor: 0x%02X",
                            vmsObjKind.toString(), objSize, blinking, x, y, fontBkColor & 0xFF));

                    data.append(System.getProperty("line.separator"));
                    switch(vmsObjKind) {
                        case OBJECT_TEXT:
                            byte r = byteBuffer.get();
                            byte g = byteBuffer.get();
                            byte b = byteBuffer.get();
                            byte fontSize = byteBuffer.get();
                            byte fontKind = byteBuffer.get();
                            byte fontBold = byteBuffer.get();
                            etc = byteBuffer.get();
                            int fontLength = objSize - 7;    // rgb(3), size(1), kind(1), bold(1), etc(1)
                            if (fontLength <= 0) {
                                data.append(String.format("TEXT 오브젝트 문자길이 오류: %d", fontLength));
                                return;
                            }
                            byte[] text = new byte[fontLength];
                            byteBuffer.get(text);
                            String textContent = SysUtils.byteArrayToString(text);

                            data.append(String.format("        FONT, Color: %03d.%03d.%03d, Size: 0x%02X, Kind: 0x%02X, Bold: 0x%02X, Content: %s",
                                    r & 0xFF, g & 0xFF, b & 0xFF, fontSize & 0xFF, fontKind & 0xFF, fontBold & 0xFF, textContent));
                            break;
                        case OBJECT_BITMAP:
                            width = byteBuffer.getShort();
                            height = byteBuffer.getShort();
                            bitmapType = byteBuffer.get();
                            etc = byteBuffer.get(); // Reserved, 0x00

                            int imageSize = objSize - 6;    // 넓이(2), 높이(2), 유형(1), 기타(1)

                            data.append(String.format("        넓이: %d, 높이: %d, Bitmap 유형: 0x%02X, 이미지크기: %d", width, height, bitmapType & 0xFF, imageSize));

                            if (imageSize <= 0) {
                                data.append(String.format("BITMAP 오브젝트 크기오류: %d", imageSize));
                                return;
                            }
                            byte[] image = new byte[imageSize];
                            byteBuffer.get(image);
                            break;
                        case OBJECT_BITMAP_ID:
                            width = byteBuffer.getShort();
                            height = byteBuffer.getShort();
                            bitmapType = byteBuffer.get();
                            short bitmapId = byteBuffer.getShort();

                            data.append(String.format("        넓이: %d, 높이: %d, Bitmap 유형: 0x%02X, Bitmap ID: BIT%04d.BMP",
                                    width, height, bitmapType & 0xFF, bitmapId));
                            break;
                        default:
                            data.append(String.format("알수없는 오브젝트 종류: 0x%02X", objKind));
                            return;
                    }
                }
            }
        }
        catch (Exception e) {
            log.error("VmsResUploadCurrentDisplayForm.parsing: Exception: {}", e.getMessage());
        }
        finally {
            this.content = data.toString();
        }
    }

    public String toString() {
        StringBuilder data = new StringBuilder();
        data.append(String.format("RESPONSE-%s. VMS %d", eVmsOpCode.OP_VMS_UPLOAD_CURRENT_DISPLAY_FORM, this.vmsObj.getVmsCtlrNmbr()));
        data.append(System.getProperty("line.separator"));
        data.append(String.format("Upload Current Display Form: %s, NAK: %s", this.success, this.error));
        data.append(System.getProperty("line.separator"));
        data.append("CONTENT:");
        data.append(System.getProperty("line.separator"));
        data.append(this.content);
        return data.toString();
    }

}
