package com.its.op.xnetudp;

import com.its.op.config.CenterCommConfig;
import com.its.op.global.UnitSystManager;
import com.its.op.entity.its.unit.TbUnitSyst;
import com.its.op.xnetudp.codec.CenterCommServerDecoder;
import com.its.op.xnetudp.handler.CenterCommServerPacketHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@ToString
@RequiredArgsConstructor
@Component
public class CenterCommUdpServer {

    private final CenterCommConfig centerCommConfig;

    private EventLoopGroup nioEventLoopGroup;
    private Bootstrap bootstrap;
    private boolean isThreadRunning = false;

    public void run() {
        log.info("UdpServerCenterComm.run: Start.");

        TbUnitSyst oper00 = UnitSystManager.get(this.centerCommConfig.getProcessId());
        if (oper00 != null) {
            this.centerCommConfig.setBindingPort(Integer.parseInt(oper00.getPrgmPort().trim()));
        }
        log.info("{}", this.centerCommConfig);

        this.nioEventLoopGroup = new NioEventLoopGroup();
        this.bootstrap = new Bootstrap();
        this.bootstrap.channel(NioDatagramChannel.class);
        this.bootstrap.group(this.nioEventLoopGroup);
        this.bootstrap.option(ChannelOption.SO_BROADCAST, false);
        this.bootstrap.option(ChannelOption.SO_REUSEADDR, true);
        this.bootstrap.option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(8192));
        this.bootstrap.option(ChannelOption.SO_RCVBUF, 8192);
        this.bootstrap.option(ChannelOption.SO_SNDBUF, 8192);
        this.bootstrap.handler(new ChannelInitializer<Channel>() {
            @Override
            protected void initChannel(Channel ch) {
                //ch.pipeline().addLast(new LoggingHandler(LogLevel.INFO));
                ch.pipeline().addLast("centerCommServerDecoder", new CenterCommServerDecoder());
                ch.pipeline().addLast("centerCommServerPacketHandler", new CenterCommServerPacketHandler());
            }
        });

        log.info("===============================================================");
        log.info("=  UDP Center Communication Server Start.......................");
        log.info("=  bindAddress: {}", this.centerCommConfig.getBindingAddr());
        log.info("=     bindPort: {}", this.centerCommConfig.getBindingPort());
        log.info("===============================================================");

        try {
            if (this.centerCommConfig.getBindingAddr().equals("0.0.0.0")) {
                if (isThreadRunning) {
                    this.bootstrap.bind(this.centerCommConfig.getBindingPort()).sync().channel().closeFuture().await();
                }
                else {
                    this.bootstrap.bind(this.centerCommConfig.getBindingPort());
                }
            }
            else {
                if (isThreadRunning) {
                    this.bootstrap.bind(this.centerCommConfig.getBindingAddr(), centerCommConfig.getBindingPort()).sync().channel().closeFuture().await();
                }
                else {
                    this.bootstrap.bind(this.centerCommConfig.getBindingAddr(), centerCommConfig.getBindingPort());
                }
            }
        }
        catch (InterruptedException e) {
            log.error("UdpServerCenterComm.run: Bind Exception");
            if (!isThreadRunning) {
                this.nioEventLoopGroup.shutdownGracefully();
            }
        }
        finally {
            if (isThreadRunning) {
                this.nioEventLoopGroup.shutdownGracefully();
            }
        }
        log.info("UdpServerCenterComm.run: ..End. {}", toString());
    }

}
