package com.zhtkj.jt808.server;

import java.util.concurrent.TimeUnit;

import javax.swing.JFrame;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.concurrent.Future;

/**
 * ClassName: ServerApplication 
 * @Description: 主程序及引导程序
 */
public class ServerApplication {

	private static final Logger LOGGER = LoggerFactory.getLogger(ServerApplication.class);
	
	public static AbstractApplicationContext appCtx;
	
	private volatile boolean isRunning = false;

	private int port;
	private EventLoopGroup bossGroup = null;
	private EventLoopGroup workerGroup = null;
	

	public ServerApplication(int port) {
		this.port = port;
	}

	private void bind() throws Exception {
		this.bossGroup = new NioEventLoopGroup();
		this.workerGroup = new NioEventLoopGroup();
		try {
			ServerBootstrap serverBootstrap = new ServerBootstrap();
			serverBootstrap.group(bossGroup, workerGroup)
					.channel(NioServerSocketChannel.class) 
					.childHandler(new ChannelInitializer<SocketChannel>() {
						@Override
						public void initChannel(SocketChannel ch) throws Exception {
							ch.pipeline().addLast("idleStateHandler", new IdleStateHandler(15, 0, 0, TimeUnit.MINUTES));
							//1024表示单条消息的最大长度,解码器在查找分隔符的时候,达到该长度还没找到的话会抛异常
							ch.pipeline().addLast(new DelimiterBasedFrameDecoder(2048, true, Unpooled.copiedBuffer(new byte[] { 0x7e }),
									Unpooled.copiedBuffer(new byte[] { 0x7e, 0x7e })));
							//添加业务处理handler
							ch.pipeline().addLast(new ServerHandler());
						}
					}).option(ChannelOption.SO_BACKLOG, 128)
					.childOption(ChannelOption.SO_KEEPALIVE, true);
			LOGGER.info(this.getName() + "启动完毕, 端口={}", this.port);
			ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
			channelFuture.channel().closeFuture().sync();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
            this.workerGroup.shutdownGracefully();
            this.bossGroup.shutdownGracefully();
		}
	}

	public synchronized void startServer() {
		if (this.isRunning) {
			throw new IllegalStateException(this.getName() + "已启动,不能重复启动");
		}
		this.isRunning = true;
		
		new Thread(() -> {
			try {
				this.bind();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}, this.getName()).start();
	}

	public synchronized void stopServer() {
		if (!this.isRunning) {
			throw new IllegalStateException(this.getName() + "未启动");
		}
		this.isRunning = false;

		try {
			Future<?> future = this.workerGroup.shutdownGracefully().await();
			if (!future.isSuccess()) {
			}
			future = this.bossGroup.shutdownGracefully().await();
			if (!future.isSuccess()) {
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	private String getName() {
		return "终端通讯服务端";
	}

	public static void main(String[] args) throws Exception {
		//初始化spring容器
        appCtx = new ClassPathXmlApplicationContext("applicationContext.xml");
        
        //初始化netty
		new ServerApplication(6666).startServer();
		
		//初始化窗口,这个窗口只是用来展示服务端是否启动
		JFrame frame = new JFrame();  
        frame.setTitle("终端通讯服务端(这个窗口只是用来展示服务端是否启动)");
        frame.setSize(618, 381);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	
}