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

public abstract class ClientHandler  implements Runnable
{

	public Thread t = null;
  	protected Connection conn = null;
  	volatile boolean stop = false;




  	public ClientHandler()
	{

		t=new Thread(this);
		t.start();

	}
  	public ClientHandler(InputStream in, OutputStream out)
  	{
    		conn = new Connection(in, out);
  		t=new Thread(this);
		t.start();

	}
  	public Connection getConnection()
	{
		return conn;
	}



	synchronized public void  removeConnection()
	{
    		stop = true;
		/* if some problem later comment code below*/
		synchronized (conn)
		{
			try
			{
				conn.in.close();
				conn.out.close();
			}
			catch(Exception e)
			{
				System.out.println("cudn't close connection :" +e);
			}
		}
	}

  	public Response readResponse() throws IOException
	{
    		Response res = null;

    		if (conn != null)
		{
      			ServerHeader receivedResponse = null;
			synchronized (conn.in)
			{
          			ObjectInputStream objIn = null;
				try
				{
					objIn = new ObjectInputStream(conn.in);
				}
				catch (IOException e)
				{
					System.out.println( e + "(2)IOException : closing it");
					removeConnection();
				}
				catch (Exception e)
				{
					e.printStackTrace();
				}
  				try
				{
					receivedResponse = (ServerHeader)objIn.readObject();
				}
				catch (java.lang.NullPointerException e)
				{
					System.out.println( e + "(3)closing connection :");
					removeConnection();
					return null;
				}

				catch (Exception e)
				{
					e.printStackTrace();
					removeConnection();
					return null;
				}
			}
			res = receivedResponse.getResponse();
		}
		return res;
	}


	public boolean sendRequest(ClientHeader cliHeader) throws IOException
  	{
    		boolean success = true;
    		if (conn != null)
		{
      			boolean ok = true;
			//System.out.println("Trying to lock on connection" );
        		synchronized (conn.out)
			{
          			//System.out.println("Got lock on connection ");
          			ObjectOutputStream objOut = null;
				try
				{
					objOut = new ObjectOutputStream(conn.out);
				}
				catch(SocketException e)
				{
					System.out.println("Socket Exception :"+e);
					removeConnection();
					ok =false;
					success = false;
				}
				catch (Exception e)
				{
					e.printStackTrace();
					ok =false;
					success = false;
				}
				if(ok)
				{
					try
					{
						objOut.writeObject(cliHeader);
						objOut.flush();
					}
					catch (Exception e)
					{
						success = false;
						e.printStackTrace();
					}
				}
				//if(success)
				//	System.out.println("writeObject successfull");
			}
		}

		return success;
	}


	public void logOff(AgentIdentity id)
	{
		RemoveConnection rmc = new RemoveConnection( id);
		Request req = new Request(rmc,"RemoveConnection");
		ClientHeader toBeSent = new ClientHeader(req);
		try
		{
			sendRequest(toBeSent);
		}
		catch(Exception ex)
		{
			ex.printStackTrace();
		}

	}


	public void run()
	{
    		System.out.println("Starting connection  handler...  " );
    		while (!stop)
		{
      			try
			{
        			Response res = readResponse();
        			if(res != null)
				{
					//System.out.println("Got a response from connection ");
	        			doThis(res);
				}
      			}


			catch (Exception e)
			{
				System.out.println(e);
				e.printStackTrace();
				removeConnection();
				break;
			}
    		}
  		System.out.println("Stopping connection  handler for connection  " );
	}


	public abstract void doThis(Response res);


}
