package com.wiley.compbooks.brose.chapter10.office;

/** 
 *
 * @author  brose
 * @version 
 */

import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import java.util.Calendar;

import com.wiley.compbooks.brose.chapter10.office.MeetingPackage.MeetingCancelled;
import com.wiley.compbooks.brose.chapter10.office.RoomPackage.*;

public class SecretaryGUI 
    extends javax.swing.JFrame 
    implements java.awt.event.ActionListener
{
    private java.awt.Panel mainPanel;

    /** GUI elements */

    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel monthPanel;
    private javax.swing.JPanel yearPanel;
    private javax.swing.JPanel calendarPanel;
    private javax.swing.JPanel appointmentPanel;
    private javax.swing.JPanel appointmentButtonPanel;

    private javax.swing.JButton exitButton;
    private javax.swing.JButton prevMonthButton;
    private javax.swing.JButton nextMonthButton;
    private javax.swing.JButton editAppointmentButton;
    private javax.swing.JButton deleteAppointmentButton;
    private javax.swing.JButton makeAppointmentButton;
    private JButton dayButtons[];

    private javax.swing.JLabel headingLabel;
    private javax.swing.JLabel appointmentLabel;
    private javax.swing.JLabel monthLabel;
    private javax.swing.JLabel yearLabel;

    private JList meetingList;
    private DefaultListModel meetingListModel;

    private Border emptyBorder;
    private Border lineBorder;

    /** */

    private String[] week = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };

    private String[] partners;
    private String[] locations;

    DigitalSecretaryImpl secretary;
    Diary diary;
    Date currentDate;
    Date today;
    Calendar calendar;

    private static String[] months = 
    { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };

    private static final String EMPTY = "<no appointment>";
  
    public SecretaryGUI(DigitalSecretaryImpl secretary) 
    {
	this.secretary = secretary;
	diary = secretary.getDiary();
	currentDate = diary.currentDate();
	today = currentDate;
	partners  = secretary.secretaryNames();
	locations = secretary.getLocations();
	calendar = Calendar.getInstance();

	initComponents ();  
	pack();
	show();
    }

    /** 
     * This method is called from within the constructor to
     * initialize the form.
     */

    private void initComponents () 
    {
	mainPanel = new java.awt.Panel ();

	exitButton = new JButton ();

	dayButtons = new JButton[31];
	for( int i = 0 ; i < dayButtons.length ; i++ )
	{
	    dayButtons[i] = new JButton();
	    dayButtons[i].setText("" + (i+1));
	    dayButtons[i].setActionCommand("day."+(i+1));
	    dayButtons[i].addActionListener( this );
	}

	headingLabel = new javax.swing.JLabel ();
	jPanel1 = new javax.swing.JPanel ();

	monthPanel = new javax.swing.JPanel ();
	prevMonthButton = new javax.swing.JButton ();
	nextMonthButton = new javax.swing.JButton ();
	monthLabel = new javax.swing.JLabel ();

	yearLabel = new javax.swing.JLabel ();
	yearPanel = new javax.swing.JPanel ();

	calendarPanel = new javax.swing.JPanel ();
	
	deleteAppointmentButton = new javax.swing.JButton();	
	deleteAppointmentButton.setActionCommand ("delete");
	deleteAppointmentButton.setLabel("Delete");
	deleteAppointmentButton.addActionListener(this);

	makeAppointmentButton = new javax.swing.JButton();	
	makeAppointmentButton.setActionCommand ("appoint");
	makeAppointmentButton.setLabel("New");
	makeAppointmentButton.addActionListener(this);

	editAppointmentButton = new javax.swing.JButton();	
	editAppointmentButton.setActionCommand ("edit");
	editAppointmentButton.setLabel("Edit");
	editAppointmentButton.addActionListener(this);

	appointmentPanel = new JPanel();
	appointmentPanel.setLayout(new java.awt.BorderLayout ());

	meetingListModel = new DefaultListModel();
	meetingList = new JList(meetingListModel);
	meetingList.setCellRenderer( new MeetingListCellRenderer());

	appointmentButtonPanel = new JPanel();
	appointmentButtonPanel.setLayout(new java.awt.FlowLayout ());
	appointmentButtonPanel.add( makeAppointmentButton );
	appointmentButtonPanel.add( deleteAppointmentButton );
	appointmentButtonPanel.add( editAppointmentButton );

	appointmentLabel = new JLabel();
	appointmentLabel.setText("Appointments for " + currentDateString());

	appointmentPanel.add( appointmentLabel, java.awt.BorderLayout.NORTH);
	appointmentPanel.add( new JScrollPane( meetingList ), java.awt.BorderLayout.CENTER);
	appointmentPanel.add( appointmentButtonPanel, java.awt.BorderLayout.SOUTH );	

	setTitle ("DigitalSecretary");

	addWindowListener (new java.awt.event.WindowAdapter () 
			   {
			       public void windowClosing (java.awt.event.WindowEvent evt) {
				   exitForm (evt);
			       }
			   }
			   );

	mainPanel.setBackground (new java.awt.Color (204, 204, 204));
	mainPanel.setForeground (java.awt.Color.black);
	mainPanel.setFont (new java.awt.Font ("Dialog", 0, 11));

	exitButton.setText ("exitButton");
	exitButton.setActionCommand ("exit");
	exitButton.setLabel ("Exit");
	exitButton.addActionListener (this);
	
	mainPanel.add (exitButton);
  
	getContentPane ().add (mainPanel, java.awt.BorderLayout.SOUTH);

	headingLabel.setText (secretary.name() +  "'s DigitalSecretary");
	headingLabel.setHorizontalAlignment (javax.swing.SwingConstants.CENTER);
	headingLabel.setFont (new java.awt.Font ("Arial", 1, 18));

	getContentPane ().add (headingLabel, java.awt.BorderLayout.NORTH);

	jPanel1.setLayout (new java.awt.BorderLayout ());
  
        prevMonthButton.setText ("prevMonthButton");
        prevMonthButton.setActionCommand ("prev");
        prevMonthButton.setLabel ("<");
	prevMonthButton.addActionListener( this );   

        monthPanel.add (prevMonthButton);
        monthPanel.add (monthLabel);
    
        nextMonthButton.setText ("nextMonthButton");
        nextMonthButton.setActionCommand ("next");
        nextMonthButton.setLabel (">");
    	nextMonthButton.addActionListener( this );    

        monthPanel.add (nextMonthButton);
    
	jPanel1.add (monthPanel, java.awt.BorderLayout.SOUTH);
  
        yearPanel.add (yearLabel);
    
	jPanel1.add (yearPanel, java.awt.BorderLayout.NORTH);
	
	
	emptyBorder = nextMonthButton.getBorder(); // just get any button border
	lineBorder = BorderFactory.createLineBorder( Color.blue );

	calendarPanel.setLayout (new java.awt.GridLayout (7, 7));
	setCalendarPanel();

	jPanel1.add(calendarPanel, java.awt.BorderLayout.CENTER);
  
	getContentPane ().add (jPanel1, java.awt.BorderLayout.CENTER);
	getContentPane().add (appointmentPanel, java.awt.BorderLayout.EAST);	

	updateYearMonth();
	viewDay( currentDate );
    }

    
    /** 
     * update the calendar displayed on the calendar panel 
     */

    private void setCalendarPanel()
    {
	calendarPanel.removeAll();
	calendar.set( currentDate.the_year, 
		      currentDate.the_month.value(), 
		      currentDate.the_day );

	int leading = calculateLeadingDays( calendar );
	int trailing = calculateTrailingDays(calendar);
        int daysInMonth = calendar.getActualMaximum( Calendar.DAY_OF_MONTH );

	for (int i = 0; i < 7; i++)
            calendarPanel.add(new JLabel(week[i], JLabel.CENTER));

        // Display leading blanks.
        for (int i = 0; i < leading; i++)
            calendarPanel.add(new JLabel());

	for( int i = 0 ; i < daysInMonth ; i++ )
	{
	    calendarPanel.add (dayButtons[i]);
	    if( today.the_month == currentDate.the_month &&
		i + 1 == today.the_day )
	    {
		dayButtons[i].setBackground(java.awt.Color.white);
	    }
	    else
		dayButtons[i].setBackground(java.awt.Color.lightGray);

	    if( i + 1 == currentDate.the_day )
	    {
		dayButtons[i].setBorder( lineBorder );
	    }
	    else
		dayButtons[i].setBorder( emptyBorder );	
	}

	// Display trailing blanks.
        for (int i = 0; i < trailing; i++)
            calendarPanel.add(new JLabel());  
    }

    void updateDays()
    {	
	calendar.set( currentDate.the_year, 
		      currentDate.the_month.value(), 
		      currentDate.the_day );

        int daysInMonth = calendar.getActualMaximum( Calendar.MONTH );

	for( int i = 0 ; i < daysInMonth ; i++ )
	{
	    calendarPanel.add (dayButtons[i]);
	    if( today.the_month == currentDate.the_month &&
		i + 1 == today.the_day )
	    {
		dayButtons[i].setBackground(java.awt.Color.white);
	    }
	    else
		dayButtons[i].setBackground(java.awt.Color.lightGray);

	    if( i + 1 == currentDate.the_day )
	    {
		dayButtons[i].setBorder( lineBorder );
	    }
	    else
		dayButtons[i].setBorder( emptyBorder );	
	}
    }

    void updateYearMonth()
    {
	monthLabel.setText ("Month: " + months[ currentDate.the_month.value() ] );    
        yearLabel.setText ( currentDate.the_year + "" );   
	setCalendarPanel();
    }

    private void viewDay(Date date)
    {      
	appointmentLabel.setText("Appointments for " + currentDateString());
	java.lang.Object[] meetings = diary.getDay( date.the_year,
							   date.the_month,
							   date.the_day );

	meetingListModel.clear();
	for( int i = 0; i < meetings.length; i++ )
	    meetingListModel.addElement( meetings[i]);
    }



    /** Exit the Application */
    private void exitForm(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_exitForm
	System.exit (0);
    }

    private void newMeeting()
    {
	String title = currentDateString();
	
	AppointmentDialog dialog  = 
	    new AppointmentDialog( this, true, title, partners,locations );
	
	String [] data = new String[4];
	if( dialog.getData( data ) )
	{
	    secretary.scheduleMeeting( data, currentDate );
	}
	viewDay(currentDate);    
    }

    private void deleteMeeting()
    {
	java.lang.Object o =  meetingList.getSelectedValue();
	if( o != null )
	{
	    Meeting meeting = (Meeting)o;
	    try
	    {
		diary.remove( meeting.when() );
		meeting.location().cancelBooking( meeting.when() );
	    }
	    catch( NoMeetingAtThisTime nmatt )
	    {}
	    meetingListModel.removeElement( meeting );
	}
	viewDay(currentDate);    
    }
    
    public void actionPerformed (java.awt.event.ActionEvent evt) 
    {
	try
	{
	    if( evt.getActionCommand().equals("exit"))
		SecretaryServer.shutdown();
	    else if( evt.getActionCommand().startsWith("day"))
	    {
		short day = Short.parseShort( evt.getActionCommand().substring(4));
		currentDate = new Date( currentDate.the_year, currentDate.the_month, 
					day, currentDate.the_hour );
		setCalendarPanel();
		viewDay(currentDate);
	    }
	    else if( evt.getActionCommand().equals("next"))
	    {
		if( currentDate.the_month.value() < 11 )
		{
		    currentDate = new Date( currentDate.the_year, 
					    Month.from_int( currentDate.the_month.value() + 1), 
					    currentDate.the_day, 
					    currentDate.the_hour );
		}
		else
		{
		    currentDate = new Date( currentDate.the_year + 1, 
					    Month.jan , 
					    currentDate.the_day, currentDate.the_hour );
		}
		updateDays();
		updateYearMonth();
		viewDay(currentDate);
	    }
	    else if( evt.getActionCommand().equals("prev"))
	    {
		if( currentDate.the_month.value() > 0 )
		{
		    currentDate = new Date( currentDate.the_year, 
					    Month.from_int(currentDate.the_month.value() - 1 ), 
					    currentDate.the_day, 
					    currentDate.the_hour );
		}
		else
		{
		    currentDate = new Date( currentDate.the_year - 1, 
					    Month.dec, 
					    currentDate.the_day, 
					    currentDate.the_hour );
		}
		updateDays();
		updateYearMonth();
		viewDay(currentDate);
	    }
	    else if( evt.getActionCommand().equals("appoint"))
	    {
		newMeeting();
	    }
	    else if( evt.getActionCommand().equals("delete"))
	    {    
		deleteMeeting();
	    }
	    else if( evt.getActionCommand().equals("edit"))
	    {    
		String title = currentDateString();

		AppointmentDialog dialog  = 
		    new AppointmentDialog( this, true, title, partners,locations );

		String [] data = new String[4];
		if( dialog.getData( data ) )
		{
		    deleteMeeting();
		    secretary.scheduleMeeting( data, currentDate );	  

		    java.lang.Object o =  meetingList.getSelectedValue();
		    if( o != null )
		    {
			Meeting meeting = (Meeting)o;
			try
			{
			    diary.remove( meeting.when() );
			    meeting.location().cancelBooking( meeting.when() );
			}
			catch( NoMeetingAtThisTime nmatt )
			{}
			meetingListModel.removeElement( meeting );
		    }
		}
		viewDay(currentDate);    
	    }
	}
	catch( Exception e )
	{
	    showException( e );
	}
    }

    private String currentDateString()
    {
	return currentDate.the_day + " " + 
	    months[ currentDate.the_month.value() ] + " " + currentDate.the_year;
    }


    private void showException(Exception e )
    {
	e.printStackTrace();
	JOptionPane.showMessageDialog(null, 
				      e.getClass().getName() + ":" + e.getMessage(),
				      "Exception", 
				      JOptionPane.ERROR_MESSAGE);	
    }


    /**
     * Simple utility function to get first day of month
     * for a given calendar.  For example, if it is given
     * a calendar for "April 15, 2000" it will return a
     * calendar for "April 1, 2000".
     */

    protected Calendar getCalendarForFirstDayOfMonth(Calendar calendar)
    {
        Calendar c = (Calendar) calendar.clone();
        int day = c.get(Calendar.DAY_OF_MONTH);
        c.add(Calendar.DAY_OF_MONTH, -(day - 1));
        return c;
    }

    /**
     * Simple utility function to calculate the number of
     * leading blank days to display on the calendar.
     */
    protected int calculateLeadingDays(Calendar calendar)
    {
        Calendar c = getCalendarForFirstDayOfMonth(calendar);
        int dayOfWeek = c.get(Calendar.DAY_OF_WEEK);

        if (dayOfWeek == c.getFirstDayOfWeek())
            return 0;

        int count = 0;
        for ( ; c.get(Calendar.DAY_OF_WEEK) != c.getFirstDayOfWeek(); c.add(Calendar.DAY_OF_YEAR, -1))
            count++;

        return count;
    }

    /**
     * Simple utility function to calculate the number of
     * trailing blank days to display on the calendar.
     */

    protected int calculateTrailingDays(Calendar calendar)
    {
        int leading = calculateLeadingDays(calendar);
        int daysInMonth = calendar.getActualMaximum( Calendar.DAY_OF_MONTH );
        return 42 - (leading + daysInMonth);
    }


}
