import java.net.*;
//import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
//import java.util.Map;
import java.io.*;

public class Server {
    List allClients = new LinkedList();  
    ServerSocket server = null;
     boolean started = false;
    ClientListenner cl = null;
  
    //客户端Control + C 时发生NullPointerException,在线程ClientServer处
     public static void main(String[] args) {
   new Server().start();
    }

     /*
  * 服务器端构造函数
  * 将监听接口绑定到本地端口8888处
  */

     public Server(){
   try {
      server = new ServerSocket(8888);
  } catch (BindException e) {
      System.out.println( "端口使用中");
      System.out.println( "请关掉相关程序并重新运行服务器!");
      System.exit(0);
  } catch (IOException e) {
      e.printStackTrace();
      System.exit(0);
  }  
    }
  
     /*
  * 服务器启动函数
  */

     public void start() {
  System.out.println( "Server Starts!");
  started = true;
  cl = new ClientListenner(server);
  cl.start();
  readCommand();
    }
  
     /*
  * 服务器关闭函数
  */

     public void shutdown() {
  started = false;
  cl.close();
  System.out.println( "server shutdown");
    }

     /*
  * 读取控制台输入命令函数
  */

     public void readCommand() {
  BufferedReader br = new BufferedReader( new InputStreamReader(System.in));
  String str = null;
   try{
       while(started){
    str = br.readLine();
    excuteCommand(str);
      }
  } catch (NullPointerException e){/Control+C时发生的异常
      System.out.println( "服务器中断");
  } catch (IOException e) {
      e.printStackTrace();
  } finally {
       try{
    br.close();
      } catch (IOException e1){
    e1.printStackTrace();
      }
  }
    }
  
     /*
  * 执行控制台命令函数
  */

     public void excuteCommand(String command) {
   if (command.toLowerCase().equals( "useramount")) {
      System.out.println(getUserAmount());
  } else if (command.toLowerCase().equals( "usernames")) {
      System.out.println(getAllUserName());
  } else if (command.toLowerCase().equals( "userinfo")) {
      System.out.println(getUserInfo());
  } else if (command.toLowerCase().equals( "help")) {
      System.out.println(getHelp());
  } else if (command.toLowerCase().equals( "shutdown")){
      shutdown();
  }
    }
  
     /*
  * 获取当前服务器在线人数函数
  */

     public String getUserAmount() {
   return "当前在线用户人数为: " + allClients.size() + "\n";
    }
  
     /*
  * 获取当前服务器在线用户的名字
  */

     public String getAllUserName(){
  StringBuffer sb = new StringBuffer();
  sb.append( "当前在线用户是:");
  sb.append( "\n");
   for ( int i = 0; i < allClients.size(); i++) {
      sb.append(allClients.get(i).userName);
  }
   return sb.toString();
    }
  
     /*
  * 获取当前服务器在线用户的信息
  * 包括用户个数和用户姓名
  */

     public String getUserInfo() {
  StringBuffer sb = new StringBuffer();
  sb.append(getUserAmount());
  sb.append(getAllUserName());
   return sb.toString();
    }
  
     /*
  * 提供服务器命令信息
  */

     public String getHelp() {
  StringBuffer sb = new StringBuffer();
  sb.append( "useramount      显示当前在线用户人数\n");
  sb.append( "usernames      显示当前在线用户的名字\n");
  sb.append( "userinfo      显示当前在线用户的人数及姓名");
   return sb.toString();
    }
  
     /*
  * 监听客户端连接线程
  * 为每一个新连接的客户端提供一个服务器线程
  */

     class ClientListenner extends Thread {
  ServerSocket s = null;
  
   public ClientListenner(ServerSocket s) {
       this.s = s;
  }
  
  @Override
   public void run() {
       try{
     while (started) {
        Socket c_server = s.accept();
        ClientServer cs = new ClientServer(c_server);
        allClients.add(cs);
        System.out.println(cs.userName + "登录");
         new Thread(cs).start();
    }
      } catch (SocketException e){
    System.out.print("");//客户端关闭的时候发生异常
      } catch (IOException e){
    e.printStackTrace();
      }  
  }
  
   public void close() {
       try {
    started = false;
     if (s != null)
        s.close();
      } catch (IOException e) {
    e.printStackTrace();
      }
  }
    }

