package com.jsowell.netty.decoder;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

@Slf4j
public class StartAndLengthFieldFrameDecoder extends ByteToMessageDecoder {
	// 起始标志
	private int HEAD_DATA;

	public StartAndLengthFieldFrameDecoder(int HEAD_DATA) {
		this.HEAD_DATA = HEAD_DATA;
	}

	/**
	 * <pre>
	 * 协议开始的标准head_data，int类型，占据1个字节.
	 * 表示数据的长度contentLength，int类型，占据1个字节.
	 * </pre>
	 */
	public final int BASE_LENGTH = 1 + 1;

	@Override
	protected void decode(ChannelHandlerContext ctx, ByteBuf buffer,
						  List<Object> out) throws Exception {
		System.out.println();
		// log.info("打印ByteBuf:{}", buffer.toString());
		// 可读长度必须大于基本长度
		if (buffer.readableBytes() <= BASE_LENGTH) {
			log.warn("可读字节数:{}小于基础长度:{}", buffer.readableBytes(), BASE_LENGTH);
			return;
		}

		// 记录包头开始的index
		int beginReader;

		while (true) {
			// 获取包头开始的index
			beginReader = buffer.readerIndex();
			// log.info("包头开始的index:{}", beginReader);
			// 标记包头开始的index
			buffer.markReaderIndex();
			// 读到了协议的开始标志，结束while循环
			if (buffer.getUnsignedByte(beginReader) == HEAD_DATA) {
				// log.info("读到了协议的开始标志，结束while循环 byte:{}, HEAD_DATA:{}", buffer.getUnsignedByte(beginReader), HEAD_DATA);
				break;
			}

			// 未读到包头，略过一个字节
			// 每次略过，一个字节，去读取，包头信息的开始标记
			buffer.resetReaderIndex();
			buffer.readByte();

			// 当略过，一个字节之后，
			// 数据包的长度，又变得不满足
			// 此时，应该结束。等待后面的数据到达
			if (buffer.readableBytes() < BASE_LENGTH) {
				log.info("数据包的长度不满足 readableBytes:{}, BASE_LENGTH:{}", buffer.readableBytes(), BASE_LENGTH);
				return;
			}
		}

		// 消息的长度
		int length = buffer.getUnsignedByte(beginReader + 1);
		// 判断请求数据包数据是否到齐
		if (buffer.readableBytes() < length + 4) {
			// log.info("请求数据包数据没有到齐,还原读指针 readableBytes:{}, 消息的长度:{}", buffer.readableBytes(), length);
			// 还原读指针
			buffer.readerIndex(beginReader);
			return;
		}

		// 读取data数据
		byte[] data = new byte[length + 4];
		buffer.readBytes(data);
		ByteBuf frame = buffer.retainedSlice(beginReader, length + 4);
		buffer.readerIndex(beginReader + length + 4);
		out.add(frame);
	}

}
