import java.awt.*;
import java.awt.event.*;
 
/**
 * CSC 442F:    Software Engineering
 * Software:    Calendar Client
 * Component:   YYmmddPanel class
 * Description: The YYmmddPanel class produces an yymmdd panel. This panel
 *              accepts date input from the user. It also enforces type
 *              restrictions.
 *
 * @author David Tam
 * @version 1.0
 */
public class YYmmddPanel extends Panel implements TextListener
{ 
  protected Frame frame;
  protected EventId eventId;

  // Labels
  protected Label year;
  protected Label month;
  protected Label day;

  // Textfields
  protected TextField yearTxt;
  protected TextField monthTxt;
  protected TextField dayTxt;

  // GridBagLayout constraints
  protected GridBagConstraints constraints;

 /**
  * Constructor 1 -- Create panel with specific values
  * =============
  *
  * @param eventId_in   Used to set specific values for yymmdd fields.
  * @param frame_in     Frame of the calling function. This is required
  *                     when creating a HelpBox that displays errors.
  *                     (HelpBox is a kind of Dialog box);
  */
  public YYmmddPanel (Frame frame_in, EventId eventId_in)
  {
    eventId = eventId_in;
    basicInit(frame_in);
    fillSpecific();
    arrange();
  }
  

 /**
  * Constructor 2 -- Create panel with empty values
  * =============
  *
  * @param frame_in     Frame of the calling function. This is required
  *                     when creating a HelpBox that displays errors.
  *                     (HelpBox is a kind of Dialog box);
  */
  public YYmmddPanel (Frame frame_in)
  {
    basicInit(frame_in);
    arrange();
  }
  
  
 /**
  * Method to perform basic initialization
  * ======================================
  *
  * @param frame_in     Frame of the calling function. This is required
  *                     when creating a HelpBox that displays errors.
  *                     (HelpBox is a kind of Dialog box);
  */
  protected void basicInit(Frame frame_in)
  {
    frame = frame_in;

    // Label instantiation
    year = new Label("Year");
    month = new Label("Month");
    day = new Label("Day");

    // Text input instantiation
    yearTxt = new TextField(4);
    monthTxt = new TextField(2);
    dayTxt = new TextField(2);

    // Constraints instantiation
    constraints = new GridBagConstraints();   

    // Text event receivers
    yearTxt.addTextListener(this);
    monthTxt.addTextListener(this);
    dayTxt.addTextListener(this);
  }

  
 /**
  * Function that enters specific values into fields
  * ================================================
  */
  protected void fillSpecific()
  {
    if (eventId.year.length()!=0)
      yearTxt.setText(eventId.year);
    if (eventId.month.length()!=0)
      monthTxt.setText(eventId.month);
    if (eventId.day.length()!=0)
      dayTxt.setText(eventId.day);
  }


 /**
  * Function that does layout of panel
  * ==================================
  */
  protected void arrange()
  {
    // yymmddPanel layout
    setLayout(new GridBagLayout());
    constraints.gridx=0;
    constraints.gridy=0;
    constraints.anchor=constraints.WEST;
    add(year, constraints);
    constraints.gridx=1;
    add(month, constraints);
    constraints.gridx=2;
    add(day, constraints);
    constraints.gridy=1;
    constraints.gridx=0;
    add(yearTxt, constraints);
    constraints.gridx=1;
    add(monthTxt, constraints);
    constraints.gridx=2;
    add(dayTxt, constraints);
  }


