package com.wiley.compbooks.brose.chapter8.roomBooking;

import java.util.*;
import java.awt.*;
import java.awt.event.*;

import org.omg.CORBA.*;
import org.omg.CosNaming.*;

import com.wiley.compbooks.brose.chapter8.roomBooking.RoomPackage.*;

public class RoomBookingClient 
    implements ActionListener 
{
    public Button viewButton;
    public Button bookButton;
    public Button cancelButton;
    public Button exitButton;
    public Button[][] slotButton;

    private TextField participants_tf;
    private TextField purpose_tf;

    private Panel mainPanel;
    private Panel titlePanel;

    private boolean[][] booked;

    private int selected_room;
    private int selected_slot;

    private ORB orb;
    private NamingContextExt root_context;
    private NamingContextExt room_context;

    private MeetingFactory meeting_factory;
    private Room[] rooms;
    private Meeting[] meetings;

    private String ior;
    private boolean is_application = true;

    Color green = new Color( 0, 94, 86 );
    Color red = new Color( 255, 61, 61 );

    /** constructor for applets */ 
    RoomBookingClient( java.applet.Applet applet ) 
    {
        try 
		{
            // initialise the ORB
			java.util.Properties props = new java.util.Properties();
			props.put("org.omg.CORBA.ORBClass","jacorb.orb.ORB");
			props.put("org.omg.CORBA.ORBSingletonClass","jacorb.orb.ORBSingleton");

			orb = ORB.init( applet, null );
			System.out.println("ORB " + orb.getClass().getName() );

			ior = applet.getParameter("NameServer");
			root_context = 
				NamingContextExtHelper.narrow( orb.resolve_initial_references("NameService") );

			if( root_context == null )
				throw new RuntimeException("No root context for " + ior);
			else
				System.out.println("Found context at " + ior );
			is_application = false;
        }
        catch(Exception system_exception ) { 
			system_exception.printStackTrace();
            throw new RuntimeException( "constructor RoomBookingClient: " +
                system_exception ); 
        }
    }

    /** constructor for applications */
    RoomBookingClient() 
    {
        try 
	{
            // initialise the ORB
            orb = ORB.init((java.lang.String[])null, null);
	    root_context = 
		NamingContextExtHelper.narrow( orb.resolve_initial_references("NameService"));
        }
        catch(Exception system_exception ) 
	{ 
            System.err.println( "constructor RoomBookingClient: " +
                system_exception ); 
        }
    }

    public int no_of_rooms() {
        return rooms.length;
    }

    public void init_GUI( java.awt.Container gui ) {

        // initialise widgets

        gui.setBackground( Color.white );

        viewButton = new Button("Back");
        viewButton.setFont(new Font("Helvetica", Font.BOLD, 14));
        viewButton.setBackground( red );
        viewButton.setActionCommand("View");
        viewButton.addActionListener( (ActionListener) this );

        bookButton = new Button("Book");
        bookButton.setFont(new Font("Helvetica", Font.BOLD, 14));
        bookButton.setBackground( red );
        bookButton.setActionCommand("Book");
        bookButton.addActionListener( (ActionListener) this );

        cancelButton = new Button("Cancel");
        cancelButton.setFont(new Font("Helvetica", Font.BOLD, 14));
        cancelButton.setBackground( red );
        cancelButton.setActionCommand("Cancel");
        cancelButton.addActionListener( (ActionListener) this );

		exitButton = new Button("Exit");
		exitButton.setFont(new Font("Helvetica", Font.BOLD, 14));
		exitButton.setBackground( red );
		exitButton.setActionCommand("Exit");
		exitButton.addActionListener( (ActionListener) this );	

        mainPanel = new Panel();
        titlePanel = new Panel();

        titlePanel.setLayout( new GridLayout(2,3));
        titlePanel.setFont(new Font("Helvetica", Font.BOLD, 20));
        titlePanel.setBackground( red );
		// first row
        titlePanel.add( new Label("", Label.CENTER) );
        titlePanel.add( new Label("Room Booking System", Label.CENTER) );
        titlePanel.add( new Label("", Label.CENTER) );
		// second row
		titlePanel.add( new Label("", Label.CENTER) );
		// exit button only for applications
		if( is_application )
		{
			titlePanel.add( exitButton );
		}
		else
			titlePanel.add( new Label("", Label.CENTER) );

		titlePanel.add( new Label("", Label.CENTER) );

        gui.setLayout(new BorderLayout());
        gui.add( "North", titlePanel );
        gui.add( "Center", mainPanel );
        gui.setSize( 700, 300 );
        gui.validate();
    }

    /** initialise from Naming Service */

    public void init_from_ns() {
        try {
            System.out.println("Resolving BuildingApplications/Rooms" ); 

	    org.omg.CORBA.Object o = root_context.resolve_str("BuildingApplications/Rooms" );
            // get room context
            room_context = NamingContextExtHelper.narrow(o);

            if( room_context == null ) {
                System.err.println( "Room context is null," );
                System.err.println( "exiting ..." );
                System.exit( 1 );
            }

            // get MeetingFactory from Naming Service
            meeting_factory = MeetingFactoryHelper.narrow(
                root_context.resolve_str(
                "BuildingApplications/MeetingFactory") );

            if( meeting_factory == null ) {
                System.err.println(
                    "No Meeting Factory registered at Naming Service" );
                System.err.println( "exiting ..." );
                System.exit( 1 );
            }
        }
        catch(SystemException system_exception ) {
 
            System.err.println( "Initialise ORB: " + system_exception ); 
	    system_exception.printStackTrace();
        }
        catch(UserException naming_exception) {
            System.err.println( "Initialise ORB: " +  naming_exception );
	    naming_exception.printStackTrace();

        }
    }

    public boolean view() {

        try {
            // list rooms
            // initialise binding list and binding iterator
            // Holder objects for out parameter
            BindingListHolder blHolder = new BindingListHolder();
            BindingIteratorHolder biHolder = new BindingIteratorHolder();
            BindingHolder bHolder = new BindingHolder();
            Vector roomVector = new Vector();
            Room aRoom;
    
            // we are 2 rooms via the room list
            // more rooms are available from the binding iterator
            room_context.list( 2, blHolder, biHolder );

            // get rooms from Room context of the Naming Service
            // and put them into the roomVector
            for( int i = 0; i < blHolder.value.length; i++ ) {
                aRoom = RoomHelper.narrow(
                    room_context.resolve( blHolder.value[i].binding_name ));
                roomVector.addElement( aRoom );
            }

            // get remaining rooms from the iterator
            if( biHolder.value != null ) {
                while( biHolder.value.next_one( bHolder ) ) {
                    aRoom = RoomHelper.narrow(
                        room_context.resolve( bHolder.value.binding_name ) );
                    if( aRoom != null ) {
                        roomVector.addElement( aRoom );
                    }
                }
            }

            // convert the roomVector into a room array
            rooms = new Room[ roomVector.size() ];
            roomVector.copyInto( rooms );

            // be fiendly with system resources
            if(  biHolder.value != null )
                biHolder.value.destroy();
    
            // create lables and slots according to the number of rooms
            Label[] r_label = new Label[rooms.length];
            slotButton =
                new Button[rooms.length][Room.MaxSlots];
            booked =
                new boolean[rooms.length][Room.MaxSlots];
            mainPanel.removeAll();
    
            // define layout for the table
            GridBagLayout gridbag = new GridBagLayout();
            GridBagConstraints c = new GridBagConstraints();
            mainPanel.setLayout(gridbag);
    
            c.fill = GridBagConstraints.BOTH;
    
            c.gridwidth = 2;
            c.gridheight = 1;
            Label room_label = new Label("Rooms", Label.CENTER );
            room_label.setFont(new Font("Helvetica", Font.BOLD, 14));
            gridbag.setConstraints( room_label, c);
            mainPanel.add( room_label );
    
            c.gridwidth = 4;
            c.gridheight = 1;
            Label  am_label = new Label("AM", Label.CENTER );
            am_label.setFont(new Font("Helvetica", Font.BOLD, 14));
            gridbag.setConstraints( am_label, c);
            mainPanel.add( am_label );
    
            c.gridheight = 1;
            c.gridwidth = GridBagConstraints.REMAINDER;
            Label  pm_label = new Label("PM", Label.CENTER );
            pm_label.setFont(new Font("Helvetica", Font.BOLD, 14));
            gridbag.setConstraints( pm_label, c);
            mainPanel.add( pm_label );
    
            c.gridwidth = 2;
            c.gridheight = 1;
            Label  e_label = new Label("");
            gridbag.setConstraints( e_label, c);
            mainPanel.add( e_label );
    
            c.gridwidth = 1;
            c.gridheight = 1;
            Label  label9 = new Label(" 9", Label.CENTER );
            label9.setFont(new Font("Helvetica", Font.BOLD, 14));
            gridbag.setConstraints( label9, c);
            mainPanel.add( label9 );
    
            c.gridwidth = 1;
            c.gridheight = 1;
            Label  label10 = new Label("10", Label.CENTER );
            label10.setFont(new Font("Helvetica", Font.BOLD, 14));
            gridbag.setConstraints( label10, c);
            mainPanel.add( label10 );
    
            c.gridwidth = 1;
            c.gridheight = 1;
            Label  label11 = new Label("11", Label.CENTER );
            label11.setFont(new Font("Helvetica", Font.BOLD, 14));
            gridbag.setConstraints( label11, c);
            mainPanel.add( label11 );
    
            c.gridwidth = 1;
            c.gridheight = 1;
            Label  label12 = new Label("12", Label.CENTER );
            label12.setFont(new Font("Helvetica", Font.BOLD, 14));
            gridbag.setConstraints( label12, c);
            mainPanel.add( label12 );
    
            c.gridwidth = 1;
            c.gridheight = 1;
            Label  label1 = new Label(" 1", Label.CENTER );
            label1.setFont(new Font("Helvetica", Font.BOLD, 14));
            gridbag.setConstraints( label1, c);
            mainPanel.add( label1 );
    
            c.gridwidth = 1;
            c.gridheight = 1;
            Label  label2 = new Label(" 2", Label.CENTER );
            label2.setFont(new Font("Helvetica", Font.BOLD, 14));
            gridbag.setConstraints( label2, c);
            mainPanel.add( label2 );
    
            c.gridwidth = 1;
            c.gridheight = 1;
            Label  label3 = new Label(" 3", Label.CENTER );
            label3.setFont(new Font("Helvetica", Font.BOLD, 14));
            gridbag.setConstraints( label3, c);
            mainPanel.add( label3 );
    
            c.gridwidth = GridBagConstraints.REMAINDER;
            c.gridheight = 1;
            Label  label4 = new Label(" 4", Label.CENTER );
            label4.setFont(new Font("Helvetica", Font.BOLD, 14));
            gridbag.setConstraints( label4, c);
            mainPanel.add( label4 );
    
            // show the lable with the room name
            for( int i = 0; i < rooms.length; i++ ) {
                c.gridwidth = 2;
                c.gridheight = 1;
                r_label[i] = new Label( rooms[i].name() );
                r_label[i].setFont(new Font("Helvetica", Font.BOLD, 14));
                gridbag.setConstraints( r_label[i], c);
                mainPanel.add( r_label[i] );
    
                // call view operation on the i-th room object and
                // create book or free button
                meetings = rooms[i].view();
                c.gridheight = 1;
                for( int j = 0; j < meetings.length; j++ ) {
                    if( j == meetings.length - 1 )
                        c.gridwidth = GridBagConstraints.REMAINDER;
                    else
                        c.gridwidth = 1;
                    if( meetings[j] == null ) {
                        // slot is free
                        slotButton[i][j] = new Button("Book");
                        slotButton[i][j].setBackground( green );
                        slotButton[i][j].setForeground( Color.white );
                        slotButton[i][j].setFont(new Font("Helvetica",
                             Font.BOLD, 14));
                        slotButton[i][j].setActionCommand("Slot"+i+j);
                        slotButton[i][j].addActionListener( (ActionListener) this );
                        booked[i][j] = false; 
                    }
                    else {
                        // slot is booked - view or cancel
                        slotButton[i][j] = new Button("View");
                        slotButton[i][j].setBackground( red );
                        slotButton[i][j].setFont(new Font("Helvetica",
                             Font.BOLD, 14));
                        slotButton[i][j].setActionCommand("Slot"+i+j);
                        slotButton[i][j].addActionListener( (ActionListener) this );
                        booked[i][j] = true; 
                    }
                    gridbag.setConstraints( slotButton[i][j], c);
                    mainPanel.add( slotButton[i][j] ); 
                } 
            }
    
            c.gridwidth = 4;
            c.gridheight = 1;
            Label  e1_label = new Label("");
            gridbag.setConstraints( e1_label, c);
            mainPanel.add( e1_label );
    
            c.gridheight = 1;
            c.gridwidth = GridBagConstraints.REMAINDER;
            Label  e2_label = new Label("");
            gridbag.setConstraints( e2_label, c);
            mainPanel.add( e2_label );
    
            c.gridheight = 1;
            c.gridwidth = GridBagConstraints.REMAINDER;
            Label  e3_label = new Label("");
            gridbag.setConstraints( e3_label, c);
            mainPanel.add( e3_label );
    
            mainPanel.validate();
        }
    
        catch(SystemException system_exception) { 
	    system_exception.printStackTrace();
            System.err.println("View: " + system_exception); 
        }
        catch(UserException naming_exception) {
	    naming_exception.printStackTrace();
            System.err.println("View: " + naming_exception);
        }
        return true;
    }

    public boolean cancel() {
        try {
            rooms[selected_room].cancelBooking(
                Slot.from_int(selected_slot) );
            System.out.println("Cancel called" ); 
        }
        catch(NoMeetingInThisSlot no_meeting ) { 
            System.err.println("Cancel :" + no_meeting ); 
        }
        catch(SystemException system_exception) { 
            System.err.println("Cancel :" + system_exception); 
        }

        // show bookings of all rooms
        return view();
    }

    public void exit() 
    {       
	System.exit(0);
    }

    public boolean process_slot( int _selected_room, int _selected_slot ) {

        selected_room = _selected_room;
        selected_slot = _selected_slot;

        if( booked[selected_room][selected_slot] ) {
            // view the meeting details, potentially cancel
            meeting_details(); 
        }
        else {
            // get meeting details and book
            booking_form(); 
        }
        return true;
    }

    public boolean meeting_details() {

        // clean main panel
        mainPanel.removeAll();

        // call view operation on the selected room
        try {
            meetings = rooms[selected_room].view(); 
        }
        catch(SystemException system_exception ) { 
            System.err.println("meeting_details: " + system_exception ); 
        }

        // create new form for displaying meeting details
        GridBagLayout gridbag = new GridBagLayout();
        GridBagConstraints c = new GridBagConstraints();
        mainPanel.setLayout(gridbag);

        c.gridwidth = GridBagConstraints.REMAINDER; 
        Label header_label = new Label("Meeting details");
        gridbag.setConstraints( header_label, c);
        mainPanel.add(  header_label );

        c.gridwidth = 1;
        c.gridheight = 1;
        c.fill = GridBagConstraints.BOTH;
        Label purpose_label = new Label("Purpose: ");
        gridbag.setConstraints( purpose_label, c);
        mainPanel.add(  purpose_label );

        c.gridheight = 1;
        c.gridwidth = 2;
        c.gridwidth = GridBagConstraints.REMAINDER; 
        purpose_tf = new TextField();
        purpose_tf.setEditable(false);
        try {
            purpose_tf.setText( meetings[selected_slot].purpose() ); 
        }
        catch(SystemException system_exception) { 
            System.err.println(system_exception); 
        }
        gridbag.setConstraints( purpose_tf, c);
        mainPanel.add(  purpose_tf );

        c.gridwidth = 1;
        c.gridheight = 1;
        c.fill = GridBagConstraints.BOTH;
        Label participants_label = new Label("Participants: ");
        gridbag.setConstraints( participants_label, c);
        mainPanel.add(  participants_label );

        c.gridheight = 1;
        c.gridwidth = 2;
        c.gridwidth = GridBagConstraints.REMAINDER; 
        participants_tf = new TextField();
        participants_tf = new TextField();
        participants_tf.setEditable(false);
        try {
            participants_tf.setText(
                meetings[selected_slot].participants() ); 
        }
        catch(SystemException system_exception) { 
            System.err.println(system_exception); 
        }
        gridbag.setConstraints( participants_tf, c);
        mainPanel.add(  participants_tf );

        c.gridheight = 1;
        c.gridwidth = 3;
        c.gridwidth = GridBagConstraints.REMAINDER; 
        gridbag.setConstraints( viewButton, c);
        mainPanel.add( viewButton );

        gridbag.setConstraints( cancelButton, c);
        mainPanel.add( cancelButton );

        mainPanel.validate();
        // mainPanel.repaint();
        return true;
    }

    public void booking_form() {

        // clean main panel
        mainPanel.removeAll();

        GridBagLayout gridbag = new GridBagLayout();
        GridBagConstraints c = new GridBagConstraints();
        mainPanel.setLayout(gridbag);

        c.gridwidth = GridBagConstraints.REMAINDER; 
        Label header_label = new Label(
            "Please, enter details of the meeting.");
        gridbag.setConstraints( header_label, c);
        mainPanel.add(  header_label );

        c.gridwidth = 1;
        c.gridheight = 1;
        c.fill = GridBagConstraints.BOTH;
        Label purpose_label = new Label("Purpose: ");
        gridbag.setConstraints( purpose_label, c);
        mainPanel.add(  purpose_label );

        c.gridheight = 1;
        c.gridwidth = 2;
        c.gridwidth = GridBagConstraints.REMAINDER; 
        purpose_tf = new TextField();
        gridbag.setConstraints( purpose_tf, c);
        mainPanel.add(  purpose_tf );

        c.gridwidth = 1;
        c.gridheight = 1;
        c.fill = GridBagConstraints.BOTH;
        Label participants_label = new Label("Participants: ");
        gridbag.setConstraints( participants_label, c);
        mainPanel.add(  participants_label );

        c.gridheight = 1;
        c.gridwidth = 2;
        c.gridwidth = GridBagConstraints.REMAINDER; 
        participants_tf = new TextField();
        gridbag.setConstraints( participants_tf, c);
        mainPanel.add(  participants_tf );

        c.gridwidth = GridBagConstraints.REMAINDER; 
        gridbag.setConstraints( bookButton, c);
        mainPanel.add(  bookButton );
        mainPanel.validate();
        // mainPanel.repaint();
    }

    public boolean book() {
        try {
            Meeting meeting =
                meeting_factory.createMeeting(
                    purpose_tf.getText(),
                    participants_tf.getText() );
            System.out.println( "meeting created" );
            String p = meeting.purpose();
            System.out.println("Purpose: "+p);
            rooms[selected_room].book(
                Slot.from_int(selected_slot), meeting );
            System.out.println( "room is booked" ); 
        }
        catch(SlotAlreadyTaken  already_taken ) { 
            System.err.println( "book :" + already_taken ); 
        }
        catch(SystemException system_exception ) { 
            System.err.println( "book :" + system_exception ); 
        }
       
        // show bookings of all rooms
        return view();
    }

    /** catch and process events */

    public void actionPerformed( ActionEvent ev ) 
    {

        if(ev.getActionCommand().equals("View"))
            view();
        if(ev.getActionCommand().equals("Book"))
            book();
        if(ev.getActionCommand().equals("Cancel"))
            cancel();
        if(ev.getActionCommand().equals("Exit"))
            exit();

        // look for free/book button pressed
        for( int i = 0; i < no_of_rooms(); i++ ) 
        {
            for( int j = 0; j < Room.MaxSlots; j++ ) 
            {
                if( ev.getActionCommand().equals("Slot"+i+j) ) 
                {
                    process_slot( i, j );
                }
            }
        }
    }

}
