import java.awt.*; 
import java.awt.image.*; 
import java.util.*; 
import java.io.*; 
import java.net.*;
import java.awt.event.*; 
import javax.swing.*; 
import javax.swing.event.*; 
import java.awt.image.*;

/** An instance is a GUI to display and manipulate Times in a time zone. */
public class TimeZoneGUI implements ActionListener {
    
    private static int vspacer= 5; //* vertical spacing for use in Time table.
    
    /** Instruction labels*/
    private JLabel instruction1= new JLabel(" Welcome to the Time Zone GUI for A4");
    private JLabel instruction2= new JLabel(" 1. To create an object for a specific time, enter time and desired clock otuput (24 hr or AM-PM)");
    private JLabel instruction2A= new JLabel("     and click \"enter new time\". 0 will be used for empty or illegal fields.  ");
    private JLabel instruction3= new JLabel(" 2. To test legality of a time object, select the object and click \"test legality of time\".  ");
    private JLabel instruction3A= new JLabel("      It has to be > -24 hours and < 48 hours in that zone.");
    private JLabel instruction4= new JLabel(" 3. To get time object in another zone, select the time object, choose the zone,");
    private JLabel instruction4A= new JLabel("     and click \"Get selected time in selected zone\".");
    private JLabel instruction5= new JLabel(" 4. To compare two times, select them and click \"compare two selected times\".");
    private JLabel instruction5A= new JLabel("     The two times will be swapped, if necessary, so that the earliest time is first.   ");
    
    private JLabel southMessage= new JLabel("This space is for messages.");
    
    /** the JFrame that is the GUI. */
    private JFrame jf= null; 
    
    /** the button to click to input a new time in a zone */
    private JButton newTimeButton= new JButton("enter new time");
    
    /** the button to click to test the legality of the time */
    private JButton testLegalityButton= new JButton("test legality of time");
    
    /** the button to click to compare two selected times */
    private JButton compareButton= new JButton("compare two selected times");
    
    /** the button to click to get a new object with the selected time but in the selected zone. */
    private JButton getTimeInZoneButton= new JButton("Get selected time in selected zone");
    
    /** list of zones */
    private JComboBox zones= new JComboBox(Time.zones);
    
    /** Fields for inputing hours, minutes, and seconds */
    private JTextField hours= new JTextField(5);
    private JTextField minutes= new JTextField(5);
    private JTextField seconds= new JTextField(5);
    
    private static String[] outputOption= new String[]{"Output using 24-hr clock", "Output using AM-PM clock"};
    
    /** Output with 24-hour or 12-hour clock */
    private JComboBox clock24= new JComboBox(outputOption);
    
    
    /** timeButtons[i] and times[i] are the ones being displayed */
    private Vector<Time> times= new Vector();
    private Vector<JRadioButton>timeButtons= new Vector();
    private Box boxForTimes; // The box that contains all the times.
    
    
    /** Constructor: a GUI that contains:     
      * (0) a color panel, with text to describe the color.      
      * (1) the complementary color panel, with text to describe it.     
      * (2) Sliders for RGB, HSV, and CMYK.      
      * Initially, the color is red. */    
    public TimeZoneGUI() {
        getTimeInZoneButton.setAlignmentY(Component.TOP_ALIGNMENT);
        jf= new JFrame("Times in zones");        
        jf.setSize(600, 200);        
        jf.setResizable(false);
        jf.getContentPane().add(BorderLayout.WEST, buttonsFields());
        jf.getContentPane().add(BorderLayout.SOUTH, southMessage);
        
        
        jf.getContentPane().add(BorderLayout.NORTH, instructionBox());
        jf.getContentPane().add(BorderLayout.CENTER, new JLabel("             "));
        
        fixBoxForTimes();
        
        // register this object as a listener for the buttons.
        newTimeButton.addActionListener(this);
        testLegalityButton.addActionListener(this);
        compareButton.addActionListener(this);
        getTimeInZoneButton.addActionListener(this);
        
        
        jf.getContentPane().add(BorderLayout.EAST, boxForTimes);
        jf.pack();
        jf.setVisible(true);
    }
    
    /** = box of times constructed from times and timeButtons. */
    public Box boxTimes() {
        Box box= new Box(BoxLayout.Y_AXIS);
        box.add(new JLabel("Existing times"));
        for (int k= 0; k != times.size(); k= k+1) {
            Box timebox= new Box(BoxLayout.X_AXIS);
            timebox.add(timeButtons.get(k));
            timebox.add(new JLabel("  "));
            timebox.add(new JLabel(times.get(k).toString()));
        }
        return null;
    }
    
