package org.nutz.net;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

import org.nutz.lang.Lang;
import org.nutz.log.Log;
import org.nutz.log.Logs;

/**
 * 提供一个简易的 TCP 的 socket 监听服务器
 * 
 * @author zozoh(zozohtnt@gmail.com)
 */
public class TcpServer implements Runnable {

    private static final Log log = Logs.get();

    private boolean stop;

    private int port;

    private ServerSocket listener;

    private SocketHandler handler;

    public TcpServer(int port, SocketHandler handler) {
        this.port = port;
        this.handler = handler;
    }

    protected void listen(Socket socket) {
        SocketHandler handler = getHandler();
        // 处理请求
        try {
            handler.handle(socket);
        }
        // 仅仅是关闭连接
        catch (SocketClosed e) {}
        // 停止服务
        catch (ServerStopped e) {
            stop = true;
        }
        // 处理异常
        catch (Throwable e) {
            handler.whenError(socket, e);
        }
        // 确保关闭
        finally {
            if (!socket.isClosed())
                try {
                    socket.close();
                }
                catch (IOException e) {
                    throw Lang.wrapThrow(e);
                }
        }
    }

    public void run() {
        // ----------------------------------------- 建立
        log.infof("start TcpServer [%s] @ %d", Thread.currentThread().getName(), port);
        try {
            listener = new ServerSocket(port);
        }
        catch (IOException e1) {
            throw Lang.wrapThrow(e1);
        }
        // ----------------------------------------- 循环
        log.infof("TcpServer listen @ %d", port);
        while (!stop) {
            log.info("before accept ...");
            Socket socket = null;
            try {
                socket = listener.accept();
            }
            catch (IOException e) {
                log.fatalf("Fail to accept %s @ %d , System.exit!", Thread.currentThread()
                                                                          .getName(), port);
                System.exit(0);
                return;
            }

            log.info("do listen ...");
            listen(socket);
            log.infof("done for listen [%s:%d], stop=%b",
                      socket.getInetAddress().getHostName(),
                      socket.getPort(),
                      stop);

        }
        // ----------------------------------------- 关闭
        try {
            listener.close();
            log.infof("TcpServer shutdown @ %d", port);
        }
        catch (IOException e) {
            throw Lang.wrapThrow(e);
        }
    }

    public SocketHandler getHandler() {
        return handler;
    }

    public void setHandler(SocketHandler handler) {
        this.handler = handler;
    }

    public void stop() {
        stop = true;
    }

}
