package com.kitkon.util;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * panel that contains  day/month/year selection controls
 * 
 *  requires JDK 1.5 or higher
 * @author jfk, kilian IT consulting, http://it.jkilian.de
 * @version 1.0
 * @license feel free to use, don't expect anything, we promise nothing :-)
 *
 */
public class DateSelectPanel extends JPanel {
	private static final long serialVersionUID = -4290527137158061717L;
	/** controls for date */
	private JSpinner  mJDay;
	private JSpinner  mJYear;
	private JComboBox mJMonth;

	/**
	 * default limits for mJYear Spinner
	 */
	Integer mMinYear = 2008;
	Integer mMaxYear = 2100;

	
	/** several formatting utils */
	public static class Formatter {
		static SimpleDateFormat mDfDate = new SimpleDateFormat("dd.MM.yyyy");
		/** extract  year from a Date */
		static SimpleDateFormat mDfYear = new SimpleDateFormat("yyyy");
		/** extract  day from a Date */
		static SimpleDateFormat mDfDay = new SimpleDateFormat("dd");
		/** extract  month name from a Date */
		static SimpleDateFormat mDfMonthName = new SimpleDateFormat("MMMM");
		/** extract  month as int from a Date */
		static SimpleDateFormat mDfMonthInt = new SimpleDateFormat("MM");
		
		/** return year of date */
		protected static int extractYear(Date date) {
			try{
				return Integer.parseInt(mDfYear.format(date));
			}
			catch( Exception e)
			{
				return Integer.parseInt(mDfYear.format(new Date()));
				
			}
		}
		/** return name of month of date */
		protected static String extractNameOfMonth(Date date) {
			try{
				return mDfMonthName.format(date);
			}
			catch( Exception e)
			{
				return mDfMonthName.format(new Date());
				
			}
		}
		/**
		 * 
		 * @param month as int  0...1
		 * @return name of month 
		 */
		protected static String monthNameToInt(int month) {
			try{
				return mDfMonthName.format(mDfMonthInt.parse(""+month));
			}
			catch( Exception e)
			{
				e.printStackTrace();
				return mDfMonthName.format(new Date());
				
			}
		}
		/**
		 * 
		 * @param date
		 * @return month 0...11
		 */
		protected static int extractMonth(Date date) {
			try{
				return Integer.parseInt(mDfMonthInt.format(date));
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
			return 0;
		}
		/**
		 * 
		 * @param date
		 * @return day of month of date
		 */
		public static int extractDay(Date date) {
			try{
				return Integer.parseInt(mDfDay.format(date));
			}
			catch( Exception e)
			{
				e.printStackTrace();
				return Integer.parseInt(mDfDay.format(new Date()));				
			}
		}
		/**
		 * 
		 * @param date in format dd.MMMM.yyyy
		 * @return Date OR null
		 */
		public static Date parseDate(String date) {
			try{
				return mDfDate.parse(date);
			}
			catch( Exception e)
			{
				e.printStackTrace();
				return null;
			}
		}

	}

	/**
	 * panel with controls for
	 * day of month (JSpinner)
	 * name of month (JComboBox)
	 * year (JSpinner) 
	 * @param minYear lower limit for year spinner
	 * @param maxYear upper limit for year spinner
	 */
	public DateSelectPanel(int minYear, int maxYear)
	{
		super();
		mMinYear = minYear;
		mMaxYear = maxYear;
		FlowLayout layout = new FlowLayout();
		layout.setAlignment(FlowLayout.LEFT)	;
		layout.setVgap(0);
		layout.setHgap(0);
			
		setLayout(layout);
		
		add(getJDay());
		add(getJMonth());
		add(getJYear());

	}
	protected JSpinner getJDay() {
		if( mJDay == null )
		{
			Integer start = Formatter.extractDay(new Date());
			Integer min = 1;
			Integer max = 31;
			
			 // Create a date spinner that controls the hours
		    SpinnerNumberModel dateModel = new SpinnerNumberModel(
		    		start, 
		    		min, max, new Integer(1));
		    mJDay = new JSpinner(dateModel);
		}
		return mJDay;
	}
	private JComboBox getJMonth() {
		if (mJMonth == null) {
			mJMonth = new JComboBox();
			mJMonth.setPreferredSize(new Dimension(50, 20));
			mJMonth.setForeground(Color.black);
			mJMonth.setBackground(Color.white);
			mJMonth.setMaximumRowCount(12);
			for( int i = 0; i < 12; i++ )
			{
				mJMonth.addItem(Formatter.monthNameToInt(i+1));
			}
			mJMonth.setSelectedIndex(Formatter.extractMonth(new Date())-1);			
			mJMonth.setFont(new Font("Dialog", Font.PLAIN, 12));
			mJMonth.addItemListener(new java.awt.event.ItemListener() {
				public void itemStateChanged(java.awt.event.ItemEvent e) {
					updateMaxDay();
				}
			});
		}
		return mJMonth;
	}
	/**
	 * update the max val of mJDay according the selected month and year
	 * (e.g. feb 2009 => max = 28, jan 2009 => max = 31)
	 */
	protected void updateMaxDay() {
		try {
			int month = getJMonth().getSelectedIndex();
			int year = (Integer)(getJYear().getValue());
			  // Create a calendar object of the desired month
		    Calendar cal = new GregorianCalendar( year, month, 1 );
		    
		    // Get the number of days in that month
		    Integer days = cal.getActualMaximum(Calendar.DAY_OF_MONTH); // 28
		    Integer cur = (Integer) getJDay().getValue();
		    if( cur.intValue() >= days.intValue() )
		    	cur = days.intValue();
		    SpinnerNumberModel model = (SpinnerNumberModel) getJDay().getModel();
		    model.setMaximum(days);
		    model.setValue(cur);
		}
		catch( Exception e ){	
			e.printStackTrace();
		}
		
	}

	private JSpinner getJYear() {
		if( mJYear == null )
		{
			Integer start = Formatter.extractYear(new Date());
			
			 // Create a date spinner that controls the hours
		    SpinnerNumberModel dateModel = new SpinnerNumberModel(
		    		start, 
		    		mMinYear, 
		    		mMaxYear, 
		    		new Integer(1) /* step size */);
		    mJYear = new JSpinner(dateModel);
		    JComponent editor = new JSpinner.NumberEditor(mJYear, "####");
		    mJYear.setEditor(editor);

			
		    dateModel.addChangeListener(new ChangeListener(){

				public void stateChanged(ChangeEvent paramChangeEvent) {
					updateMaxDay();
				}
		    }
		    );
			

		}
		return mJYear;
	}
	/**
	 * 
	 * @return selected date OR null
	 */
	public Date getDate()
	{
		try{
			int day = ((Integer)getJDay().getValue()).intValue();
			int month = getJMonth().getSelectedIndex()+1;
			int year = ((Integer)getJYear().getValue()).intValue();
			return Formatter.parseDate(day+"."+month+"."+year);
		}
		catch( Exception e)
		{			
			e.printStackTrace();
		}
		return null;
	}
	/**
	 * set date to selector controls
	 * @param date
	 */
	public void setDate(Date date)
	{
		getJYear().setValue(Formatter.extractYear(date));
		getJMonth().setSelectedIndex(Formatter.extractMonth(date)-1);
		getJDay().setValue(Formatter.extractDay(date));
	}
}