    /** = A Box with the instructions for the north panel */
    public Box instructionBox() {
        Box box= new  Box(BoxLayout.Y_AXIS);
        
        box.add(Box.createVerticalStrut(15));
        box.add(instruction1);
        box.add(Box.createVerticalStrut(15));
        box.add(instruction2);
        box.add(instruction2A);
        box.add(instruction3);
        box.add(instruction3A);
        box.add(instruction4);
        box.add(instruction4A);
        box.add(instruction5);
        
        box.add(Box.createVerticalStrut(15));
        return box;
    }
    
    /** = a Box with all the buttons and fields for input */
    public Box buttonsFields() {
        Box box= new  Box(BoxLayout.Y_AXIS);
        
        Box one= new Box(BoxLayout.X_AXIS);
        one.add(newTimeButton);
        one.add(Box.createHorizontalGlue());
        box.add(one);
        
        Box two= new Box(BoxLayout.X_AXIS);
        two.add(testLegalityButton);
        two.add(Box.createHorizontalGlue());
        box.add(two);
        
        
        
        Box tzone= new Box(BoxLayout.X_AXIS);
        tzone.add(zones);
        tzone.setMaximumSize(new Dimension(500, 50));
        tzone.add(new JLabel("time zone    "));
        tzone.add(Box.createHorizontalGlue());
        box.add(tzone);
        
        Box thours= new Box(BoxLayout.X_AXIS);
        thours.add(hours);
        hours.setMaximumSize(new Dimension(10, 40));
        thours.add(new JLabel("hours    "));
        thours.add(Box.createHorizontalGlue());
        box.add(thours);
        
        Box tmins= new Box(BoxLayout.X_AXIS);
        tmins.add(minutes);
        minutes.setMaximumSize(new Dimension(10, 40));
        tmins.add(new JLabel("minutes  "));
        tmins.add(Box.createHorizontalGlue());
        box.add(tmins);
        
        Box tsecs= new Box(BoxLayout.X_AXIS);
        tsecs.add(seconds);
        seconds.setMaximumSize(new Dimension(10, 40));
        tsecs.add(new JLabel("seconds  "));
        tsecs.add(Box.createHorizontalGlue());
        box.add(tsecs);
        
        Box box1242= new Box(BoxLayout.X_AXIS);
        box1242.add(clock24);
        clock24.setMaximumSize(new Dimension(250, 40));
        clock24.setAlignmentY(Component.LEFT_ALIGNMENT);
        box1242.add(new JLabel("          "));
        box1242.add(Box.createHorizontalGlue());
        box.add(clock24);
        
        box.add(Box.createVerticalStrut(15));
        
        
        Box fifth= new Box(BoxLayout.X_AXIS);
        fifth.add(getTimeInZoneButton);
        fifth.add(Box.createHorizontalGlue());
        box.add(fifth);
        
        box.add(Box.createVerticalStrut(15));
        
        Box sixth= new Box(BoxLayout.X_AXIS);
        sixth.add(compareButton);
        sixth.add(Box.createHorizontalGlue());
        box.add(sixth);
        
        box.add(Box.createVerticalGlue());
        return box;
    }
    
    /** Fix the box for times, to go in the east. */
    public void fixBoxForTimes() {
        boxForTimes= new Box(BoxLayout.X_AXIS);
        boxForTimes.setAlignmentY(Component.TOP_ALIGNMENT);
        
        Box leftBox= new Box(BoxLayout.Y_AXIS);
        leftBox.setAlignmentY(Component.TOP_ALIGNMENT);
        leftBox.add(new JLabel(" Select object  "));
        leftBox.add(Box.createVerticalStrut(5));
        for (int k= 0; k != times.size(); k= k+1) {
            leftBox.add(timeButtons.get(k));
        }
        boxForTimes.add(leftBox);
        
        Box midBox= new Box(BoxLayout.Y_AXIS);
        midBox.setAlignmentY(Component.TOP_ALIGNMENT);
        midBox.add(new JLabel("Java's name for object    "));
        midBox.add(Box.createVerticalStrut(5));
        for (int k= 0; k != times.size(); k= k+1) {
            midBox.add(Box.createVerticalStrut(2));
            midBox.add(new JLabel(times.get(k).objectName() + "    "));
            midBox.add(Box.createVerticalStrut(vspacer));
        }
        boxForTimes.add(midBox);
        
        Box rightBox= new Box(BoxLayout.Y_AXIS);
        rightBox.setAlignmentY(Component.TOP_ALIGNMENT);
        rightBox.add(new JLabel("Object\'s time    "));
        rightBox.add(Box.createVerticalStrut(5));
        for (int k= 0; k != times.size(); k= k+1) {
            rightBox.add(Box.createVerticalStrut(2));
            rightBox.add(new JLabel(times.get(k).toString() + "    "));
            rightBox.add(Box.createVerticalStrut(vspacer));
        }
        boxForTimes.add(rightBox);
        
        boxForTimes.add(Box.createVerticalGlue());;
    }
    
