package com.pwt.netty.handler.codec.vehicle1;

import com.pwt.netty.common.vehicle1.Vehicle1Message;
import com.pwt.netty.common.vehicle1.client.*;
import com.pwt.netty.common.vehicle1.server.*;
import com.pwt.netty.handler.codec.exceptions.ProtocolException;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;

import java.nio.ByteOrder;

import static com.pwt.netty.common.vehicle1.Vehicle1Message.MAGIC_LENGTH;

public class Vehicle1ProtocolDecoder extends LengthFieldBasedFrameDecoder {

    public Vehicle1ProtocolDecoder() {
        super(ByteOrder.LITTLE_ENDIAN, 128, 2, 1, 0, 2, true);
    }

    @Override
    protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
        if(in.readableBytes() < MAGIC_LENGTH) {
            return null;
        }

        // 验证frame header
        in.markReaderIndex();
        short header = in.readShortLE();
        if(header != Vehicle1Message.MAGIC) {
            throw new ProtocolException("invalid frame header");
        }
        in.resetReaderIndex();

        // 基于长度帧解码
        ByteBuf byteBuf = (ByteBuf)super.decode(ctx, in);
        if(byteBuf == null) {
            return null;
        }
        // skip header
        // byteBuf.skipBytes(2); 因为在LengthFieldBasedFrameDecoder中指定了initialBytesToStrip，所以这里不需要再跳过
        byte length = byteBuf.readByte();
        byte type = byteBuf.readByte();
        Vehicle1Message message;
        switch (type) {
            case (byte)0x10:
                message = new LoginResponse();
                break;
            case (byte)0x11:
                message = new HeartBeatResponse();
                break;
            case (byte)0x12:
                message = new BatterySwapResponse();
                break;
            case (byte)0x13:
                message = new BatterySwapDoneRequest();
                break;
            case (byte)0x14:
                message = new LockRequest();
                break;
            case (byte)0x20:
                message = new LoginRequest();
                break;
            case (byte)0x21:
                message = new HeartBeatRequest();
                break;
            case (byte)0x22:
                message = new BatterySwapRequest();
                break;
            case (byte)0x23:
                message = new BatterySwapDoneResponse();
                break;
            case (byte)0x24:
                message = new LockResponse();
                break;
            default:
                throw new ProtocolException(String.format("invalid message type 0x%x.", type));
        }
        if(message.getProtocolLength() != length) {
            throw new ProtocolException("decode frame error: data length mismatched.");
        }
        message.decode(byteBuf);
        return message;
    }
}
