package com.its.vds.xnettcp.vds;

import com.its.app.utils.NettyUtils;
import com.its.vds.config.CommunicationConfig;
import com.its.vds.dto.TbVdsCtlrDto;
import com.its.vds.process.DbmsDataProcess;
import com.its.vds.service.AppRepositoryService;
import com.its.vds.xnettcp.vds.codec.TcpServerByteBufMessageDecoder;
import com.its.vds.xnettcp.vds.codec.VdsTcpServerEncoder;
import com.its.vds.xnettcp.vds.handler.VdsServerIdleStateHandler;
import com.its.vds.xnettcp.vds.handler.VdsServerPacketInboundHandler;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

@Slf4j
@RequiredArgsConstructor
public class VdsTcpCommServerInitializer extends ChannelInitializer<Channel> {

    private final CommunicationConfig config;
    private final DbmsDataProcess dbmsDataProcess;
    private final VdsServerPacketInboundHandler vdsServerPacketInboundHandler;
    private final VdsTcpServerEncoder vdsTcpServerEncoder;
    private final TcpServerByteBufMessageDecoder tcpServerByteBufMessageDecoder;
    private final AppRepositoryService repoService;

    @Override
    protected void initChannel(Channel channel) throws Exception {
        String ipAddress  = NettyUtils.getRemoteIpAddress(channel);
        TbVdsCtlrDto vdsObj = this.repoService.getIpAddrMap(ipAddress);
        if (vdsObj == null) {
            log.error("VdsTcpCommServerInitializer.----initChannel: {}, Unknown ip address. will be closed.", ipAddress);
            channel.disconnect();
            channel.close();
        }
        else {
            IdleStateHandler tcpIdleStateHandler = new IdleStateHandler(
                    this.config.getReaderIdleTimeSeconds(),
                    this.config.getWriterIdleTimeSeconds(),
                    this.config.getAllIdleTimeSeconds(),
                    TimeUnit.SECONDS);

            ChannelPipeline pipeline = channel.pipeline();
            if (vdsObj.getDebug().isDump()) {
                pipeline.addLast(new LoggingHandler(LogLevel.INFO));
            }
            pipeline.addLast("vdsTcpIdleStateHandler", tcpIdleStateHandler);
            pipeline.addLast("vdsServerIdleStateHandler", new VdsServerIdleStateHandler(vdsObj, this.dbmsDataProcess, this.config));   // packet idle state handler, event handler
            // CONTROLLER KIND(0 1), ADDRESS(2 3, 4 5), FRAME SEQUENCE NO(6 7), OP CODE(8), DATA LENGTH(9 10 11 12), DATA(13 ...)
            int lengthFieldOffset = 9;
            int lengthFieldLength = 4;
            int lengthAdjustment = 0;
            int initialBytesToStrip = 0;
            pipeline.addLast("vdsServerDecoder", new LengthFieldBasedFrameDecoder(Short.MAX_VALUE, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip));  // Decoding handler
            //pipeline.addLast("vdsServerPacketDecoder", this.tcpServerByteBufMessageDecoder);

            pipeline.addLast("vdsServerPacketInboundHandler", this.vdsServerPacketInboundHandler); // packet distribute handler add
            pipeline.addLast("vdsServerEncoder", this.vdsTcpServerEncoder);  // Encoding handler
        }
    }

}
