import java.io.*;
import java.net.*;
import java.util.*;

public class Server {
    static List<ConnectionToClient> clients = new ArrayList<>(); //모든 클라이언트
    static List<ConnectionToClient> Waiting_room = new ArrayList<>(); //대기방을 보는 곳
    static  HashMap<String,List<ConnectionToClient>> room = new HashMap<String, List<ConnectionToClient>>(); //클라이언트 들을 담는 해쉬맵 (방)
    static List<ConnectionToClient> room_out = new ArrayList<>();


    public static void main(String[] args) {
        try {
            ServerSocket server = new ServerSocket(8888);
            Socket socket = null;
            while ((socket = server.accept()) != null) {
                new ServerThread(socket).start();
            }
            server.close();
        } catch (Exception e) {
        }
    }


    static class ServerThread extends Thread {
        Socket socket;
        ConnectionToClient conToClient;
        int i = 0;

        ServerThread(Socket socket) throws IOException {
            this.socket = socket;
            this.conToClient = new ConnectionToClient(socket);


        }
        public void run() {
            try {
                String input = "";


                while( (input = conToClient.read())!=null){
                    // System.out.println(input);
                    String msgs[]=input.split("\\|");
                    String protocol = msgs[0];

                    if(protocol.equals("room")){ //만약 방을 만드는 명령어라면
                        List<ConnectionToClient> clients_for_room  = new ArrayList<>();
                        System.out.println("room : " + msgs[1]);
                        clients_for_room.add(conToClient);
                        System.out.println("clients : " + clients_for_room);
                        room.put(msgs[1],clients_for_room);
                        System.out.println("Hash : " + room);
                        clients.add(conToClient);
                        clients_for_room = null;

                    }else if(protocol.equals("location")){ //위치동기화
                        String key = msgs[1] ;
                        String loc = "location|"+msgs[2]+"|";
                        sendToAll(loc,key,"gameinfo");
                    }else if(protocol.equals("Boss_die")){ //위치동기화
                        String key = msgs[1] ;
                        String loc = "Boss_die|"+msgs[2]+"|";
                        sendToAll(loc,key,"gameinfo");
                    }else if(protocol.equals("shoot")){ //총알 동기화
                        // System.out.println("shoot ok");
                        String key = msgs[1] ;
                        String loc = "shoot|"+msgs[2]+"|";
                        sendToAll(loc,key,"shoot");
                    }else if(protocol.equals("death")){ //몬스터 위치
                        String key = msgs[1] ;
                        String loc = "death|"+msgs[2]+"|";
                        sendToAll(loc,key,"gameinfo");
                    }else if(protocol.equals("room_clear")){ //몬스터 생성
                        String key = msgs[1] ;
                        String loc = "room_clear|"+msgs[2]+"|";
                        sendToAll(loc,key,"gameinfo");
                    }else if(protocol.equals("monster_make")){ //몬스터 생성
                        String key = msgs[1] ;
                        String loc = "monster_make|"+msgs[2]+"|";
                        sendToAll(loc,key,"gameinfo");
                    }else if(protocol.equals("item_make")){ //몬스터 생성
                        String key = msgs[1] ;
                        String loc = "item_make|"+msgs[2]+"|";
                        sendToAll(loc,key,"gameinfo");
                    }else if(protocol.equals("join")){ //만약 방을 들어가려는 명령어라면
                        List<ConnectionToClient> clients_join_room  = new ArrayList<>();
                        clients_join_room =  room.get(msgs[1]);
                        clients_join_room.add(conToClient);
                        room.put(msgs[1],clients_join_room);
                        System.out.println("Hash : " + room);
                        clients.add(conToClient);
                        String key = msgs[1] ;
                        String loc = "join|"+msgs[2]+"|";
                        sendToAll(loc,key,key);
                    }
                    else if(protocol.equals("chat")){ //만약 채팅을 치려는 명령어라면
                        String key = msgs[1] ;
                        sendToAll(msgs[2],key,key);
                    } else if (protocol.equals("room_list")){ //방목록을 조회하려는 것이라면
                        System.out.println("room list okay");
                        Set<String> keys = room.keySet();
                        ArrayList<String> list = new ArrayList<String>();

                        for (String key : keys) {

                            Object o = room.get(key);
                            String a = String.valueOf(o);
                            String[] ab = a.split(",");
                            if(ab.length <2){
                                list.add(key);
                            }
                        }
                        if(list.size() <1){

                        } else{

                            sendToAll(" "+list,"room","key");
                        }

                    } else if(protocol.equals("room_list_join")){
                        Waiting_room.add(conToClient);
                    } else if(protocol.equals("room_break")){
                        String key = msgs[1] ;
                        sendToAll("delete",key,key);
                        room.remove(key);
                        System.out.println("room break , rooms left : " + room);
                    }
                    else if (protocol.equals("room_out")){
                        String key = msgs[1] ;
                        room_out  = room.get(key); //나갈 방을 새로운 리스트에 담는다.
                        room_out.remove(conToClient);
                        room.put(key, room_out);
                        System.out.println("room out, all room: " + room);
                        // sendToAll("out",key);
                    }
                    else if(protocol.equals("ID")){
                        conToClient.Make_id(msgs[1]);
                    }

                }
            } catch (Exception e) {
            }
        }

        public void sendToAll(String message, String key,String other) throws IOException{
            List<ConnectionToClient> clients_chat = new ArrayList<>();
            clients_chat = room.get(key);
            if(key.equals("room")){
                System.out.println("Send room list to clients :" + message);
                conToClient.write_sec(message);

            }else if (message.equals("delete")){
                for(ConnectionToClient client :clients_chat){
                    System.out.println("room delete");
                    client.write_sec("delete");
                }
            }else if(other.equals("gameinfo")){
                for(ConnectionToClient client :clients_chat){
                    // System.out.println("inside room : " + clients_chat);
                    client.write_sec(message);
                }
            }else if(other.equals("shoot")){
                for(ConnectionToClient client :clients_chat){
                    // long start = System.currentTimeMillis() ;
                    // long end = System.currentTimeMillis();
                    // System.out.println((end-start)/1 +" seconds" + ", data : "+ loc);
                    client.write_sec(message);
                }
            }else {
                for(ConnectionToClient client :clients_chat){
                    System.out.println("chat: " + message);
                    client.write_sec("chat|"+message);
                }

            }


        }
    }


    static class ConnectionToClient {
        Socket socket;
        BufferedReader br;
        DataOutputStream dos;
        String ID;

        ConnectionToClient(Socket socket) {
            this.socket = socket;
            try {
                br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                dos = new DataOutputStream(socket.getOutputStream());
            } catch (Exception e) {
                System.out.println(e);
            }
        }
        public String read(){
            try{

                return br.readLine();
            }catch(Exception e){
                System.out.println(e);
                return null;
            }
        }
        public void write_sec(String msg) {
            try {
                byte[] buf = new byte[1024];
                int a = msg.getBytes().length;
                String size = Integer.toString(a);
                // System.out.println(size);
                // dos.writeBytes(size);
              dos.write(msg.getBytes(), 0, msg.getBytes().length);
                dos.flush();
            } catch (Exception e) {
                System.out.println(e);
            }
        }
        public void Make_id(String id) {
            try {
                ID = id;
            } catch (Exception e) {
                System.out.println(e);
            }
        }
    }
}


