/* Copyright (c) Oracle Corporation 2000.  All Rights Reserved. */

package oracle.forms.demos;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.Date;
import java.text.*;

import oracle.ewt.lwAWT.*;


public class CalendarWidget
       extends oracle.ewt.lwAWT.LWContainer
       implements ActionListener, DateChangeListener
{
  private String theDate;
  private oracle.ewt.button.PushButton change;
  private CalendarFrame calendarFrame;
  private DateFormat format;
  private Vector listeners = new Vector();

  public CalendarWidget()
  {
    setLayout(new GridLayout(1,1));
    format = DateFormat.getDateInstance(DateFormat.LONG);
    format.setCalendar(Calendar.getInstance());
    change = new oracle.ewt.button.PushButton("[cal]");
    change.addActionListener(this);
    add(change);
  }

  // set button label
  public void setLabel(String label)
  {
    change.setLabel(label);
    repaint();
  }

  // date property
  public String getDate()
  {
    return format.format(format.getCalendar().getTime());
  }

  public void setDate(String datestring)
  {
    String oldDate = getDate();
    try {
      Date date;
      date = format.parse(datestring);
      format.getCalendar().setTime(date);
      change.setEnabled(true);
    } catch (Exception e) {
      System.out.println("Warning: Wrong date format. Date change failed.");
    }
  }

  // calendar property needed for communication with CalendarFrame
  public void setCalendar(Calendar calendar)
  {
    format.setCalendar(calendar);
    change.setEnabled(true);
  }

  public void setEnabled(boolean value)
  {
    change.setEnabled(value);
  }

  public Calendar getCalendar()
  {
    return format.getCalendar();
  }

  public void actionPerformed(ActionEvent e)
  {
    if(e.getSource() == change) {
      change.setEnabled(false);
      calendarFrame = new CalendarFrame(format.getCalendar().getTime(), this);
      calendarFrame.addDateChangeListener(this);
      calendarFrame.setLocation(new Point(getLocationOnScreen().x,
           getLocationOnScreen().y + getSize().height));
      calendarFrame.show();

      // account for the insets if running inside of an applet
      // to compensate for the yellow warning banner
      Insets insets = calendarFrame.getInsets();
      Dimension dim = calendarFrame.getPreferredSize();
      dim.setSize(dim.width, dim.height+insets.bottom);
      calendarFrame.setSize(dim);
    }
  }

  public void addCalendarWidgetListener(CalendarWidgetListener l)
  {
    listeners.addElement(l);
  }

  public void removeCalendarWidgetListener(CalendarWidgetListener l)
  {
    if(listeners.contains(l))
      listeners.removeElement(l);
  }

  public void fireCalendarWidgetListeners()
  {
    Date d = format.getCalendar().getTime();
    CalendarWidgetEvent cwe = new CalendarWidgetEvent(this,d);
    Vector clone;
    synchronized(this){
      clone = (Vector)listeners.clone();
    }
    for(int i=0;i<clone.size();i++){
      ((CalendarWidgetListener)(clone.elementAt(i))).calendarWidgetDateChanged(cwe);
    }
  }

  // the DateChangeListener event
  public void dateChanged(Date d)
  {
    System.out.println("date changed: " + d.toString());
    fireCalendarWidgetListeners();
  }

  public static void main(String args[])
  {
    final Frame f = new Frame();

    f.addWindowListener(new WindowAdapter()
    {
      public void windowClosing(WindowEvent we)
      {
        f.dispose();
        System.exit(0);
      }
    });

    f.setTitle("Running CalendarWidget Demo");
    CalendarWidget cw = new CalendarWidget();
    cw.setDate("August 26, 1969");
    f.add(cw);
    f.pack();
    f.show();
  }
}


