/*
*  Copyright (c) 2000 David R. Adaskin.  All Rights Reserved.
*
*  Day of the Week (DOW) calculator for the Palm OS.
*
*  The user inputs the year, month, and date and the palm determines the day of
*  the week of that date.
*
*/


/* Things to do:
* DONE  1. Change TextBox to accept only Numbers.   
* DONE  2. Alert Boxes for insufficient inputs (3).
* DONE  3. Alert Boxes for bad month or day.
* DONE  4. Exception Handling for parseInt().
* DONE  5. Add Clear button that clears input fields and
*          returns focus to Year field.                   
*       6. Add Julian Day computation.
* DONE  7. Add Easter computation
* DONE  8. Add Menu Item with About box.
*       9. Make List box look neater when an item is selected.
*      10. Add IsLeapYear() & Validate Date entry for 29 Feb.
* DONE 11. Add Preferences Dialog for Julian/Gregorian distinction.
*      12. Add InfoDialog to PrefDialog explaining when/where J/G used.
*      13. Incoporate J/G differences in calculations.
*      14. Move scaling functionality from PrefDialog to Preferences.
*      15. InfoDialog & PrefDialog underline title and display it.
*    
*/




import com.sun.kjava.*;


public class DOW extends Spotlet implements DialogOwner{

	Graphics      g;
	Button        dowButton;
	Button        easterButton;
	Button        exitButton;
	Button        clrButton;
	TextField     yField;
	TextBox       mLabel;
	SelectScrollTextBox mListBox;
	TextField     dField;
	TextBox       outputLabel;
	TextBox       easterLabel;
	TextBox       titleLabel;
	String        month = "xxx";

	Button        aboutButton;
    InfoDialog    aboutDialog;
	String        a1 = "Day of the Week Calculator\n";
	String        a2 = "(with Easter)\n\n";
	String        a3 = "Version 2.2\n\n";
	String        a4 = "(c)2000 David R. Adaskin";
    String        aboutTitle = "About";	
	String        aboutText = a1+a2+a3+a4;

    Button        prefButton;
	PrefDialog    prefDialog;
    String        prefTitle = "Preferences";	

    Preferences   pref;
	
    private static String mNames =								  
	"Jan\nFeb\nMar\nApr\nMay\nJun\nJul\nAug\nSep\nOct\nNov\nDec";					                      


	
    public static void main(String[] args) {
		(new DOW()).register(NO_EVENT_OPTIONS);
	}


	public DOW()  {
		g = Graphics.getGraphics();

	    // Initialize the widgets
		g.clearScreen();
		
		titleLabel = new TextBox("Calculate Day of the Week", 0,  0, 118, 13);
		aboutButton = new Button("i", 150, 1);
		prefButton  = new Button("p", 137, 1);
		pref = new Preferences();					 
		
		yField      = new TextField("Year",    10, 20, 55, 15);
		yField.setUpperCase(true);  // won't accept input otherwise

		mLabel      = new TextBox("Month:", 75, 20, 30, 15);
		mListBox    = new SelectScrollTextBox(mNames,  110, 20, 30, 35);
		
		dField      = new TextField("Date",    10, 40, 45, 15);
        dField.setUpperCase(true);  // won't accept input otherwise
		
		dowButton    = new Button("Day",     45, 75);
        easterButton = new Button("Easter",  75, 75);
		
		outputLabel = new TextBox("Day:",    10,  95, 100, 15);
		easterLabel = new TextBox("Easter:", 10, 115, 100, 15); 
		
		exitButton = new Button("Exit",  50, 145);
		clrButton  = new Button("Clear", 80, 145);
		
		yField.setFocus();
		paint();
	}	
	

	void clear()  {
			g.clearScreen();
	}

	
	void paint() {
		// Display the widgets
		titleLabel.paint();
		g.drawLine(0, 13, 110, 13, g.PLAIN); 
		yField.paint();
		mLabel.paint();
		mListBox.paint();
		dField.paint();
		outputLabel.paint();
		easterLabel.paint();
		dowButton.paint();
		easterButton.paint();
		exitButton.paint();
		clrButton.paint();
		aboutButton.paint();
		prefButton.paint();
	}

	
    public void dialogDismissed(String title) {
        register(NO_EVENT_OPTIONS);
		g.clearScreen();
		dField.loseFocus();
		yField.setFocus();
		paint();

//		if (title.equals(prefTitle)){
//			String era;
//			era = pref.getRG().getSelected().getText();
//			g.drawString(era, 20, 135, g.PLAIN);
//		}
	}
    
	
	public void penDown(int x, int y) {
		if (exitButton.pressed(x,y)) {
			clear();
			System.exit(0);
		}
		
		if (aboutButton.pressed(x,y)) {
			yField.loseFocus();
			dField.loseFocus();
		    aboutDialog = new InfoDialog(this, aboutTitle, aboutText);
			unregister();
			aboutDialog.showDialog();
			return;
		}

		if (prefButton.pressed(x,y)) {
			yField.loseFocus();
			dField.loseFocus();
			prefDialog = new PrefDialog(this, prefTitle, pref);
			unregister();
			prefDialog.showDialog();
			return;
		}

		if (dowButton.pressed(x,y)) {
			computeDOW(yField.getText(), month, dField.getText());
			computeEaster(yField.getText());
			return;
		}

		if (easterButton.pressed(x,y)) {
			computeEaster(yField.getText());
			return;
		}

		if (clrButton.pressed(x,y)) {
			dField.loseFocus();
			yField.loseFocus();
			g.clearScreen();
			pref.setDefaults();
			yField      = new TextField("Year",    10, 20, 55, 15);
		    yField.setUpperCase(true);  // won't accept input otherwise

		    mListBox    = new SelectScrollTextBox(mNames,  110, 20, 30, 35);
		    month = "xxx";
			
    		dField      = new TextField("Date",    10, 40, 45, 15);
            dField.setUpperCase(true);  // won't accept input otherwise
		
   		    outputLabel = new TextBox("Day:",    10,  95, 100, 15);
            easterLabel = new TextBox("Easter:", 10, 115, 100, 15);
			
			yField.setFocus();
            paint();
			return;
		}
		
		if ( yField.pressed(x,y) && (!yField.hasFocus()) ) {
			dField.loseFocus();
			yField.setFocus();
			return;
		}

		String selection = mListBox.getSelection(x,y);
		if (selection != null) {
			yField.loseFocus();
			dField.loseFocus();
			month = selection;
			return;
		}
			
		if (mListBox.contains(x,y)) {
            yField.loseFocus();
			dField.loseFocus();
			mListBox.handlePenDown(x,y);
			return;
		}
		
		if ( dField.pressed(x,y) && (!dField.hasFocus()) ) {
			yField.loseFocus();
			dField.setFocus();
			return;
		}
		
    }

	
	public void keyDown(int keyCode) {
		if (yField.hasFocus())  {
			if ( ((keyCode >= 48) && (keyCode <= 57)) || (keyCode == 8) ) 
 			    yField.handleKeyDown(keyCode);
		}
		else if (dField.hasFocus()) {
			if ( ((keyCode >= 48) && (keyCode <= 57)) || (keyCode == 8) ) 
   			    dField.handleKeyDown(keyCode);
		}
		else  	    mListBox.handleKeyDown(keyCode);
	}



