package org.yzh.web.jt808.codec;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.CompositeByteBuf;
import io.netty.buffer.UnpooledByteBufAllocator;
import org.yzh.framework.codec.MessageDecoder;
import org.yzh.framework.commons.transform.ByteBufUtils;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

/**
 * 808协议解码器
 *
 * @author zhihao.ye ([email protected])
 */
public class JT808MessageDecoder extends MessageDecoder {

    public JT808MessageDecoder(Charset charset) {
        super(charset);
    }

    /**
     * 获取消息类型
     */
    @Override
    public int getType(ByteBuf source) {
        return source.getUnsignedShort(0);
    }

    /**
     * 校验
     */
    @Override
    public boolean check(ByteBuf buf) {
        byte checkCode = buf.getByte(buf.readableBytes() - 1);
        buf = buf.slice(0, buf.readableBytes() - 1);
        byte calculatedCheckCode = ByteBufUtils.xor(buf);

        return checkCode != calculatedCheckCode;
    }

    /**
     * 反转义
     */
    @Override
    public ByteBuf unEscape(ByteBuf source) {
        int low = source.readerIndex();
        int high = source.writerIndex();

        int mark = source.indexOf(low, high, (byte) 0x7d);
        if (mark == -1)
            return source;

        List<ByteBuf> bufList = new ArrayList<>(3);

        int len;
        do {

            len = mark + 2 - low;
            bufList.add(slice(source, low, len));
            low += len;

            mark = source.indexOf(low, high, (byte) 0x7d);
        } while (mark > 0);

        bufList.add(source.slice(low, high - low));

        return new CompositeByteBuf(UnpooledByteBufAllocator.DEFAULT, false, bufList.size(), bufList);
    }

    /**
     * 截取转义前报文,并还原转义位
     */
    protected ByteBuf slice(ByteBuf byteBuf, int index, int length) {
        byte second = byteBuf.getByte(index + length - 1);
        if (second == 0x02)
            byteBuf.setByte(index + length - 2, 0x7e);

        // 0x01 不做处理 p47
        // if (second == 0x01) {
        // }
        return byteBuf.slice(index, length - 1);
    }
}