     /*
  * 服务器服务线程类
  * 接受客户端的输入,并将获得到信息发送到所有的客户端
  */

     class ClientServer implements Runnable {
  Socket c_server = null;
  ClientServer cs = null;
   boolean connected = false;
  DataOutputStream dout = null;
  DataInputStream din = null;
  String userName = null;  

   /*
   * 构造函数
   * 初始化从客户端获得的socket、建立服务器与客户端的连接、初始化输入输出流
   */

   public ClientServer(Socket s) {
      c_server = s;
      connected = true;
       try {
    din = new DataInputStream(s.getInputStream());
    dout = new DataOutputStream(s.getOutputStream());
      } catch (IOException e) {
    e.printStackTrace();
      }
      register(receiveMessage());
  }

   /*
   * 消息发送函数
   * 向客户端发送消息
   */

   public void sendMessage(String message) {
       try {
    dout.writeUTF(message);
    dout.flush();
      } catch (IOException e) {
    e.printStackTrace();
      }
  }

   /*
   * 消息接受函数
   * 从客户端接受消息
   */

   public String receiveMessage() {
      String message = null;
       try{
    message = din.readUTF();
      } catch (EOFException e){
    System.out.println( "客户端中断!");
      } catch (SocketException e){
    System.out.print("");//客户端关闭的时候发生异常
      } catch (IOException e){
    e.printStackTrace();
      }
       return message;  
  }
  
  @Override
   public void run() {
      String str = null;
    
      sendMessage( "server says:hello,I am the server!");
       while (connected) {
    str = receiveMessage();
    interpret(str);
      }
      close();
  }
  
   /*
   * 服务线程类关闭函数
   * 关闭相关输入输出流、socket
   */

   public void close() {
       try {
     if (dout != null)
        dout.close();
     if (din != null)
        din.close();
     if (c_server != null)
        c_server.close();
     if (allClients.contains( this))
        allClients.remove( this);
      } catch (IOException e) {
    e.printStackTrace();
      }  
  }

   /*
   * 消息解释函数
   * 根据消息类型选择执行相关操作
   */

   public void interpret(String str) {
       boolean bToAll = true;
       switch (strType(str)) {
       case 0:
    sendToClient(bToAll, str);
     break;
       case 1:
    bToAll = changePeople(str);
     break;
       case 2:
    excuteUserCommand(str);
     break;
       default:
     break;
      }  
  }
  
   /*
   * 注册函数
   * 服务器段记录登录用户名
   */

   private void register(String name){
      userName = name;
  }
  
   /*
   * 命令执行函数
   * 根据客户端发送过来的指令执行相关操作
   */

   private void excuteUserCommand(String str){
      String command = str.substring(1);
       if (command.equals( "userinfo")){
    sendMessage(getUserInfo());
      }
       else if(command.equals( "help")){
    sendMessage(getHelp());
      }
       else if(command.equals( "bye")){
    connected = false;
    System.out.println(userName + "退出了");
    allClients.remove( this);
      }
  }
  
   /*
   * 消息转发对象转换函数
   * 选择单对单发送消息,或者群发消息
   */

   private boolean changePeople(String str) {
      String name = str.substring(1);
       if (name.equals( "all")) {
     return true;
      } else {
     for ( int i = 0; i < allClients.size(); i++) {
         if (name.equals(allClients.get(i).userName)) {
      cs = allClients.get(i);
       return false;
        }
    }
      }
       return true;
  }
  
   /*
   * 消息解释函数
   * 根据消息起始字符调用返回整型值
   * @return 1 表示对象转换
   * @return 2 表示获取服务器信息
   * @return 0 表示正常消息发送语句
   */

   private int strType(String str){
       if (str.startsWith( "-"))
     return 1;
       else if(str.startsWith( "?"))
     return 2;
       else  
     return 0;
  }
  
   /*
   * 消息发送函数
   * 根据传入的参数,将消息传给群发或者发送给指定客户端
   */

   private void sendToClient( boolean bToAll,String str) {
       if (bToAll) {
     for ( int i = 0; i < allClients.size(); i++) {
        allClients.get(i).sendMessage( this.userName + " says: " + str);  
    }
      } else {
    cs.sendMessage(cs.userName + " says: " + str);
      }
  }  
    }
}