import java.util.Set;

import java.io.PrintWriter;

import java.util.HashMap;

import java.io.*;

import java.net.*;

import java.util.*;


public class Server {

public static void main(String[] args) {

try {

ServerSocket server = new ServerSocket(12000);

// 서버 소켓을 만

HashMap<String, PrintWriter> hm = new HashMap<String, PrintWriter>();

// hash맵<아이디, 출력빨대> 로 만듬

HashMap<String, HashMap<String, PrintWriter>> room = new HashMap<String, HashMap<String, PrintWriter>>();

// 방을 맵으로 만듬, 방해쉬맵<방제, 게스트맵>

while (true) {

System.out.println("접속대기!!");

Socket sock = server.accept();


// 소켓을 열고 대기

System.out.println("@이녀석 도킹 완으리요!  --> "

+ sock.getInetAddress());

// 접속된 아이피 보여줌

ChatThread ct = new ChatThread(sock, hm, room);

// 쓰레드에 소켓,게스트맵,룸맵을 파라미터로


ct.start();

}// while

} catch (Exception e) {

System.out.println(e);

}

}// main

}


class ChatThread extends Thread {

private Socket sock;

private HashMap<String, PrintWriter> hm;

private HashMap<String, HashMap<String, PrintWriter>> room;

private BufferedReader br;

private String id;

private PrintWriter pw = null;

private String bang = null;


// ///////-------------------------------------------------------------

public ChatThread(Socket sock, HashMap<String, PrintWriter> hm,

HashMap<String, HashMap<String, PrintWriter>> room) {

// 생성자에 sock과 HashMap 2가지(유저,룸)을 가져와서 멤버필드로 넣


this.sock = sock;

this.hm = hm;

this.room = room;


try {


pw = new PrintWriter(new OutputStreamWriter(sock.getOutputStream()));

// 서버->클라이언트 출력빨때를 소켓에 꼽음 @@@ pw @@@

br = new BufferedReader(

new InputStreamReader(sock.getInputStream()));

// 클라->서버 를 받아주는 빨대를 소켓에 꼽음 @@@ br @@@

this.id = br.readLine();

// 입력받은 id를 멤버필드에 넣어줌

String add = InetAddress.getLocalHost().getHostAddress();

System.out.println(id + "(" + add + ")" + " 님이 접속하셧습니다.");

broadcast(id + "님이 입장하셨습니다.");

synchronized (hm) {

hm.put(this.id, pw);

// synchronized를 거는 이유 : 수정이잇을시에 동시에 작용하기떄문에 오류가 날수도잇어서

// hm<아이디,서버->클라>

}

} catch (Exception e) {

System.out.println(e);

}

}// -----------------------------------------------생성자


public void run() {

boolean isinroom;

try {

String line = null;


while ((line = br.readLine()) != null) {

// 사용자에게 받은 문자를 모두에게 전달

if (line.equals("/quit")) {

pw.println("종료합니다.");

}// quit

if (line.equals("/make")) {


pw.println("방 제목을 입력하세요.");

pw.flush();

bang = br.readLine();

Set<String> um = room.keySet();

if (um.contains(bang)) {

pw.println("동일한 방제목이 존재합니다. 다시 입력해주세요.");

pw.flush();

} else {

pw.println(bang + "가 생성되었습니당!!!!!!");

pw.flush();


room.put(bang, new HashMap<String, PrintWriter>());

synchronized (hm) {

synchronized (room) {

room.get(bang).put(this.id, hm.get(this.id));

System.out.println("방 생성 이후 room -> "

+ room.size());

// Set<String> idd = room.get(bang).keySet();

broadcast(bang, id + "님께서 " + bang

+ "에 입장하심!!!");

hm.get(this.id).flush();

hm.remove(id);

System.out.println("리무브 이후 hm -> " + hm.size());

}

}

}

} else if (line.equals("/out")) {

hm.put(id, pw);

room.get(room).remove(id);

broadcast(bang, id + "님이 나가셨습니다.");

} else if (line.equals("/join")) {

pw.println("방 제목을 입력하세요");

pw.flush();

bang = br.readLine();

if (room.containsKey(bang)) {

synchronized(room){

room.get(bang).put(id, pw);

// 룸에서 벨류값에 아이디와 빨대를 넣는다

broadcast(bang, id + "님께서 입장하였습니다.");

hm.remove(this.id);

}

} else {

pw.print("해당하는 방이 없엉!!");

}

}// join

else if (line.equals("/show")) {

Set<String> hi = room.keySet();

Iterator<String> it = hi.iterator();

pw.println("현 재 존 재 하 는 방!!!!!!");

pw.flush();

if (room.keySet().size() < 1) {

pw.println("존재하는 방이 없엉!!!!!");

pw.flush();

} else {

pw.println("현재 존재하는 방은"+room.size()+"개 입니다");

while (it.hasNext()) {

pw.println(it);

pw.flush();

}

}

}// if startwith

else {

broadcast(id + " : " + line);

}

}

} catch (Exception e) {

System.out.println(e);

}

}// run


public void broadcast(String bang, String msg) {

if (room.containsKey(bang)) {

HashMap<String, PrintWriter> user = room.get(bang);

synchronized (user) {

Collection<PrintWriter> pws = user.values();

// values => return 밸류들 가져와서 전체 리턴 콜렉션 타

Iterator<PrintWriter> it = pws.iterator();

while (it.hasNext()) {

PrintWriter pwq = it.next();

pwq.println(msg);

pwq.flush();

System.out.println(msg + "\t\t <---  다보냄");

}

}

}

}


public void broadcast(String msg) {

synchronized (hm) {

Collection<PrintWriter> pws = hm.values();

// values => return 밸류들 가져와서 전체 리턴 콜렉션 타

Iterator<PrintWriter> it = pws.iterator();

while (it.hasNext()) {

PrintWriter pwq = it.next();

pwq.println(msg);

pwq.flush();

}

}

}

}


---------------------------------------------------------------------------------------------------


앰창같은 브로드캐스트에서 특정 방에만  뿌려주는거 어떻게 해야될까..

불린값을 어떻게 주면 될거같은데


그게 감이 아예 안옴;; 하... 


님들 길어서 안읽겟죠?