	public void penMove(int x, int y) {
		if (mListBox.contains(x,y)) {
			mListBox.handlePenMove(x,y);
			return;
		}
	}

	
	public void computeDOW(String yString, String mString, String dString) {
        int y;
		int m;
		int d;

		// Validate year input
		try {
		    y = Integer.parseInt(yString);
		}
		catch (NumberFormatException e) {
			outputLabel.setText("Please enter a Year.");
			paint();
			return;
		}

		// Validate month input	
        if (mString.equals("Jan"))       m=1;
		else if (mString.equals("Feb"))  m=2;
		else if (mString.equals("Mar"))  m=3;
		else if (mString.equals("Apr"))  m=4;
		else if (mString.equals("May"))  m=5;
		else if (mString.equals("Jun"))  m=6;
		else if (mString.equals("Jul"))  m=7;
		else if (mString.equals("Aug"))  m=8;
		else if (mString.equals("Sep"))  m=9;
		else if (mString.equals("Oct"))  m=10;
		else if (mString.equals("Nov"))  m=11;
		else if (mString.equals("Dec"))  m=12;
		else  {
			outputLabel.setText("Please select a month");
			paint();
			return;
		}


		// Validate date input
		try {
  		    d = Integer.parseInt(dString);
		}
		catch (NumberFormatException e) {
			outputLabel.setText("Please Enter a Date.");
			paint();
			return;
		}

		if (d > 31) {
			badDate(d, "");
			return;
		}
		else if ( (d>30) && ((m==4)||(m==6)||(m==9)||(m==11)) ) {
			badDate(d, mString);
		    return;
		}
		else if ( (d>29) && (m ==2))   {
			badDate(d, mString);
			return;
		}
			
        

		
		// The actual computation
        int m1 = mod((9+m),12);
        int y1 = y - m1/10;
        while (y1<0) { y1 += 400; }
        int w = 1+ mod((2 + d + (13*m1+2)/5 + y1 + y1/4 - y1/100 + y1/400),7);

   	    String day;	   
        if (w == 1)       day = "Sunday";
		else if (w == 2)  day = "Monday";
		else if (w == 3)  day = "Tuesday";
		else if (w == 4)  day = "Wednesday";
		else if (w == 5)  day = "Thursday";
		else if (w == 6)  day = "Friday";
		else if (w == 7)  day = "Saturday";
		else {
			outputLabel.setText("Report this date to Dave!");
			paint();
			return;
		}
				   
 		outputLabel.setText("Day: " + day);

		g.clearScreen();
		paint();
	}



	int mod(int a, int b) {
		return (a - (a/b)*b);
	}


	private void badDate(int date, String monthStr) {
	    if (monthStr.equals("")) {
			outputLabel.setText(date + " is an improper date.");
		} else {
			outputLabel.setText(date + " " +monthStr+" is an invalid date.");
		}
		paint();
	}
			

    public void computeEaster(String yString) {
		int y;

		try {
			y = Integer.parseInt(yString);
		}
		catch (NumberFormatException e) {
			outputLabel.setText("Please enter a Year");
			paint();
			return;
		}

		// Warn about Julian vs Gregorian Calendar.

		// The actual computation
		int a = y/100;        // Century
		int b = a-a/4;        // Centuries since 1600
		int c = mod(y,19);     // Position in Metonic Cycle
		int d = mod((15+19*c+b-(a-(a-17)/25)/3),30);   // Epact
		int e = d-(c+11*d)/319;   // Adjusted Epact
		int s = 22+e+mod((140004-y-y/4+b-e),7);   // Day of March.

		if (s > 31) {
			s -= 31;
			easterLabel.setText("Easter: " + s + " April");
		}
		else
			easterLabel.setText("Easter: " + s + " March");

		g.clearScreen();
		paint();
	
	}
	
}
