package com.yeejoin.amos.iec104.tcp.server;

import com.yeejoin.amos.connect.dao.entity.ConfigVo;
import org.apache.log4j.Logger;

import com.yeejoin.amos.iec104.business.service.intfc.IConfService;
import com.yeejoin.amos.iec104.context.FireAutoIntfContext;
import com.yeejoin.amos.iec104.exception.YeeException;
import com.yeejoin.amos.op.core.util.ApplicationConfig;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class IEC104Server {
	
    /**
     * boss线程池
     */
    private EventLoopGroup bossLoopGroup;

    /**
     * worker线程池
     */
    private EventLoopGroup workLoogGroup;
    /**
     * server配置
     */
    private ApplicationConfig applicationConfig;
    
    /**
     * ChannelFuture
     */
    private ChannelFuture customerChannelFuture;

    /**
     * 	监听端口
     */
    private int port;
    
    private IEC104ChannelInitalizer channelInitalizer = null;

	private Channel serverChannel;
    /**
     * 	运行tcp服务
     */
    public void start() {
    	Thread nettyServer = new Thread(() -> {

            try {
                // 创建一个serverbootstrap实例
                ServerBootstrap serverBootstrap = new ServerBootstrap();
                // BOSS线程池
                bossLoopGroup = new NioEventLoopGroup(1);
                // CPU个数
                int processorsNumber = Runtime.getRuntime().availableProcessors();
                // worker线程池
                workLoogGroup = new NioEventLoopGroup(processorsNumber * 2);
                // 指定 boss线程池、worker线程池
                serverBootstrap.group(bossLoopGroup, workLoogGroup);
                // 指定使用NIO传输Channel
                serverBootstrap.channel(NioServerSocketChannel.class);

                // 设置option
                /***
                 * BACKLOG用于构造服务端套接字ServerSocket对象，标识当服务器请求处理线程全满时，用于临时存放已完成三次握手的请求的队列的最大长度。
                 * 	如果未设置或所设置的值小于1，Java将使用默认值50。
                 */
                String backlog = applicationConfig.getParamValueStr("so.backlog");
                serverBootstrap.option(ChannelOption.SO_BACKLOG, Integer.valueOf(backlog));
                serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
                // 设置连接超时时间30秒
                serverBootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30000);
                // 设置ChannelHandler
        		IConfService confService = (IConfService) FireAutoIntfContext.getInstance().getBean(IConfService.class);
        		ConfigVo client = confService.getServerByPort(port+"");
                channelInitalizer = new IEC104ChannelInitalizer(client.getServiceId());
                serverBootstrap.childHandler(channelInitalizer);
                // 异步的绑定服务器,sync()一直等到绑定完成:绑定端口
//                customerChannelFuture = serverBootstrap.bind("100.100.100.90", port).sync();
                customerChannelFuture = serverBootstrap.bind(port).sync();
             // 将ServerChannel保存下来
    			serverChannel = customerChannelFuture.channel();
    			Logger.getLogger(this.getClass()).debug("iec104 TCP服务启动成功");
    			// 阻塞至channel关闭
    			Logger.getLogger(this.getClass()).error("service wait close");
    			serverChannel.closeFuture().sync();
            } catch (Exception e) {
                Logger.getLogger(this.getClass()).error(e);
                
                throw new YeeException("run gateway netty server error!", e, 1004001);
            } finally {
    			// 优雅关闭server线程及相关资源
            	 Logger.getLogger(this.getClass()).error("service is close");
            	workLoogGroup.shutdownGracefully();
            	bossLoopGroup.shutdownGracefully();
    		}
		});

		nettyServer.setName("netty-server-thread" + port);
		nettyServer.setDaemon(true);
		nettyServer.start();
    }

    /**
     * 	停止tcp服务
     */
    public void stop() {
        try {
        	customerChannelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            Logger.getLogger(this.getClass()).error(e);
        } finally {
            bossLoopGroup.shutdownGracefully();
            workLoogGroup.shutdownGracefully();
        }
    }

	public ApplicationConfig getApplicationConfig() {
		return applicationConfig;
	}

	public void setApplicationConfig(ApplicationConfig applicationConfig) {
		this.applicationConfig = applicationConfig;
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public void close() {
		customerChannelFuture.channel().close();
		customerChannelFuture = null;
	}
    
}
