/*******************************************************************************
 * Copyright (c) 2004, 2005 Actuate Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *  Actuate Corporation  - initial API and implementation
 *******************************************************************************/

package org.eclipse.birt.core.script.bre;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import org.eclipse.birt.core.data.DataTypeUtil;
import org.eclipse.birt.core.exception.BirtException;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ScriptableObject;

import com.ibm.icu.util.Calendar;

/**
 * 
 */
public class BirtDateTime extends ScriptableObject
{
	//TODO Change these values according to the locale.
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	static private SimpleDateFormat abbrMonthFormat = null;
	static private SimpleDateFormat monthFormat = null;
	static private SimpleDateFormat abbrWeekFormat = null;
	static private SimpleDateFormat weekFormat = null;
	
	/**
	 * 
	 * @return
	 */
	private static SimpleDateFormat getAbbrMonthFormat( )
	{
		if ( abbrMonthFormat != null )
			return abbrMonthFormat;

		try
		{
			Locale defaultLocale = Context.enter( ).getLocale( );
			abbrMonthFormat = new SimpleDateFormat( "MMM", defaultLocale );

			return abbrMonthFormat;
		}
		finally
		{
			Context.exit( );
		}
	}
	
	/**
	 * 
	 * @return
	 */
	private static SimpleDateFormat getMonthFormat( )
	{
		if ( monthFormat != null )
			return monthFormat;

		try
		{
			Locale defaultLocale = Context.enter( ).getLocale( );
			monthFormat = new SimpleDateFormat( "MMMM", defaultLocale );

			return monthFormat;
		}
		finally
		{
			Context.exit( );
		}
	}
	
	/**
	 * 
	 * @return
	 */
	private static SimpleDateFormat getAbbrWeekFormat( )
	{
		if ( abbrWeekFormat != null )
			return abbrWeekFormat;

		try
		{
			Locale defaultLocale = Context.enter( ).getLocale( );
			abbrWeekFormat = new SimpleDateFormat( "EEE", defaultLocale );

			return abbrWeekFormat;
		}
		finally
		{
			Context.exit( );
		}
	}
	
	/**
	 * 
	 * @return
	 */
	private static SimpleDateFormat getWeekFormat( )
	{
		if ( weekFormat != null )
			return weekFormat;

		try
		{
			Locale defaultLocale = Context.enter( ).getLocale( );
			weekFormat = new SimpleDateFormat( "EEEE", defaultLocale );

			return weekFormat;
		}
		finally
		{
			Context.exit( );
		}
	}
	/**
	 * 
	 *
	 */
	public BirtDateTime( )
	{
		this.defineProperty( "year", new Function_Year( ), 0 );
		this.defineProperty( "quarter", new Function_Quarter( ), 0 );
		this.defineProperty( "month", new Function_Month( ), 0 );
		this.defineProperty( "week", new Function_Week( ), 0 );
		this.defineProperty( "day", new Function_Day( ), 0 );
		this.defineProperty( "weekDay", new Function_WeekDay( ), 0 );
		this.defineProperty( "today", new Function_Today( ), 0 );
		this.defineProperty( "now", new Function_Now( ), 0 );
		this.defineProperty( "diffYear", new Function_DiffYear( ), 0 );
		this.defineProperty( "diffMonth", new Function_DiffMonth( ), 0 );
		this.defineProperty( "diffQuarter", new Function_DiffQuarter( ), 0 );
		this.defineProperty( "diffWeek", new Function_DiffWeek( ), 0 );
		this.defineProperty( "diffDay", new Function_DiffDay( ), 0 );
		this.defineProperty( "diffHour", new Function_DiffHour( ), 0 );
		this.defineProperty( "diffMinute", new Function_DiffMinute( ), 0 );
		this.defineProperty( "diffSecond", new Function_DiffSecond( ), 0 );
		this.defineProperty( "addYear", new Function_AddYear( ), 0 );
		this.defineProperty( "addMonth", new Function_AddMonth( ), 0 );
		this.defineProperty( "addQuarter", new Function_AddQuarter( ), 0 );
		this.defineProperty( "addWeek", new Function_AddWeek( ), 0 );
		this.defineProperty( "addDay", new Function_AddDay( ), 0 );
		this.defineProperty( "addHour", new Function_AddHour( ), 0 );
		this.defineProperty( "addMinute", new Function_AddMinute( ), 0 );
		this.defineProperty( "addSecond", new Function_AddSecond( ), 0 );
	}

