package utility;
import java.util.*;
import java.io.*;
import java.net.*;




public abstract class ServerHandler implements Runnable
{


	protected Thread t = null;
  	protected Hashtable connections = new Hashtable();
	protected Hashtable connectionHandlers = new Hashtable();
  	protected Vector  ids = new Vector();
	public ServerHandler()
	{
		t=new Thread(this);
		t.start();
	}

	synchronized public Vector getConnectionsIds()
	{
    		Vector cids = new Vector();
    		Enumeration e = connections.keys();
    		while (e.hasMoreElements())
		{
      			cids.addElement((Integer)e.nextElement());
    		}
    		return cids;
  	}


  	synchronized public void addConnection(AgentIdentity id, InputStream in, OutputStream out)
	{
    		connections.put(new Integer(id.getId()), new Connection(in, out));
    		ConnectionHandler connHandler = new ConnectionHandler(id, this);
        	connectionHandlers.put(new Integer(id.getId()), connHandler);
  		ids.addElement(id);
	}


  	synchronized public   boolean removeConnection(AgentIdentity aId)
	{
		return removeConnection(aId.getId());

	}

	synchronized public boolean removeConnection(int cid)
	{
    		boolean success = false;
    		ConnectionHandler connHandler = (ConnectionHandler) connectionHandlers.remove(new Integer(cid));
		Connection conn = (Connection)connections.remove(new Integer(cid));
		if (connHandler != null && conn != null)
		{
      			connHandler.stop= true;
      			success = true;
    			/* if  some problem abt closing conn comment code below*/
			try
			{
				conn.in.close();
				conn.out.close();

			}
			catch(Exception e)
			{
				System.out.println("cudn't close connection");
				success = false;
			}
		}
		return success;
	}

  	protected synchronized Connection getConnection(int cid)
	{
    		return (Connection)connections.get(new Integer(cid));
  	}

	synchronized int getConnectionId(AgentIdentity id)
	{

    		int cid = -1;
		Enumeration e = ids.elements();
    		while (e.hasMoreElements())
		{
      			AgentIdentity aid = (AgentIdentity)e.nextElement() ;

			if(id.getLoginName().compareTo(aid.getLoginName()) == 0)
			{
				cid = aid.getId();
			}
    		}
    		return cid;
  	}

	public Request readRequest(AgentIdentity id) throws IOException
	{
    		Request req = null;

    		Connection conn = getConnection(id.getId());
    		if (conn != null)
		{
      			ClientHeader receivedRequest = null;
			synchronized (conn.in)
			{
          			ObjectInputStream objIn = null;
				try
				{
					objIn = new ObjectInputStream(conn.in);
				}
				catch (StreamCorruptedException e)
				{
					System.out.println(e + " : closing it(1)");
					removeConnection(id);
				}
				catch (Exception e)
				{
					e.printStackTrace();
				}
  				try
				{
					receivedRequest = (ClientHeader)objIn.readObject();
				}

				catch (StreamCorruptedException e)
				{
					System.out.println(e + " : closing it(2)");
					removeConnection(id);
					return null;
				}
				catch (java.lang.NullPointerException e)
				{
					System.out.println( e + " : closing it(3)");
					removeConnection(id);
					return null;
				}


				catch (SocketException e)
				{
					e.printStackTrace();
					removeConnection(id);
				}
				catch (Exception e)
				{
					e.printStackTrace();
					removeConnection(id);
				}
			}
			req = receivedRequest.getRequest();
		}
		return req;
	}


	public boolean sendResponse(ServerHeader svrHeader, int cid) throws IOException
  	{
    		boolean success = true;
    		Connection conn = getConnection(cid);
    		if (conn != null)
		{
      			//System.out.println("Trying to lock on connection" + cid);
        		synchronized (conn.out)
			{
          			//System.out.println("Got lock on connection " + cid);
          			ObjectOutputStream objOut = null;
				try
				{
					objOut = new ObjectOutputStream(conn.out);
				}
				catch (Exception e)
				{
					e.printStackTrace();
				}
				try
				{
					objOut.writeObject(svrHeader);
					objOut.flush();
				}
				catch (Exception e)
				{
					success = false;
					e.printStackTrace();
				}
				//if(success)
				//	System.out.println("writeObject successfull");
			}
		}

		return success;
	}

	public void run()
	{
	}

	public boolean broadcast(ServerHeader svrHeader) throws IOException
	{
		Enumeration cids = connections.keys();
    		boolean success = true;
    		while (cids.hasMoreElements())
		{
      			Integer id = (Integer)cids.nextElement();
      			//System.out.println("Attempting send to connection " + id.intValue());
      			if (!sendResponse(svrHeader, id.intValue()))
        			success = false;
      			
			//System.out.println("Sent message to connection " + id.intValue());
    		}
		return success;
	}

	synchronized public int nextConnectionId()
	{
		int nextId = connections.size();
		for(int i=0 ;i<connections.size();i++)
		{
			if(! connections.containsKey(new Integer(i)))
			{
				nextId = i;
				break;
			}
		}
  		return nextId;
	}
	abstract public void doThis(Request req ,AgentIdentity id);

}
