package server.Network;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import CustomEvents.CustomEventSource;
import CustomEvents.DisconnectClientEvent;
import CustomEvents.OpenMsgClientEvent;
import server.CustomEvents.ConnectClientEvent;
import chatown.Client;
import chatown.ClientIdentityMsg;
import chatown.DisconnectMsg;
import chatown.Globals;
import chatown.OpenMsg;
public class CT_ClientSocket implements Runnable {
private CustomEventSource[] _events;
private Socket _socket;
private ObjectInputStream _inputstream;
private ObjectOutputStream _outputStream;
private Map<String, Client> _clientsMap = Collections.synchronizedMap(new HashMap<String, Client>());
private Map<String, CT_Socket> _clientsSocketMap = Collections.synchronizedMap(new HashMap<String, CT_Socket>());
private String _clientID;
public CT_ClientSocket(CustomEventSource[] events, Socket socket, Map<String, Client> clientsMap, Map<String, CT_Socket> clientsSocketMap) {
_events = events;
_socket = socket;
_clientsMap = clientsMap;
_clientsSocketMap = clientsSocketMap;
}
@Override
public void run() {
Object clientObj = null;
try {
_inputstream = new ObjectInputStream(_socket.getInputStream());
clientObj = _inputstream.readObject();
} catch (IOException e) {
e.printStackTrace();
return;
} catch (ClassNotFoundException e) {
e.printStackTrace();
return;
}
if (clientObj instanceof ClientIdentityMsg) { // new client
ClientIdentityMsg clientIdentity = (ClientIdentityMsg)clientObj;
String nickName = clientIdentity.get_nickname();
System.out.println("nick name : " + nickName);
if (clientIdentity.get_ID() != null) {
_clientID = clientIdentity.get_ID();
} else {
Random generator = new Random();
Integer clientIDInt = generator.nextInt(Integer.MAX_VALUE);
int i = 0;
while (_clientsMap.containsKey(clientIDInt.toString())) {
clientIDInt = generator.nextInt();
if (i++ > 100) return;
}
_clientID = clientIDInt.toString();
}
// send ID to client
try {
_outputStream = new ObjectOutputStream(_socket.getOutputStream());
_outputStream.writeObject(_clientID);
_outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
return;
}
Client newClient = new Client(_socket.getInetAddress().getHostName(), nickName, _clientID);
// fire CLIENT CONNECT event to update UI
clientConnected(newClient);
// add new client to list
_clientsMap.put(_clientID, newClient);
CT_Socket ctSocket = new CT_Socket(_socket, _inputstream, _outputStream);
_clientsSocketMap.put(_clientID, ctSocket);
// send messages to other clients about new client
sendClientsListToClients();
}
else if (clientObj instanceof OpenMsg) { // client sent open message
OpenMsg om = (OpenMsg)clientObj;
Client clt = _clientsMap.get(om.get_client().get_ID());
clt.inc_numOpenMsgs();
_clientsMap.put(clt.get_ID(), clt);
OpenMsg newOM = new OpenMsg(clt, om.get_msg());
if (!_clientsMap.containsKey(newOM.get_client().get_ID())) { return; } // client not found in clients list
// fire CLIENT SentOpenMsg event to update UI
clientSentOpenMsg(newOM);
sendClientsOpenMsg(newOM);
}
else if (clientObj instanceof DisconnectMsg) {
String clientID = ((DisconnectMsg)clientObj).get_client().get_ID();
if (!_clientsMap.containsKey(clientID)) { return; } // client not found in clients list
// fire CLIENT DISCONNECT event to update UI
clientDisconnected(_clientsMap.get(clientID));
_clientsMap.remove(clientID);
_clientsSocketMap.remove(clientID);
// send messages to other clients about client disconnect
sendClientsListToClients();
}
}
private void sendClientsListToClients() {
Iterator<java.util.Map.Entry<String, CT_Socket>> it = _clientsSocketMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, CT_Socket> entry = (Map.Entry<String, CT_Socket>)it.next();
try {
ObjectOutputStream out = entry.getValue().get_outputStream();
out.writeObject(_clientsMap.values().toArray());
out.flush();
} catch (IOException e) { // remove client from list because socket can't write
//st.close(); // TODO
_clientsMap.remove(entry.getKey());
it.remove();
}
}
}
private void sendClientsOpenMsg(OpenMsg om) {
Iterator<java.util.Map.Entry<String, CT_Socket>> it = _clientsSocketMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, CT_Socket> entry = (Map.Entry<String, CT_Socket>)it.next();
try {
ObjectOutputStream out = entry.getValue().get_outputStream();
out.writeObject(om);
out.flush();
} catch (IOException e) { // remove client from list because socket can't write
//st.close(); // TODO
_clientsMap.remove(entry.getKey());
it.remove();
}
}
}
private void clientConnected(Client client) {
_events[Globals.CONNECT].fireEvent(new ConnectClientEvent(this, client));
}
private void clientDisconnected(Client client) {
_events[Globals.DISCONNECT].fireEvent(new DisconnectClientEvent(this, client));
}
private void clientSentOpenMsg(OpenMsg msg) {
_events[Globals.OPEN_MSG].fireEvent(new OpenMsgClientEvent(this, msg));
}
}