package com.yeejoin.amos.transmit.tcp;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
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.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

public class RpcTcpServer {
    private static final String TAG = "NettyTcpServer";
    private final int port = 8888;
    private Channel channel;

    private static RpcTcpServer instance = null;
    private RpcServerListener listener;
    //    private boolean connectStatus;
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private boolean isServerStart;

    public static RpcTcpServer getInstance() {
        if (instance == null) {
            synchronized (RpcTcpServer.class) {
                if (instance == null) {
                    instance = new RpcTcpServer();
                }
            }
        }
        return instance;
    }

    private RpcTcpServer() {
    }

    public void start() {
        new Thread() {
            @Override
            public void run() {
                super.run();
                bossGroup = new NioEventLoopGroup(1);
                workerGroup = new NioEventLoopGroup();
                try {
                    ServerBootstrap b = new ServerBootstrap();
                    b.group(bossGroup, workerGroup)
                            .channel(NioServerSocketChannel.class) // 5
//                            .localAddress(new InetSocketAddress(port)) // 6
                            .option(ChannelOption.SO_BACKLOG, 128)
                            // 设置连接超时时间30秒
                            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30000)
                            .childOption(ChannelOption.SO_KEEPALIVE, true)
                            .childHandler(new ChannelInitializer<SocketChannel>() { // 7

                                @Override
                                public void initChannel(SocketChannel ch) throws Exception {
                                    ch.pipeline().addLast(new StringEncoder(CharsetUtil.UTF_8));
//                                    ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
                                    ch.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));
                                    ch.pipeline().addLast(new EchoServerHandler(listener));
                                }
                            });

                    // Bind and start to accept incoming connections.
                    ChannelFuture f = b.bind(port).sync(); // 8

                    isServerStart = true;
                    listener.onStartServer();
                    // Wait until the server socket is closed.
                    // In this example, this does not happen, but you can do that to gracefully
                    // shut down your server.
                    f.channel().closeFuture().sync(); // 9
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    isServerStart = false;
                    listener.onStopServer();
                    workerGroup.shutdownGracefully();
                    bossGroup.shutdownGracefully();
                }
            }
        }.start();

    }

    public void disconnect() {
        workerGroup.shutdownGracefully();
        bossGroup.shutdownGracefully();
    }

    public void setListener(RpcServerListener listener) {
        this.listener = listener;
    }

//    public void setConnectStatus(boolean connectStatus) {
//        this.connectStatus = connectStatus;
//    }
//
//    public boolean getConnectStatus() {
//        return connectStatus;
//    }

    public boolean isServerStart() {
        return isServerStart;
    }


    // 异步发送消息
    public boolean sendMsgToServer(String data, ChannelFutureListener listener) {
        boolean flag = channel != null && channel.isActive();
        if (flag) {
            channel.writeAndFlush(data + System.getProperty("line.separator")).addListener(listener);
        }
        return flag;
    }

    // 同步发送消息
    public boolean sendMsgToServer(String data) {
        boolean flag = channel != null && channel.isActive();
        if (flag) {
//			ByteBuf buf = Unpooled.copiedBuffer(data);
//            ByteBuf byteBuf = Unpooled.copiedBuffer(data + System.getProperty("line.separator"), //2
//                    CharsetUtil.UTF_8);
            ChannelFuture channelFuture = channel.writeAndFlush(data + System.getProperty("line.separator")).awaitUninterruptibly();
            return channelFuture.isSuccess();
        }
        return false;
    }

    public boolean sendMsgToServer(byte[] data, ChannelFutureListener listener) {
        boolean flag = channel != null && channel.isActive();
        if (flag) {
            ByteBuf buf = Unpooled.copiedBuffer(data);
            channel.writeAndFlush(buf).addListener(listener);
        }
        return flag;
    }

    /**
     * 切换通道
     * 设置服务端，与哪个客户端通信
     * @param channel
     */
    public void selectorChannel(Channel channel) {
        this.channel = channel;
    }
}
