package com.tsi.app.common.xnet;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Data
public abstract class NettyTcpServer {

    private final NettyServerConfig config;

    private EventLoopGroup acceptGroups = null;
    private EventLoopGroup workerGroups = null;
    private ServerBootstrap serverBootstrap = null;
    private ChannelFuture channelFuture = null;

    private ChannelInitializer<Channel> channelInitializer;

    public NettyTcpServer(NettyServerConfig config) {
        this.config = config;
    }

    public void run() {

        try {
            if (NettyUtils.isEpollAvailable()) {
                log.info("서버가 리눅스 EPOLL 모드에서 실행됩니다.");
            }
            else {
                log.info("서버가 윈도우 NIO 모드에서 실행됩니다.");
            }

            this.serverBootstrap = ServerBootstrapFactory.createBootstrap(this.config, this.channelInitializer);

        } catch (Exception e) {
            e.printStackTrace();
        }

        log.info("  bindAddress: {}", this.config.getBindingAddr());
        log.info("     bindPort: {}", this.config.getBindingPort());
        log.info("      backlog: {}", this.config.getBacklog());
        log.info("acceptThreads: {}", this.config.getAcceptThreads());
        log.info("workerThreads: {}", this.config.getWorkerThreads());

        try {
            if (this.config.getBindingAddr().equals("0.0.0.0")) {
                this.channelFuture = this.serverBootstrap.bind(this.config.getBindingPort());
            }
            else {
                this.channelFuture = this.serverBootstrap.bind(this.config.getBindingAddr(), config.getBindingPort());
            }
        }
        catch (Exception e) {
            log.error("{}", e.toString());
            this.acceptGroups.shutdownGracefully();
            this.workerGroups.shutdownGracefully();
        }
    }

    public void stop() {
        try {
            this.acceptGroups.shutdownGracefully().sync();
            this.workerGroups.shutdownGracefully().sync();
            this.channelFuture.channel().closeFuture().sync();
        }
        catch (InterruptedException e) {
            log.error("{}", e.toString());
            e.printStackTrace();
        }
    }
}
