//: SeatServer.java
import java.net.*;
import java.io.*;
import java.util.*;

/** Assignment
* Server for the Concert Seat Reservation System
* @author Eric Kon Yin Liang
* E-mail: [email protected]
* @version 1.0
*/
public class SeatServer extends Thread
{
	private static final int port = 1000;
	private ServerSocket Server;
	private Concert serverConcert;
	private Block[] serverBlock;
	private int ctr=1;
	

	/** Sole entry point to SeatServer class & application
	* @param args array of string arguments, arg[0]-operator name
	* @return No return value
	* @exception with throws exceptions
	*/
	public static void main(String args[])
	{
		new SeatServer();	
	}


	// SeatServer Constructor
	public SeatServer()
	{
		try {
			Server=new ServerSocket(port);
		}
		catch(IOException e){
			fail(e,"Could not start server: Could not listen on port: " + port);
		}
		//define number of seat in particular block
		serverBlock = new Block[3];
		serverBlock[0] = new Block(3,3,27.0);
		serverBlock[1] = new Block(4,6,20.0);
		serverBlock[2] = new Block(2,4,15.0);
		serverConcert = new Concert (serverBlock);
		//get all the previous status that hava been save test.txt file
		try{
			FileInputStream infile=new FileInputStream("test.txt");
			ObjectInputStream In=new ObjectInputStream(infile);
			serverConcert=(Concert)In.readObject();
		} catch(FileNotFoundException e){
			System.out.println("error");
			System.exit(-1);
		} catch(ClassNotFoundException e){
		} catch(java.io.IOException e){}
		//when server start this message will appear
		System.out.println("======================");
		System.out.println("Concert Server Started");
		System.out.println("======================");
		this.start();
	}
	
	//when the client connect to server this message will appear
	public void run()
	{
		try {
			while (true) {
				Socket client=Server.accept();
				connection con=new connection(client);
				System.out.println("");
				System.out.println("connection " + ctr + " accepted");
				System.out.println("");
				ctr=ctr+1;	
			}
		}
		catch(IOException e) {
			fail(e,"Not listening");
		}		
	}
	
		
	public static void fail(Exception e,String str)
	{
		System.err.println(str+ "." +e);
		System.exit(1);
	}

		
	class connection extends Thread
	{
		protected Socket clientsocket;
		protected BufferedReader fromclient = null;
		protected PrintWriter toclient = null;
		protected String operatorName, seatNumber, action;
		protected ConcertSeat tempSeat;
		protected boolean result=false;
		BufferedReader stdin =new BufferedReader(new InputStreamReader(System.in));

		public connection (Socket client)
		{
			clientsocket=client;
			
			try {
				fromclient=new BufferedReader(new InputStreamReader(clientsocket.getInputStream()));
				toclient = new PrintWriter(clientsocket.getOutputStream(), true);
				toclient.println("Welcome to Concert Seat Reservation System!");
			}
			catch(Exception e) {
				try {
					clientsocket.close();
				}
				catch(IOException e1){}
				System.err.println("Unable to set up steams"+e);
				return;
			}
			this.start();
		}


		/** This method is use to send the concert layout information to client
		* @param No parameter
		* @return No return
		* @exception without throws exceptions
		*/
		public void concertInfo ()
		{
			toclient.println(serverBlock.length);
			for (int count=0; count< serverBlock.length; count++) {
			     toclient.println(serverBlock[count].getRows());
				 toclient.println(serverBlock[count].getAcross());
			}				
		}


		/** This method is use to send the seat status information to client
		* @param No parameter
		* @return No return
		* @exception without throws exceptions
		*/
		public void refreshStatus ()
		{
			try {
				seatNumber = fromclient.readLine();
				tempSeat = serverConcert.getSeat(seatNumber);
				toclient.println(tempSeat.getStatus());				
			}
			catch (IOException e) {}
		}