 /**
  * Method to handle TextField events
  * =================================
  */
  public void textValueChanged(TextEvent event)
  {
    // Local variables
    TextField textField;
    String stringIn;
      
    // Determine who caused the event
    textField = (TextField) event.getSource();

    // Need to disable TextListener to prevent infinite loop
    textField.removeTextListener(this);

    stringIn = textField.getText();

    // Restrict input to length of two
    if (stringIn.length() > 2 && textField != yearTxt)
      textField.setText(stringIn.substring(2,3));
    
    // If year field, set length to four
    if (stringIn.length() > 4 && textField == yearTxt)
      textField.setText(stringIn.substring(4,5));
    
    // Restrict input to integers
    stringIn = textField.getText();
    if (stringIn.length() == 1)
    {
      if (stringIn.charAt(0) < '0' || stringIn.charAt(0) > '9')
        textField.setText("");
      // Otherwise, make sure month and day are not 0;
      else if ((textField == monthTxt || textField == dayTxt) && 
          Integer.parseInt(stringIn)==0)
        textField.setText("1");
    }
    else if (stringIn.length() == 2)
    {
      // Restrict to integers first, ignoring max range
      if (stringIn.charAt(0) < '0' || stringIn.charAt(0) > '9')
        textField.setText("");
      else if (stringIn.charAt(1) < '0' || stringIn.charAt(1) > '9')
        textField.setText("");
      // If all digits are integer, then check ranges
      else
      {
        // If months field, restrict to max of 12
        if (textField == monthTxt && Integer.parseInt(stringIn) > 12)
          textField.setText("12");
        // Else if days field, restrict to appropriate max
        else if (textField == dayTxt && Integer.parseInt(stringIn) > 31)
          textField.setText("31");
        // Otherwise, make sure month and day are not 0;
        else if ((textField == monthTxt || textField == dayTxt) && 
                  Integer.parseInt(stringIn)==0)
          textField.setText("1");
      }

    }
    // Restricts year field to integers
    else if (stringIn.length() == 3)
    {
      // Restrict to integers first, ignoring max range
      if (stringIn.charAt(0) < '0' || stringIn.charAt(0) > '9')
        textField.setText("");
      else if (stringIn.charAt(1) < '0' || stringIn.charAt(1) > '9')
        textField.setText("");
      else if (stringIn.charAt(2) < '0' || stringIn.charAt(2) > '9')
        textField.setText("");
    }
    // Restricts year field to integers
    else if (stringIn.length() == 4)
    {
      // Restrict to integers first, ignoring max range
      if (stringIn.charAt(0) < '0' || stringIn.charAt(0) > '9')
        textField.setText("");
      else if (stringIn.charAt(1) < '0' || stringIn.charAt(1) > '9')
        textField.setText("");
      else if (stringIn.charAt(2) < '0' || stringIn.charAt(2) > '9')
        textField.setText("");
      else if (stringIn.charAt(3) < '0' || stringIn.charAt(3) > '9')
        textField.setText("");
      // Otherwiwse, make sure year is greater than 1998
      else if (Integer.parseInt(stringIn) < 1998)
        textField.setText("1998");
    }
        
    // Restore TextListener
    textField.addTextListener(this);
  }


 /**
  * Method to send date back to calling function
  * ============================================
  * 
  * @return   Returns a String in the form of the protocol.
  *           If year is < 1998, displays a message box with
  *           error message, and String returned is null ("").
  */
  public String buildResponse()
  {
    // Local variables
    MsgBox msgbox;
    String result = "";
    String year_out = yearTxt.getText();
    String month_out = monthTxt.getText();
    String day_out = dayTxt.getText();    
    
    // Error check year field
    if (year_out.length()==0 || Integer.parseInt(year_out) < 1998)
    {
      msgbox = new MsgBox(frame, "Error -- Invalid Year",
                          "The year field(s) must be at least 1998.",300,150);
      msgbox.setVisible(true);
      result = "";
    }
    // Error check month field
    else if (month_out.length()==0)
    {
      msgbox = new MsgBox(frame, "Error -- Invalid Month",
                          "Please enter a value in the month field(s).",350,150);
      msgbox.setVisible(true);
      result = "";
    }
    // Error check day field
    else if (day_out.length()==0)
    {
      msgbox = new MsgBox(frame, "Error -- Invalid Day",
                          "Please enter a value in the day field(s).",350,150);
      msgbox.setVisible(true);
      result = "";
    }
    // If year, month and day are valid, concatenate result
    else
      {
        result = result.concat(year_out);
        result = result.concat("/");
        result = result.concat(month_out);
        result = result.concat("/");
        result = result.concat(day_out);
        result = result.concat("/");
      }

    return result;
  }
  
  
 /**
  * Method to toggle input fields between editable and noneditable
  * ==============================================================
  *
  * @param value   A boolean value that set field to editable or noneditable
  */
  public void setEditable(boolean value)
  {
    yearTxt.setEditable(value);
    monthTxt.setEditable(value);
    dayTxt.setEditable(value);
  }
}