    /** Process a click of one of the buttons. They are:
      newTimeButton, testLegalityButton, compareButton,
      getTimeInZoneButton
      */     
    public void actionPerformed(ActionEvent e) {                  
        if (e.getSource() == newTimeButton) {             
            processNewTimeClick();
            return;
        }
        
        if (e.getSource() == testLegalityButton) {
           processLegalityButton();
           return;
        } 
        
        if (e.getSource() == getTimeInZoneButton) {
           processTimeInZoneButton();
           return;
        }
        
         if (e.getSource() == compareButton) {
           processCompareButton();
           return;
        }
    }
    
    /** Process click of compareButton() */
    public void processCompareButton() {
        int h= selectedButton(0);
        int k= timeButtons.size();
        if (h >= 0) {
            k= selectedButton(h+1);
        }
        if (h == timeButtons.size()  || k == timeButtons.size()) {
            southMessage.setText("You asked to compare to times, but two time objects were not selected.");
            jf.repaint();
            return;
        }
        
        Time t1= times.get(h);
        Time t2= times.get(k);
        String t1thing= t1 + " (" + t1.objectName() + ")";
        String t2thing= t2 + " (" + t2.objectName() + ")";
       
        int i= t1.compareTo(t2);
        if (i < 0) {
             southMessage.setText("Time " + t1thing + " is before time " + t2thing);
           
        } else if (i == 0) {
            southMessage.setText("Times " + t1thing +  "and " + t2thing + " are the same");
           
        } else {
            southMessage.setText("Time " + t1thing + " is after time " + t2thing);
           
        }
        
        jf.repaint();
    }
    
    /** Process click of getTimeInZoneButton */
    public void processTimeInZoneButton() {
         int h= selectedButton(0);
         if (h == timeButtons.size()) {
            southMessage.setText("You asked for a time in a different zone, but no time object is selected.");
            jf.repaint();
            return;
        }
        
        // h is the index of the first selected button
         
        int z= zones.getSelectedIndex();
        String zone= Time.GMT;
        if (z > 0)
            zone= Time.zones[z];
         
        Time t= times.get(h);
        Time newTime= t.timeInZone(zone);
        times.add(newTime);
        timeButtons.add(new JRadioButton());
        southMessage.setText("New time object " + newTime.objectName() + " created.");
        fixBoxTimes();
    }
    
    /** Process a click of testLegalityButton */
    public void processLegalityButton() {
        /** find the index of the first selected time object (length of 
          /*testLegalityButton*/
        int h= selectedButton(0);
        
        if (h == timeButtons.size()) {
            southMessage.setText("You asked for the legality of a time, but no time object is selected.");
            
            jf.repaint();
            return;
        }
        // h is the index of the first selected button 
        Time t= times.get(h);
        boolean isLegal= t.isLegal();
        southMessage.setText("The selected time, " + t.toString() + ", is " + 
                             (isLegal ? "" : "not ") + "legal.");
        
        jf.repaint();
    }
    
    /** = the index of first selected button in timeButtons[k..]
      (length of timeButtons if none) */
    public int selectedButton(int k) {
        for (int h= k; h < timeButtons.size(); h= h+1) {
            if (timeButtons.get(h).isSelected()) 
                return h;
        }
        
        return timeButtons.size();
    }
    
    /** process a click of button newTimeButton */
    private void processNewTimeClick() {
        // Get input values for hr, min, sec, and zone
        int z= zones.getSelectedIndex();
        String zone= Time.GMT;
        if (z > 0)
            zone= Time.zones[z];
        
        String hr= hours.getText();
        String mn= minutes.getText();
        String sc= seconds.getText();
        Time t= new Time(toInt(hr), toInt(mn), toInt(sc), zone, clock24.getSelectedIndex() == 0);
        times.add(t);
        timeButtons.add(new JRadioButton());
        fixBoxTimes();
        return; 
    }
    
    /** Remove the box for times from the JFrame,
       make it up again, and add it */
    public void fixBoxTimes() {
        jf.getContentPane().remove(boxForTimes);
        fixBoxForTimes();
        jf.getContentPane().add(BorderLayout.EAST, boxForTimes);
        jf.pack();
        jf.repaint();
    }
    
    /** = s as an integer.
      * If s is not an integer (possibly preceded by -), use 0. */
    public static int toInt(String s) {
        try {
            return Integer.valueOf(s);
        } catch (NumberFormatException nf) {
            return 0; 
        }
    }
}



