package com.its.api.xnetudp;

import com.its.api.config.CenterCommConfig;
import com.its.api.xnetudp.codec.CenterCommServerDecoder;
import com.its.api.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 serverConfig;

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

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

        try {
            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 channel) throws Exception
                {
                    channel.pipeline().addLast("centerCommServerDecoder", new CenterCommServerDecoder());
                    channel.pipeline().addLast("centerCommServerPacketHandler", new CenterCommServerPacketHandler());
                }
            });
        }
        catch (Exception e) {
            this.log.error("UdpServerCenterComm.init: Exception: {}", e.toString());
        }

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

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

}
