package corba.RoomBookingImpl;

import java.util.*;
import java.awt.*;
import java.awt.event.*;
import org.omg.CORBA.*;
import org.omg.CosNaming.*;
import corba.RoomBooking.MaxSlots;
import corba.RoomBooking.NoMeetingInThisSlot;
import corba.RoomBooking.SlotAlreadyTaken;
import corba.common.*;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import net.jini.discovery.LookupDiscovery;
import net.jini.discovery.DiscoveryListener;
import net.jini.discovery.DiscoveryEvent;
import net.jini.core.lookup.ServiceRegistrar;
import net.jini.core.lookup.ServiceTemplate;


public class RoomBookingClient implements ActionListener, DiscoveryListener {

    private RoomBookingBridge roomBookingBridge;

    public Button viewButton;
    public Button bookButton;
    public Button cancelButton;
    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 NamingContext room_context;
    // private EasyNaming easy_naming;

    // private MeetingFactory meeting_factory;
    private JavaRoom[] rooms;
    private JavaMeeting[] meetings;

    private String ior;

    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
            orb = ORB.init( applet );
            // easy_naming = new EasyNaming( orb );
        }
        catch(SystemException system_exception ) { 
            System.err.println( "constructor RoomBookingClient: " +
                system_exception ); 
        }
	*/
    }

    // constructor for applications
    RoomBookingClient(String[] args) {

        System.setSecurityManager(new RMISecurityManager());

        LookupDiscovery discover = null;
        try {
            discover = new LookupDiscovery(LookupDiscovery.ALL_GROUPS);
        } catch(Exception e) {
            System.err.println(e.toString());
            System.exit(1);
        }

        discover.addDiscoveryListener(this);

	/*
	try {
	    roomBookingBridge = new RoomBookingBridgeImpl(args);
	} catch(RemoteException e) {
	    e.printStackTrace();
	    System.exit(1);
     	} catch(UserException e) {
	    e.printStackTrace();
	    System.exit(1);
	}
	*/
    }

    public void discovered(DiscoveryEvent evt) {

        ServiceRegistrar[] registrars = evt.getRegistrars();
 
        for (int n = 0; n < registrars.length; n++) {
            System.out.println("Service found");
            ServiceRegistrar registrar = registrars[n];

            new LookupThread(registrar).start();
        }

            // System.exit(0);
    }

    public void discarded(DiscoveryEvent evt) {
        // empty
    }

    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 );

        mainPanel = new Panel();
        titlePanel = new Panel();

        titlePanel.setLayout( new GridLayout(3,1));
        titlePanel.setFont(new Font("Helvetica", Font.BOLD, 20));
        titlePanel.setBackground( red );
        titlePanel.add( new Label("", Label.CENTER) );
        titlePanel.add( new Label("Room Booking System", Label.CENTER) );
        titlePanel.add( new Label("", Label.CENTER) );

        gui.setLayout(new BorderLayout());
        gui.add( "North", titlePanel );
        gui.add( "Center", mainPanel );
        // gui.setSize( 500, 300 );
        gui.validate();
    }

    /*
    public void init_from_ns() {

        // initialise from Naming Service
        try {
            // get room context
	    String str_name = "/BuildingApplications/Rooms/";
System.out.println("init0");
	    org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
System.out.println("init1");
	    NamingContext ncRef = NamingContextHelper.narrow(objRef);
System.out.println("init2");
	    NameComponent nc = new NameComponent(str_name,  " ");
System.out.println("init3");
	    NameComponent path[] = {nc};
    
    
	    org.omg.CORBA.Object roomRef = ncRef.resolve(path);
System.out.println("init3b");
            room_context = NamingContextHelper.narrow(roomRef);
            if( room_context == null ) {
                System.err.println( "Room context is null," );
                System.err.println( "exiting ..." );
                System.exit( 1 );
            }
System.out.println("init4");
	    
	    // System.out.println(room_context.toString());
            // get MeetingFactory from Naming Service
	    str_name = "/BuildingApplications/MeetingFactories/MeetingFactory";
	    nc = new NameComponent(str_name, " ");
	    path[0] = nc;
            meeting_factory = MeetingFactoryHelper.narrow(ncRef.resolve(path));

	    // easy_naming.resolve_from_string(
	    // "/BuildingApplications/MeetingFactories/MeetingFactory") );

            if( meeting_factory == null ) {
                System.err.println(
                    "No Meeting Factory registred at Naming Service" );
                System.err.println( "exiting ..." );
                System.exit( 1 );
            }
System.out.println("factory ok");

        }
        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() {
System.out.println("client view1");

        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
System.out.println("view4");
            room_context.list( 2, blHolder, biHolder );
System.out.println("view5");

System.out.println("rooms");
            // 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 );
            }
System.out.println("rooms got");

            // 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

	    try {
		rooms = roomBookingBridge.getRooms();
	    } catch(RemoteException e) {
		e.printStackTrace();
		rooms = new JavaRoom[0];
	    }
	    System.out.println("client got rooms, length " + rooms.length);

            Label[] r_label = new Label[rooms.length];
            slotButton =
                new Button[rooms.length][MaxSlots.value];
            booked =
                new boolean[rooms.length][MaxSlots.value];
            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].getName() );
                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();
System.out.println("getting meetings for room " + i);
		try {
		    meetings = roomBookingBridge.getMeetings(i);
		} catch(RemoteException e) {
		    e.printStackTrace();
		    meetings = new JavaMeeting[0];
		}
System.out.println("got meetings, length " + meetings.length);
                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.err.println("View: " + system_exception); 
        }
	/*
        catch(UserException naming_exception) {
            System.err.println("View: " + naming_exception);
        }
	*/
        return true;
    }

    public boolean cancel() {
	try {
	    roomBookingBridge.cancel(selected_room, selected_slot);
        } catch(NoMeetingInThisSlot no_meeting ) { 
            System.err.println("Cancel :" + no_meeting); 
        } catch(RemoteException remote) { 
            System.err.println("Cancel :" + remote); 
        }
	/*
        try {
            rooms[selected_room].Cancel(
                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 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 = roomBookingBridge.getMeetings(selected_room);
        }
        catch(SystemException system_exception ) { 
            System.err.println("meeting_details: " + system_exception ); 
	    meetings = new JavaMeeting[0];
	} catch(RemoteException e) {
	    e.printStackTrace();
	    meetings = new JavaMeeting[0];
	}
        // 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].getPurpose() ); 
        }
        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].getParticipants() ); 
        }
        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() { // modified JN
        try {
	    roomBookingBridge.book(purpose_tf.getText(),
				   participants_tf.getText(),
				   selected_room, 
				   selected_slot);
	    /*
            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(RemoteException e) {
	    e.printStackTrace();
	} 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();

        // look for free/book button pressed
        for( int i = 0; i < no_of_rooms(); i++ ) {
            for( int j = 0; j < MaxSlots.value; j++ ) {
                if( ev.getActionCommand().equals("Slot"+i+j) ) {
                    process_slot( i, j );
                }
            }
        }
    }

    class LookupThread extends Thread {

        ServiceRegistrar registrar;

        LookupThread(ServiceRegistrar registrar) {
            this.registrar = registrar;
        }


        public void run() {

            Class[] classes = new Class[] {RoomBookingBridge.class};
            ServiceTemplate template = new ServiceTemplate(null, classes, 
                                                           null);
            
            try {
		roomBookingBridge = (RoomBookingBridge) registrar.lookup(template);
            } catch(java.rmi.RemoteException e) {
                e.printStackTrace();
                System.exit(2);
	    }
            if (roomBookingBridge == null) {
                System.out.println("bridge null");
                return;
            }

	    view();
        }
    }

}