		/** This method is use to figure out with block the particular seat belong to
		* @param String ps_seatNumber - seat number that to be figure out
		* @return int - indicate the block number
		* @exception without throws exceptions
		*/
		public int findBlock (String ps_seatNumber)
		{
			int blockIndex, seatIndex, rowIndex, rowNo = 0;
			String seatNumber;

			for(blockIndex = 0; blockIndex < serverBlock.length; blockIndex++)
				for(rowIndex = 0; rowIndex < serverBlock[blockIndex].getRows(); rowIndex ++){
					rowNo++;
					for(seatIndex = 1; seatIndex <= serverBlock[blockIndex].getAcross(); seatIndex++){
						if (new ConcertSeat(rowNo, seatIndex-1).seatNumber().compareTo(ps_seatNumber)==0)
						{
							return blockIndex;
						}
					}
				}

			return -1;
		}


		/** This method is use to process the seat reservation process
		* @param No parameter
		* @return No return
		* @exception without throws exceptions
		*/
		public void reserveSeat ()
		{
			float seatPrice = 0;
		
			tempSeat = serverConcert.getSeat(seatNumber);
			if (tempSeat.getStatus() == 0)
			{
				try	{
					System.out.print("Accept? [y/n]: ");
					if(stdin.readLine().compareTo("y")==0) {
						result = tempSeat.setStatus(1, operatorName);
						seatPrice = serverBlock[findBlock(seatNumber)].getPrice();
						if (result)
							toclient.println("Reserved Seat: " + seatNumber + " Price: " + seatPrice);
					} else 
						toclient.println("Reservation for seat " + seatNumber + " Rejected");
				}
				catch (IOException e) {}
			} else {
				toclient.println("Already reserved");
			}
		}


		/** This method is use to process the seat freeing process
		* @param No parameter
		* @return No return
		* @exception without throws exceptions
		*/
		public void freeSeat ()
		{
			tempSeat = serverConcert.getSeat(seatNumber);
			result = tempSeat.setStatus(0, operatorName);	
			if (result) 
				toclient.println("Free Seat: " + seatNumber); 
			else 
				toclient.println("Rejected");
		}


		/** This method is use to process the seat allocation process
		* @param No parameter
		* @return No return
		* @exception without throws exceptions
		*/
		public void allocateSeats ()
		{
		     ConcertSeat[] reservedSeat=serverConcert.getReservedSeats();
			 String tempName;

			 if (reservedSeat!= null) {
				for (int count=0; count< reservedSeat.length; count++) { 
					tempSeat = serverConcert.getSeat(reservedSeat[count].seatNumber());
					tempName = tempSeat.getOperator();
					if (tempName.compareTo(operatorName)==0) {
						result = tempSeat.setStatus(2, operatorName);
					}
				}
			 }
			 toclient.println("End");
		}


		/** This method is use to save the seat status information
		* @param No parameter
		* @return No return
		* @exception without throws exceptions
		*/
		public void saveData ()
		{
			try {
				FileOutputStream outfile=new FileOutputStream("test.txt");
			    ObjectOutput out=new ObjectOutputStream(outfile);
				out.writeObject(serverConcert);
				out.flush();
				out.close();
			} catch(IOException e) {
				e.printStackTrace();
			}
		}


		/** This method is use to display the active request
		* @param No parameter
		* @return No return
		* @exception without throws exceptions
		*/
		public void displayActivity ()
		{
			  System.out.println("========================");
			  System.out.println("OPERATOR NAME  : " + operatorName);
			  System.out.println("SEAT NUMBER    : " + seatNumber);
			  System.out.println("NEW SEAT STATUS: "+action); 
		}


		public void run()
		{
			String word;
	
			try {
				word = fromclient.readLine();
				while (word != null) {
					action = word;

					if (action.compareTo("Check")==0) 
						refreshStatus();
					else if (action.compareTo("BlockInfo")==0) 
						concertInfo();
					else if (action.compareTo("Allocate")==0) {
						operatorName = fromclient.readLine();
						allocateSeats();
					}
					else {
						operatorName = fromclient.readLine();
						seatNumber = fromclient.readLine();
						displayActivity();
						
						if (action.compareTo("Reserve")==0)
							reserveSeat();
						else if (action.compareTo("Free")==0)
							freeSeat();
					}

					saveData();
					word = fromclient.readLine(); 
				} //while
			}
			catch (IOException e) {}		
			finally {
				try {
               		clientsocket.close();
          		}
				catch (IOException e) {
					System.out.println("Exception while closing socket:" + e);
				}
			}
        	System.out.println("Connection completed: closed socket");
		} // public void Run
	} // Class connection
} ///:~