package net.virtuemed.jt808.codec;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
import net.virtuemed.jt808.config.JT808Const;
import net.virtuemed.jt808.util.JT808Util;
import net.virtuemed.jt808.vo.DataPacket;

/**
 * @Author: Zpsw
 * @Date: 2019-05-15
 * @Description:JT808协议编码器,转义规则: 0x7e -> 0x7d 0x02
 * 0x7d -> 0x7d 0x01
 * @Version: 1.0
 */
@Slf4j
public class JT808Encoder extends MessageToByteEncoder<DataPacket> {

    @Override
    protected void encode(ChannelHandlerContext ctx, DataPacket msg, ByteBuf out) throws Exception {
        log.debug(msg.toString());
        ByteBuf bb = msg.toByteBufMsg();
        bb.markWriterIndex();//标记一下,先到前面去写覆盖的,然后回到标记写校验码
        short bodyLen = (short) (bb.readableBytes() - 12);//包体长度=总长度-头部长度
        short bodyProps = createDefaultMsgBodyProperty(bodyLen);
        //覆盖占用的4字节
        bb.writerIndex(0);
        bb.writeShort(msg.getHeader().getMsgId());
        bb.writeShort(bodyProps);
        bb.resetWriterIndex();
        bb.writeByte(JT808Util.XorSumBytes(bb));
        log.debug(">>>>> ip:{},hex:{}\n", ctx.channel().remoteAddress(), ByteBufUtil.hexDump(bb));
        ByteBuf escape = escape(bb);
        out.writeBytes(escape);
        ReferenceCountUtil.safeRelease(escape);
    }

    /**
     * 转义待发送数据
     *
     * @param raw
     * @return
     */
    public ByteBuf escape(ByteBuf raw) {
        int len = raw.readableBytes();
        ByteBuf buf = ByteBufAllocator.DEFAULT.directBuffer(len + 12);
        buf.writeByte(JT808Const.PKG_DELIMITER);
        while (len > 0) {
            byte b = raw.readByte();
            if (b == 0x7e) {
                buf.writeByte(0x7d);
                buf.writeByte(0x02);
            } else if (b == 0x7d) {
                buf.writeByte(0x7d);
                buf.writeByte(0x01);
            } else {
                buf.writeByte(b);
            }
            len--;
        }
        ReferenceCountUtil.safeRelease(raw);
        buf.writeByte(JT808Const.PKG_DELIMITER);
        return buf;
    }

    /**
     * 生成header中的消息体属性
     *
     * @param bodyLen
     * @return
     */
    public static short createDefaultMsgBodyProperty(short bodyLen) {
        return createMsgBodyProperty(bodyLen, (byte) 0, false, (byte) 0);
    }

    public static short createMsgBodyProperty(short bodyLen, byte encType, boolean isSubPackage, byte reversed) {
        int subPkg = isSubPackage ? 1 : 0;
        int ret = (bodyLen & 0x3FF) | ((encType << 10) & 0x1C00) | ((subPkg << 13) & 0x2000)
                | ((reversed << 14) & 0xC000);
        return (short) (ret & 0xffff);
    }

}