package com.its.vms.xnettcp.vms.protocol.impl.dle;

import com.google.common.primitives.Bytes;
import com.its.vms.xnettcp.vms.protocol.VmsFrameHead;
import com.its.vms.xnettcp.vms.protocol.VmsProtocolConst;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Data
public class VmsDleFrameHead implements VmsFrameHead {

    public static final int HEAD_SIZE = 11;

    private byte dle = VmsProtocolConst.VMS_DLE;    // byte
    private byte stx = VmsProtocolConst.VMS_STX;    // byte
    private int group;          // byte
    private int controller;     // byte
    private int opCode;         // byte
    private int curr;           // byte
    private int total;          // byte
    private int length;         // int

    public VmsDleFrameHead(int group, int controller, int opCode, int curr, int total) {
        this.group = group;
        this.controller = controller;
        this.opCode = opCode;
        this.curr = curr;
        this.total = total;
        this.length = 0;
    }

    public VmsDleFrameHead(byte[] headBytes) {
        if (headBytes != null && headBytes.length >= VmsDleFrameHead.HEAD_SIZE) {
            ByteBuffer byteBuffer = ByteBuffer.wrap(headBytes);
            byteBuffer.order(VmsDleFramePacket.BYTE_ORDER);
            this.dle = byteBuffer.get();
            this.stx = byteBuffer.get();
            this.group = byteBuffer.get() & 0xFF;
            this.controller = byteBuffer.get() & 0xFF;
            this.opCode = byteBuffer.get() & 0xFF;
            this.curr = byteBuffer.get() & 0xFF;
            this.total = byteBuffer.get() & 0xFF;
            this.length = byteBuffer.getInt();
        }
        else {
            log.error("VmsReqDleFrameHead: create failed, headBytes error");
        }
    }

    public byte[] getBuffer() {
        List<Byte> list = new ArrayList<>();

        // HEAD (패킷 분석결과 DLE Stuffing 하지 않음)
        list.add(this.dle);
        list.add(this.stx);
        list.add((byte)(this.group      & 0xFF));
        list.add((byte)(this.controller & 0xFF));
        list.add((byte)(this.opCode     & 0xFF));
        list.add((byte)(this.curr       & 0xFF));
        list.add((byte)(this.total      & 0xFF));

        // 길이 부분은 Little Endian
        list.add((byte)(((this.length & 0x000000FF)      ) & 0xFF));
        list.add((byte)(((this.length & 0x0000FF00) >>  8) & 0xFF));
        list.add((byte)(((this.length & 0x00FF0000) >> 16) & 0xFF));
        list.add((byte)(((this.length & 0xFF000000) >> 24) & 0xFF));

        return Bytes.toArray(list);
    }

    @Override
    public int getGroupNo() {
        return this.group;
    }

    @Override
    public int getControllerNo() {
        return this.controller;
    }
}
