package com.cisdi.data.HJ212.gateway;

import com.cisdi.data.common.exception.BusinessException;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

/**
 * <p>Title: 永峰HJ212协议解码</p>
 * <p>Description: 得到一个完整报文长度</p>
 *
 * @author lhp
 * @version 1.0
 * @date 2021.05.13
 */
public class Hj212FrameDecoder extends ByteToMessageDecoder {
    Logger logger = LoggerFactory.getLogger(Hj212FrameDecoder.class);
    // 包头2+数据段长度4+数据段0+CRC校验4+包尾2
    private static final short Min_Length = 12;
    private static final short Max_Length = 8192;
    private Charset charset = StandardCharsets.UTF_8;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf bufferIn, List<Object> out) throws Exception {
        try {
            if (bufferIn.readableBytes() < Min_Length) {
                return;
            }

            final int beginIndex = bufferIn.readerIndex();

            byte[] headerBytes = new byte[6];
            bufferIn.readBytes(headerBytes);

            String header = new String(headerBytes, charset);

            // 解析headerString
            String lendthString = getString(header, 2, 6);

            // 数据段长度
            int length = Integer.valueOf(lendthString);

            // 数据段长度+其他长度才是总的长度
            length += 12;

            if (length > Max_Length) {
                ctx.close();
                throw new BusinessException("超过协议允许最大报文长度，默认为 " + Max_Length + " byte，当前为" + length + "byte");
            }

            if (length < Min_Length) {
                ctx.close();
                throw new BusinessException(ctx.channel().toString() + "传输数据体长度小于12， 此长度为:" + length);
            }

            if (bufferIn.readableBytes() < length - 6) { // 拆包
                bufferIn.readerIndex(beginIndex);
                return;
            }

            bufferIn.readerIndex(beginIndex);

            ByteBuf otherByteBufRef = bufferIn.retainedSlice(beginIndex, length);

            bufferIn.readerIndex(beginIndex + length);

            out.add(otherByteBufRef);

            // 处理可能的粘包
            decode(ctx, bufferIn, out);
        } catch (Exception e) {
            logger.error("拆包过程出现异常,原始消息为:{}", bufferIn.toString(charset));
        }

    }

    private String getString(String header, int start, int end) {
        char[] dst = new char[end - start];
        header.getChars(start, end, dst, 0);

        return new String(dst);
    }
}