class CalendarFrame extends oracle.ewt.lwAWT.BufferedFrame
      implements ActionListener, ItemListener
{
  CalendarWidget parent;
  Choice month;
  TextField year;
  LWComponent days;
  LWContainer monthNyear;
  int currentDay;
  String months[] = {"January", "February", "March", "April", "May",
         "June", "July", "August", "September", "October",
         "November", "December"};
  int monthLength[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  String weekdays[] = {"S", "M", "T", "W", "T", "F", "S"};
  DayCell[] cells;
  Dimension cellsize;
  int pad = 3;

  // the listeners
  Vector listeners = new Vector();

  public CalendarFrame(Date date, CalendarWidget widget)
  {
    //
    // add an inner class to handle the window closing event
    // for this frame
    //
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e)
      {
        setVisible(false);
        parent.setEnabled(true);
      };
    });

    setVisible(false);
    parent = widget;
    setResizable(false);

    Calendar calendar = Calendar.getInstance();

    // make it some nicer colors
    setBackground(Color.decode("#336699"));
    setForeground(Color.white);

    // construct the top level control elements
    monthNyear = new LWContainer();
    month = new Choice();
    month.setBackground(Color.white);
    month.setForeground(Color.decode("#003388"));
    for (int i = 0; i < 12; i++)
      month.addItem(months[i]);
    month.addItemListener(this);

    year = new TextField(4);
    year.setBackground(Color.white);
    year.setForeground(Color.decode("#003388"));
    year.addActionListener(this);

    year.addFocusListener(new FocusAdapter()
    {
      public void focusLost(FocusEvent fe)
      {
        arrangeDays();
      }
    });

    monthNyear.add(month);
    monthNyear.add(year);
    add(monthNyear, "North");
    days = new LWComponent();
    days.setLayout(new GridLayout(0, 7));
    setDate(date);
    arrangeDays();
    add(days, "South");
    pack();
  }

  public Date getDate()
  {
    Calendar calendar = Calendar.getInstance();
    calendar.set(getYear(), getMonth(), getDay());
    return calendar.getTime();
  }

  public void setDate(Date newDate)
  {
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(newDate);
    setYear(calendar.get(Calendar.YEAR));
    setMonth(calendar.get(Calendar.MONTH));
    setDay(calendar.get(Calendar.DAY_OF_MONTH));
  }

  public int getYear()
  {
    return(Integer.parseInt(year.getText()));
  }

  public void setYear(int newYear)
  {
    year.setText(Integer.toString(newYear));
  }

  public int getMonth()
  {
    return(month.getSelectedIndex());
  }

  public void setMonth(int newMonth)
  {
    month.select(newMonth);
  }

  public int getDay()
  {
    return currentDay;
  }

  public void setDay(int newDay)
  {
    currentDay = newDay;
  }

  public Calendar getCalendar()
  {
    Calendar calendar = Calendar.getInstance();
    calendar.set(getYear(), getMonth(), getDay());
    return calendar;
  }

  /**
   * Detect the enter key being pressed in the textfield and cause
   * the calendar display to be re-arranged
   *
   * @param the actionevent generated by the year textfield
   * @see java.awt.event.ActionListener
   */
  public void actionPerformed(ActionEvent e)
  {
    arrangeDays();
  }

  /**
   * Detect when a change is made to the months list and cause
   * the calendar display to be re-arranged
   *
   * @param the itemevent generated by the months list
   * @see java.awt.event.ItemListener
   */
  public void itemStateChanged(ItemEvent e)
  {
    arrangeDays();
  }

  /**
   * Modifies the date displayed, notifies each of the interested
   * components via their listeners that the date has changed and then
   * disposes of the CalendarFrame
   *
   * @param newDay the day selected by the user by clicking on the canvas
   */
  public void setDateAndExit(int newDay)
  {
    cells[currentDay - 1].deactivate();
    setDay(newDay);
    parent.setCalendar(getCalendar());
    fireDateChangeListeners(getCalendar().getTime());
    dispose();
  }

  /**
   * Visually arranges the days on the canvas given a date to display
   */
  private void arrangeDays()
  {
    days.removeAll();
    Font f = new Font("TimesRoman", Font.PLAIN, 10);
    setFont(f);
    FontMetrics fm = getFontMetrics(f);
    cellsize = new Dimension(fm.charWidth('0') * 2 + pad * 3,
           fm.getHeight() + pad * 2);
    int cMonth = getMonth();
    int cYear = getYear();
    Calendar calendar = Calendar.getInstance();
    calendar.set(cYear, cMonth, 1);
    calendar.setTime(calendar.getTime());
    int weekday = calendar.get(Calendar.DAY_OF_WEEK );

    int max;
    if((cMonth == 1) && (calendar instanceof GregorianCalendar) &&
       (((GregorianCalendar)calendar).isLeapYear(cYear))) {
      max = 29;
    } else {
      max = monthLength[cMonth];
    }
    if (currentDay > max)
      currentDay = max;

    for (int i = 0; i < 7; i++)
      days.add(new WeekdayCell(weekdays[i], cellsize,
             this));
    for (int i = 1; i < weekday ; i++)
      days.add(new WeekdayCell("", cellsize, this));
    cells = new DayCell[max];
    for (int i = 0; i < max; i++)
      days.add(cells[i] = new DayCell(i + 1, cellsize, this));
    cells[currentDay - 1].activate();
    pack();
  }

  public void addDateChangeListener(DateChangeListener listener)
  {
    listeners.addElement(listener);
  }

  public void removeDateChangeListener(DateChangeListener listener)
  {
    if(listeners.contains(listener))
       listeners.removeElement(listener);
  }

  public void fireDateChangeListeners(Date d)
  {
    Vector clone = null;
    synchronized(this){
      clone = (Vector)listeners.clone();
    }
    for(int i=0; i<clone.size();i++){
      ((DateChangeListener)clone.elementAt(i)).dateChanged(d);
    }
  }
}


class DayCell extends Canvas
{
  CalendarFrame parent;
  int day;
  int pad;
  Color active = Color.red;
  Color passive;

  public DayCell(int newDay, Dimension size, CalendarFrame frame)
  {
    parent = frame;
    day = newDay;

    // handle the mouseclick event with an inner class
    addMouseListener(new MouseAdapter()
    {
      public void mouseClicked(MouseEvent e)
      {
        activate();
        parent.setDateAndExit(getDay());
      }
    });
    setSize(size);
    setFont(parent.getFont());
    pad = parent.pad;
  }

  public void paint(Graphics g)
  {
    if (day != 0)
    {
      FontMetrics fm = getFontMetrics(getFont());
      g.drawString(Integer.toString(day), pad, pad + fm.getHeight());
    }
  }

  public void activate()
  {
    passive = getBackground();
    setBackground(active);
    repaint();
  }

  public void deactivate()
  {
    setBackground(passive);
    repaint();
  }

  int getDay()
  {
    return (day);
  }
}

class WeekdayCell extends Canvas
{
  String day;
  int pad;

  public WeekdayCell(String newDay, Dimension size, CalendarFrame parent)
  {
    day = newDay;
    setSize(size);
    setFont(parent.getFont());
    pad = parent.pad;
  }

  public void paint(Graphics g)
  {
    FontMetrics fm = getFontMetrics(getFont());
    g.drawString(day, pad, pad + fm.getHeight());
  }
}

interface DateChangeListener
{
  public void dateChanged(Date d);
}

