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<ClientServer> allClients = new LinkedList<ClientServer>();  
    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);
      }
  }  
    }
}