	private class Function_Year extends Function_temp
	{
		Function_Year()
		{
			length = 1;
			isFixed = true;
		}
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		protected Object getValue( Object[] args ) throws BirtException
		{
				return new Integer( year(DataTypeUtil.toDate(args[0])));
		}
	}		
	
	/**
	 * 4-digit year number of date/time value d
	 * 
	 * @param d
	 * @return
	 */
	private static int year( Date d )
	{
		if ( d == null )
			throw new java.lang.IllegalArgumentException( "date value is null!" );

		return getCalendar( d ).get( Calendar.YEAR );
	}

	private class Function_Quarter extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_Quarter( )
		{
			length = 1;
			isFixed = true;
		}
		
		protected Object getValue( Object[] args ) throws BirtException
		{
			return new Integer( quarter(DataTypeUtil.toDate(args[0])));
		}
	}		
	
	/**
	 * Quarter number (1 to 4) of date/time value d
	 * 
	 * @param d
	 * @return
	 */
	private static int quarter( Date d )
	{
		if ( d == null )
			throw new java.lang.IllegalArgumentException( "date value is null!" );

		int month = getCalendar( d ).get( Calendar.MONTH );
		switch ( month )
		{
			case Calendar.JANUARY :
			case Calendar.FEBRUARY :
			case Calendar.MARCH :
				return 1;
			case Calendar.APRIL :
			case Calendar.MAY :
			case Calendar.JUNE :
				return 2;
			case Calendar.JULY :
			case Calendar.AUGUST :
			case Calendar.SEPTEMBER :
				return 3;
			case Calendar.OCTOBER :
			case Calendar.NOVEMBER :
			case Calendar.DECEMBER :
				return 4;
			default :
				return -1;
		}
	}

	private class Function_Month extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_Month()
		{
			length = 2;
			isFixed = false;
		}
		
		protected Object getValue( Object[] args ) throws BirtException
		{
			if( args.length == 1 )
				return new Integer( month(DataTypeUtil.toDate(args[0])));
			else
				return month(DataTypeUtil.toDate(args[0]), ((Number)args[1]).intValue( ));
		}
	}	
	/**
	 * Month of date/time value d. Return month number (1-12)
	 * 
	 * @param d
	 * @return
	 */
	private static int month( Date d )
	{
		if ( d == null )
			throw new java.lang.IllegalArgumentException( "date value is null!" );

		return getCalendar( d ).get( Calendar.MONTH ) + 1;
	}

	/**
	 * Month of date/time value d. Option is an integer value: 1 (default):
	 * return month number (1-12) 2: return full month name as per user locale
	 * (e.g., January to December for English locale). 3: return short month
	 * name as per user locale (e.g., Jan to Dec for English locale)
	 * 
	 * @param d
	 * @param option
	 * @return
	 */
	private static String month( Date d, int option )
	{
		// TODO: finish me.
		if ( d == null )
			throw new java.lang.IllegalArgumentException( "date value is null!" );

		Calendar c = getCalendar( d );
		int month = c.get( Calendar.MONTH );
		if ( option == 1 )
		{
			return String.valueOf( month + 1 );
		}
		else if ( option == 2 )
		{
			return getMonthFormat().format( d );
		}
		else if ( option == 3 )
		{
			return getAbbrMonthFormat().format( d );
		}
		return null;
	}
	
	private class Function_Week extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_Week( )
		{
			length = 1;
			isFixed = true;
		}
		
		protected Object getValue( Object[] args ) throws BirtException
		{
			return new Integer( week(DataTypeUtil.toDate(args[0])));
		}
	}	

	/**
	 * Week number of the year (1 to 52) of date/time value d.
	 * 
	 * @param d
	 * @return
	 */
	private static int week( Date d )
	{
		if ( d == null )
			throw new java.lang.IllegalArgumentException( "date value is null!" );

		return getCalendar( d ).get( Calendar.WEEK_OF_YEAR );
	}

	private class Function_Day extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_Day( )
		{
			length = 1;
			isFixed = true;
		}
		
		protected Object getValue( Object[] args ) throws BirtException
		{
			return new Integer( day(DataTypeUtil.toDate(args[0])));
		}
	}	
	
	/**
	 * Day number of the month(1 to 31).
	 * 
	 * @param d
	 * @return
	 */
	private static int day( Date d )
	{
		if ( d == null )
			throw new java.lang.IllegalArgumentException( "date value is null!" );

		return getCalendar( d ).get( Calendar.DAY_OF_MONTH );
	}
	
	private class Function_WeekDay extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_WeekDay( )
		{
			length = 2;
			isFixed = false;
		}
		
		protected Object getValue( Object[] args ) throws BirtException
		{
			if( args.length == 1 )
				return weekDay(DataTypeUtil.toDate(args[0]));
			else
				return weekDay(DataTypeUtil.toDate(args[0]), ((Number)args[1]).intValue( ));
		}
	}

	/**
	 * Day the week. Return a number 1 (Sunday) to 7 (Saturday).
	 * 
	 * @param d
	 * @return
	 */
	private static String weekDay( Date d )
	{
		if ( d == null )
			throw new java.lang.IllegalArgumentException( "date value is null!" );

		return String.valueOf(getCalendar( d ).get( Calendar.DAY_OF_WEEK ));
	}

	/**
	 * Day the week. Option is an integer value: 1: return a number 1 (Sunday)
	 * to 7 (Saturday) 2: return a number 1 (Monday) to 7 (Sunday) 3: return a
	 * number 0 (Monday) to 6 (Sunday) 4: return the weekday name as per user
	 * locale (e.g., Sunday 閳?? Saturday for English) 5: return the abbreviated
	 * weekday name as per user locale (e.g., Sun 閳?? Sat for English)
	 * 
	 * @param d
	 * @param option
	 * @return
	 */
	private static String weekDay( Date d, int option )
	{
		if ( d == null )
			throw new java.lang.IllegalArgumentException( "date value is null!" );
		switch ( option )
		{
			case 1 :
				return String.valueOf( getWeekDay( d, Calendar.SUNDAY ) );
			case 2 :
				return String.valueOf( getWeekDay( d, Calendar.MONDAY ) );
			case 3 :
				return String.valueOf( getWeekDay( d, Calendar.MONDAY ) - 1 );
			case 4 :
				return getWeekFormat().format( d );
			case 5 :
				return getAbbrWeekFormat().format( d );
		}
		return null;

	}

	private class Function_Today extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_Today( )
		{
			length = 0;
			isFixed = true;
		}
		
		protected Object getValue( Object[] args ) throws BirtException
		{
			return today();
		}
	}
	
	/**
	 * Returns a timestamp value which is midnight of the current date.
	 * 
	 * @return
	 */
	private static Timestamp today( )
	{
		Calendar c = Calendar.getInstance( );
		return new Timestamp(c.getTimeInMillis( ));
	}

	private class Function_Now extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_Now( )
		{
			length = 0;
			isFixed = true;
		}
		
		protected Object getValue( Object[] args ) throws BirtException
		{
			return now();
		}
	}
	
	/**
	 * Returns the current timestamp
	 * 
	 * @return
	 */
	private static Timestamp now( )
	{
		Date now = new Date( );
		return new Timestamp( now.getTime( ) );
	}

	private class Function_DiffYear extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_DiffYear( )
		{
			length = 2;
			isFixed = true;
		}
		
		protected Object getValue( Object[] args ) throws BirtException
		{
			return new Integer(diffYear(DataTypeUtil.toDate(args[0]), DataTypeUtil.toDate(args[1])));
		}
	}
	
	/**
	 * Return difference in number of years
	 * 
	 * @param d1
	 * @param d2
	 * @return
	 */
	private static int diffYear( Date d1, Date d2 )
	{
		if ( d1 == null || d2 == null )
		{
			throw new java.lang.IllegalArgumentException( "date value is null!" );
		}
		int startYear = year( d1 );
		int endYear = year( d2 );

		return endYear - startYear;
	}

	private class Function_DiffMonth extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_DiffMonth( )
		{
			length = 2;
			isFixed = true;
		}
		
		protected Object getValue( Object[] args ) throws BirtException
		{
			return new Integer(diffMonth(DataTypeUtil.toDate(args[0]), DataTypeUtil.toDate(args[1])));
		}
	}
	
	/**
	 * Return difference in number of months
	 * 
	 * @param d1
	 * @param d2
	 * @return
	 */
	private static int diffMonth( Date d1, Date d2 )
	{
		if ( d1 == null || d2 == null )
		{
			throw new java.lang.IllegalArgumentException( "date value is null!" );
		}

		int startMonth = year( d1 ) * 12 + month( d1 );
		int endMonth = year( d2 ) * 12 + month( d2 );

		return endMonth - startMonth;
	}

	private class Function_DiffQuarter extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_DiffQuarter( )
		{
			length = 2;
			isFixed = true;
		}
		
		protected Object getValue( Object[] args ) throws BirtException
		{
			return new Integer(diffQuarter(DataTypeUtil.toDate(args[0]), DataTypeUtil.toDate(args[1])));
		}
	}
	
	/**
	 * Return difference in number of quarters
	 * 
	 * @param d1
	 * @param d2
	 * @return
	 */
	private static int diffQuarter( Date d1, Date d2 )
	{
		if ( d1 == null || d2 == null )
		{
			throw new java.lang.IllegalArgumentException( "date value is null!" );
		}

		int startQuter = year( d1 ) * 4 + quarter( d1 );
		int endQuter = year( d2 ) * 4 + quarter( d2 );

		return endQuter - startQuter;
	}

	
	private class Function_DiffWeek extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_DiffWeek( )
		{
			length = 2;
			isFixed = true;
		}
		
		protected Object getValue( Object[] args ) throws BirtException
		{
			return new Long(diffWeek(DataTypeUtil.toDate(args[0]), DataTypeUtil.toDate(args[1])));
		}
	}
	
	/**
	 * Return difference in number of weeks
	 * 
	 * @param d1
	 * @param d2
	 * @return
	 */
	private static long diffWeek( Date d1, Date d2 )
	{	
		Calendar c = getClearedCalendarInstance( 0,0,7 );

		Date baseDay = new Date(c.getTimeInMillis( ));
		
		int diffDay = 1 - Integer.valueOf( weekDay( baseDay ) ).intValue( );

		baseDay = addDay( baseDay, diffDay );

		return ( diffSecond( baseDay, d2 ) + 3000 * 60 * 60 * 24 * 7 )
				/ ( 60 * 60 * 24 * 7 )
				- ( diffSecond( baseDay, d1 ) + 3000 * 60 * 60 * 24 * 7 )
				/ ( 60 * 60 * 24 * 7 );
	}

	private class Function_DiffDay extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_DiffDay( )
		{
			length = 2;
			isFixed = true;
		}
		
		protected Object getValue( Object[] args ) throws BirtException
		{
			return new Long(diffDay(DataTypeUtil.toDate(args[0]), DataTypeUtil.toDate(args[1])));
		}
	}
	
	/**
	 * Return difference in number of days
	 * 
	 * @param d1
	 * @param d2
	 * @return
	 */
	private static long diffDay( Date d1, Date d2 )
	{
		Calendar c = getClearedCalendarInstance( 0, 0, 1 );

		return ( diffSecond( new Date(c.getTimeInMillis( ) ), d2 ) + 3000
				* 60 * 60 * 24 * 7 )
				/ ( 60 * 60 * 24 )
				- ( diffSecond( new Date( c.getTimeInMillis( ) ), d1 ) + 3000
						* 60 * 60 * 24 * 7 ) / ( 60 * 60 * 24 );
	}

	private class Function_DiffHour extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_DiffHour( )
		{
			length = 2;
			isFixed = true;
		}
		
		protected Object getValue( Object[] args ) throws BirtException
		{
			return new Long(diffHour(DataTypeUtil.toDate(args[0]), DataTypeUtil.toDate(args[1])));
		}
	}
	
	/**
	 * Return difference in number of hours
	 * 
	 * @param d1
	 * @param d2
	 * @return
	 */
	private static long diffHour( Date d1, Date d2 )
	{
		Calendar c = getClearedCalendarInstance( 0, 0, 1 );

		return ( diffSecond( new Date( c.getTimeInMillis( ) ), d2 ) + 3000
				* 60 * 60 * 24 * 7 )
				/ ( 60 * 60 )
				- ( diffSecond( new Date( c.getTimeInMillis( ) ), d1 ) + 3000
						* 60 * 60 * 24 * 7 ) / ( 60 * 60 );
	}

	private class Function_DiffMinute extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_DiffMinute( )
		{
			length = 2;
			isFixed = true;
		}
		
		protected Object getValue( Object[] args ) throws BirtException
		{
			return new Long(diffMinute(DataTypeUtil.toDate(args[0]), DataTypeUtil.toDate(args[1])));
		}
	}
	
	/**
	 * Return difference in number of minutes
	 * 
	 * @param d1
	 * @param d2
	 * @return
	 */
	private static long diffMinute( Date d1, Date d2 )
	{
		Calendar c = getClearedCalendarInstance( 0, 0, 1  );
		
		return ( diffSecond( new Date( c.getTimeInMillis( ) ), d2 ) + 3000
				* 60 * 60 * 24 * 7 )
				/ ( 60 )
				- ( diffSecond( new Date( c.getTimeInMillis( ) ), d1 ) + 3000
						* 60 * 60 * 24 * 7 ) / ( 60 );
	}

	/**
	 * The Calendar by default will give you an instance of
	 * current time. This is however not expected. The method clear()
	 * has to be invoked to re-init the Calendar instance.
	 * @return
	 */
	private static Calendar getClearedCalendarInstance(int year, int month, int date )
	{
		Calendar c = Calendar.getInstance( );
		
		c.clear( );
		
		c.set( year, month, date );
		return c;
	}

	/**
	 * 
	 * @author xyi
	 *
	 */
	private class Function_DiffSecond extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_DiffSecond( )
		{
			length = 2;
			isFixed = true;
		}
		
		protected Object getValue( Object[] args ) throws BirtException
		{
			return new Long(diffSecond(DataTypeUtil.toDate(args[0]), DataTypeUtil.toDate(args[1])));
		}
	}
	
	/**
	 * Return difference in number of seconds
	 * 
	 * @param d1
	 * @param d2
	 * @return
	 */
	private static long diffSecond( Date d1, Date d2 )
	{
		if ( d1 == null || d2 == null )
		{
			throw new java.lang.IllegalArgumentException( "date value is null!" );
		}
		long diff = d2.getTime( ) - d1.getTime( );

		return ( new Long( diff / 1000 ) ).longValue( );
	}

	private class Function_AddYear extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_AddYear( )
		{
			length = 2;
			isFixed = true;
		}
			
		protected Object getValue( Object[] args ) throws BirtException
		{
			return addYear(DataTypeUtil.toDate(args[0]), ((Number)args[1]).intValue( ));
		}
	}
	
	/**
	 * Add num years
	 * 
	 * @param date
	 * @param num
	 * @return
	 */
	private static Date addYear( Date date, int num )
	{
		Calendar startCal = getCalendar( date );

		startCal.add( Calendar.YEAR, num );

		return startCal.getTime( );
	}

	private class Function_AddMonth extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_AddMonth( )
		{
			length = 2;
			isFixed = true;
		}
			
		protected Object getValue( Object[] args ) throws BirtException
		{
			return addMonth(DataTypeUtil.toDate(args[0]), ((Number)args[1]).intValue( ));
		}
	}
	
	/**
	 * Add num months
	 * 
	 * @param date
	 * @param num
	 * @return
	 */
	private static Date addMonth( Date date, int num )
	{
		Calendar startCal = getCalendar( date );

		startCal.add( Calendar.MONTH, num );

		return startCal.getTime( );
	}

	private class Function_AddQuarter extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_AddQuarter( )
		{
			length = 2;
			isFixed = true;
		}
			
		protected Object getValue( Object[] args ) throws BirtException
		{
			return addQuarter(DataTypeUtil.toDate(args[0]), ((Number)args[1]).intValue( ));
		}
	}
	
	/**
	 * Add num quarters
	 * 
	 * @param date
	 * @param num
	 * @return
	 */
	private static Date addQuarter( Date date, int num )
	{
		return addMonth( date, num * 3 );
	}

	private class Function_AddWeek extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_AddWeek( )
		{
			length = 2;
			isFixed = true;
		}
			
		protected Object getValue( Object[] args ) throws BirtException
		{
			return addWeek(DataTypeUtil.toDate(args[0]), ((Number)args[1]).intValue( ));
		}
	}
	
	/**
	 * Add num weeks
	 * 
	 * @param date
	 * @param num
	 * @return
	 */
	private static Date addWeek( Date date, int num )
	{
		return addDay( date, num * 7 );
	}

	private class Function_AddDay extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_AddDay( )
		{
			length = 2;
			isFixed = true;
		}
			
		protected Object getValue( Object[] args ) throws BirtException
		{
			return addDay(DataTypeUtil.toDate(args[0]), ((Number)args[1]).intValue( ));
		}
	}
	
	/**
	 * Add num days
	 * 
	 * @param date
	 * @param num
	 * @return
	 */
	private static Date addDay( Date date, int num )
	{
		Calendar startCal = getCalendar( date );

		startCal.add( Calendar.DATE, num );

		return startCal.getTime( );
	}

	private class Function_AddHour extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_AddHour( )
		{
			length = 2;
			isFixed = true;
		}
			
		protected Object getValue( Object[] args ) throws BirtException
		{
			return addHour(DataTypeUtil.toDate(args[0]), ((Number)args[1]).intValue( ));
		}
	}
	
	/**
	 * Add num hours
	 * 
	 * @param date
	 * @param num
	 * @return
	 */
	private static Date addHour( Date date, int num )
	{
		Calendar startCal = getCalendar( date );

		startCal.add( Calendar.HOUR_OF_DAY, num );

		return startCal.getTime( );
	}

	private class Function_AddMinute extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_AddMinute( )
		{
			length = 2;
			isFixed = true;
		}
			
		protected Object getValue( Object[] args ) throws BirtException
		{
			return addMinute(DataTypeUtil.toDate(args[0]), ((Number)args[1]).intValue( ));
		}
	}
	
	/**
	 * Add num minutes
	 * 
	 * @param date
	 * @param num
	 * @return
	 */
	private static Date addMinute( Date date, int num )
	{
		Calendar startCal = getCalendar( date );

		startCal.add( Calendar.MINUTE, num );

		return startCal.getTime( );
	}

	private class Function_AddSecond extends Function_temp
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		Function_AddSecond( )
		{
			length = 2;
			isFixed = true;
		}
			
		protected Object getValue( Object[] args ) throws BirtException
		{
			return addSecond(DataTypeUtil.toDate(args[0]), ((Number)args[1]).intValue( ));
		}
	}	
	
	/**
	 * Add num seconds
	 * 
	 * @param date
	 * @param num
	 * @return
	 */
	private static Date addSecond( Date date, int num )
	{
		Calendar startCal = getCalendar( date );

		startCal.add( Calendar.SECOND, num );

		return startCal.getTime( );
	}

	
	/**
	 * 
	 * @param d
	 * @param startDay
	 * @return
	 */
	private static int getWeekDay( Date d, int startDay )
	{
		int dayOfWeek = getCalendar( d ).get( Calendar.DAY_OF_WEEK );
		if ( dayOfWeek >= startDay )
		{
			return dayOfWeek - startDay + 1;
		}
		else
		{
			return ( dayOfWeek - startDay + 1 + 7 ) % 8;
		}

	}

	/**
	 * 
	 * @param d
	 * @return
	 */
	private static Calendar getCalendar( Date d )
	{
		if ( d == null )
			throw new java.lang.IllegalArgumentException( "date value is null!" );
		Calendar c = Calendar.getInstance( );
		c.setTime( d );
		return c;
	}

	public String getClassName( )
	{
		return "BirtDateTime";
	}
}
