/**
 * @class ep.Date
 * 
 */

/**
 * Sum or subtract days for the date object.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Integer} days A number of days.
 * 
 * @method addDate
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * Sum or subtract days for the date object.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Integer} days A number of days.
 * 
 * @method addDay
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * Sum or subtract years for the date object.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Integer} years A number of years.
 * 
 * @method addFullYear
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * Sum or subtract hours for the date object.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Integer} hours A number of hours.
 * 
 * @method addHours
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * Sum or subtract milliseconds for the date object.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Integer} milliseconds A number of milliseconds.
 * 
 * @method addMilliseconds
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * Sum or subtract minutes for the date object.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Integer} minutes A number of minutes.
 * 
 * @method addMinutes
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * Sum or subtract months for the date object.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Integer} months A number of months.
 * 
 * @method addMonth
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * Sum or subtract seconds for the date object.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Integer} seconds A number of seconds.
 * 
 * @method addSeconds
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * Sum or subtract milliseconds for the date object.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Integer} milliseconds A number of milliseconds.
 * 
 * @method addTime
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * Sum or subtract seconds for the date object.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Integer} seconds A number of seconds.
 * 
 * @method addUnixTime
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * The `.compareDate()` method compares a date with the current date without consideration of the time.
 * Returns an integer indication:
 * 
 *  + date(current date) > date(givn date) = 1
 *  + date(current date) == date(givn date) = 0
 *  + date(current date) < date(givn date) = -1
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Object} date A date object to compare.
 * 
 * @method compareDate
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * The `.compareTime()` method compares a the time between a date and the current date without consideration of the date.
 * Returns an integer indication:
 * 
 *  + time(current date) > time(givn date) = 1
 *  + time(current date) == time(givn date) = 0
 *  + time(current date) < time(givn date) = -1
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Object} date A date object to compare.
 * 
 * @method compareTime
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * The `.diffDate()` method returns difference of days between current date and givn date.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Object} date A date object to get a diff.
 * 
 * @method diffDate
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * The `.diffDay()` method returns difference of days between current date and givn date.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Object} date A date object to get a diff.
 * 
 * @method diffDay
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * The `.diffFullYear()` method returns difference of years between current date and givn date.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Object} date A date object to get a diff.
 * 
 * @method diffFullYear
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * The `.diffHours()` method returns difference of hours between current date and givn date.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Object} date A date object to get a diff.
 * 
 * @method diffHours
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * The `.diffMilliseconds()` method returns difference of milliseconds between current date and givn date.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Object} date A date object to get a diff.
 * 
 * @method diffMilliseconds
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * The `.diffMinutes()` method returns difference of minutes between current date and givn date.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Object} date A date object to get a diff.
 * 
 * @method diffMinutes
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * The `.diffMonth()` method returns difference of months between current date and givn date.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Object} date A date object to get a diff.
 * 
 * @method diffMonth
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * The `.diffSeconds()` method returns difference of seconds between current date and givn date.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Object} date A date object to get a diff.
 * 
 * @method diffSeconds
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * The `.diffTime()` method returns difference of miliseconds between current date and givn date.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Object} date A date object to get a diff.
 * 
 * @method diffTime
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/**
 * The `.diffUnixTime()` method returns difference of seconds between current date and givn date.
 * 
 * ### Dependencies
 * 
 *  + `ep`
 *  + `jQuery.i18n`
 *  + `jQuery.class`
 * 
 * @param {Object} date A date object to get a diff.
 * 
 * @method diffUnixTime
 * @member ep.Date
 * 
 * @since 6.11.0
 */

/*
 * @copyright		© Copyright 2006-2010, epages GmbH, All Rights Reserved.
 *
 * @module			ep.date
 *
 * @revision		$Revision: 1.8 $
 */

define("ep/date", [
	"jquery",
	"ep",
	"class",

	"jquery/i18n"
], function ($, ep, Class) {

	var noGetExp = /^(UnixTime)/,
		noSetExp = /^(Day|UnixTime)$/,
		noAddExp = /^UTC/,
		proto = {};

	// $.extend with property prototype doesn't work in IE lte 8
	/**
	 * Using advanced date operations.
	 * 
	 * The `ep.Date()` method works like the native javascript `Date()` method and supports the same prototype methods.
	 * 
	 * If no parameter is provided, the created date object represents the current time.
	 * 
	 * If only one parameter is provided, and this parameter is a string, the date is created from this string. It is assumed
	 * that the string has the format "monthName day, year hours:minutes:seconds".
	 * 
	 * If only one parameter is provided, and this parameter is an integer, the date is created from this number, which is
	 * interpreted as the milliseconds since Januar 1th 1970.
	 * 
	 * Getter in `ep.Date()` return the same value as the native function:
	 * 
	 *  + toGMTString, UTC, getDate, getDay, getFullYear, getHours, getMilliseconds, getMinutes, getMonth, getSeconds, getTime, getTimezoneOffset, getUTCDate, getUTCFullYear, getUTCHours, getUTCMilliseconds, getUTCMinutes, getUTCMonth, getUTCSeconds, getYear
	 * 
	 * Setter in `ep.Date()` set the same value(s) as the native function but return the current instance of ep.Date:
	 * 
	 *  + parse, setDate, setFullYear, setHours, setMilliseconds, setMinutes, setMonth, setSeconds, setTime, setUTCDate, setUTCFullYear, setUTCHours, setUTCMilliseconds, setUTCMinutes, setUTCMonth, setUTCSeconds, setYear
	 * 
	 * ### Examples
	 * Simply date operation.
	 * 
	 * JavaScript:
	 * 
	 *     new ep.Date(2009,1,17)
	 *             .addDate(4)
	 *             .addFullYear(-2)
	 *             .toGMTString();
	 * 
	 * Results:
	 * 
	 *     Tue, 20 Feb 2009 00:00:00 GMT
	 * 
	 * 
	 * ### Dependencies
	 * 
	 *  + `ep`
	 *  + `jQuery.i18n`
	 *  + `jQuery.class`
	 * 
	 * @param {Integer} year A full year number.
	 * @param {Integer} month A zero indexed month of the year.
	 * @param {Integer} day A day of the month.
	 * @param {Integer} [hours] An hour in 24 hours format.
	 * @param {Integer} [minutes] A minute.
	 * @param {Integer} [seconds] A second.
	 * 
	 * @method constructor
	 * @member ep.Date
	 * 
	 * @since 6.11.0
	 */
	proto.constructor = function( a, b, c, d, e, f, g ){
		switch( arguments.length ) {
			case 1:
				this.date = new Date( (/^-?\d+$/).test(a) ? parseInt(a,10) : a instanceof Date || a instanceof ep.Date ? a.getTime() : a );
			break;
			case 3:
				this.date = new Date( a, b, c );
			break;
			case 6:
				this.date = new Date( a, b, c, d, e, f );
			break;
			case 7:
				this.date = new Date( a, b, c, d, e, f, g );
			break;
			default:
				this.date = new Date();
			break;
		}
		return this;
	};

	// advanced
	$.extend(proto,{
		// clone
		/**
		 * Clone the current date object, `.clone()` returns a new instance of `ep.Date()` with the same date as the current date object.
		 * 
		 * ### Dependencies
		 * 
		 *  + `ep`
		 *  + `jQuery.i18n`
		 *  + `jQuery.class`
		 * 
		 * @method clone
		 * @member ep.Date
		 * 
		 * @since 6.11.0
		 */
		clone: function(){
			return new ep.Date( this.getTime() );
		},
		// i18n format
		/**
		 * The `.getFormat()` returns a formatted string of the date using `jQuery.i18n`.
		 * 
		 * ### Dependencies
		 * 
		 *  + `ep`
		 *  + `jQuery.i18n`
		 *  + `jQuery.class`
		 * 
		 * @param {String} format A formatter string.
		 * @param {Object} [options] A map of additional options pass to the method.
		 * 
		 * @method getFormat
		 * @member ep.Date
		 * 
		 * @since 6.11.0
		 */
		getFormat: function( format, options ){
			return $.i18n.formatDate( this.date, format, options );
		},
		/**
		 * The `.setFormat()` set a date from a string with specified format using `jQuery.i18n`.
		 * 
		 * ### Dependencies
		 * 
		 *  + `ep`
		 *  + `jQuery.i18n`
		 *  + `jQuery.class`
		 * 
		 * @param {String} value A value to set as date.
		 * @param {String} format A formatter to patse the value.
		 * @param {Object} [options] A map of additional options pass to the method.
		 * 
		 * @method setFormat
		 * @member ep.Date
		 * 
		 * @since 6.11.0
		 */
		setFormat: function( value, format, options ){
			var date = $.i18n.parseDate( value, format,  options );

			if( date ){
				this.setTime( date.getTime() );
			}
			return this;
		},
		// leap year
		/**
		 * The `.isLeapYear()` method returns a boolean indication wether the current date is in a leap year.
		 * 
		 * ### Dependencies
		 * 
		 *  + `ep`
		 *  + `jQuery.i18n`
		 *  + `jQuery.class`
		 * 
		 * @method isLeapYear
		 * @member ep.Date
		 * 
		 * @since 6.11.0
		 */
		isLeapYear: function(){
			var year = this.getFullYear();
			return !(year%400) || (!(year%4) && !!(year%100));
		},
		// days of month
		/**
		 * The `.getMonthLength()` method returns the the count of days in current month.
		 * 
		 * ### Dependencies
		 * 
		 *  + `ep`
		 *  + `jQuery.i18n`
		 *  + `jQuery.class`
		 * 
		 * @method getMonthLength
		 * @member ep.Date
		 * 
		 * @since 6.11.0
		 */
		getMonthLength: function(){
			var month = this.getMonth(),
				days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

			if( month===1 && this.isLeapYear() ){
				return 29;
			}
			return days[month];
		},
		/**
		 * The `.setFirstMonthDay()` method sets the date to to the first day of the current month.
		 * 
		 * ### Dependencies
		 * 
		 *  + `ep`
		 *  + `jQuery.i18n`
		 *  + `jQuery.class`
		 * 
		 * @method setFirstMonthDay
		 * @member ep.Date
		 * 
		 * @since 6.11.0
		 */
		setFirstMonthDay: function(){
			this.setDate( 1 );
			return this;
		},
		/**
		 * The `.setLastMonthDay()` method sets the date to to the last day of the current month.
		 * 
		 * ### Dependencies
		 * 
		 *  + `ep`
		 *  + `jQuery.i18n`
		 *  + `jQuery.class`
		 * 
		 * @method setLastMonthDay
		 * @member ep.Date
		 * 
		 * @since 6.11.0
		 */
		setLastMonthDay: function(){
			this.setDate( this.getMonthLength() );
			return this;
		},
		// day of week
		/**
		 * The `.setDay()` method sets the date to an other speciefied weekday in the current week.
		 * 
		 * ### Dependencies
		 * 
		 *  + `ep`
		 *  + `jQuery.i18n`
		 *  + `jQuery.class`
		 * 
		 * @param {Integer} day A zero index weekday.
		 * 
		 * @method setDay
		 * @member ep.Date
		 * 
		 * @since 6.11.0
		 */
		setDay: function( set ){
			this.setDate( this.getDate() + ( set - this.getDay() ) );
			return this;
		},
		// unix time
		/**
		 * The `.getUnixTime()` method returns the date as unixtime (seconds since Januar 1th 1970).
		 * 
		 * ### Dependencies
		 * 
		 *  + `ep`
		 *  + `jQuery.i18n`
		 *  + `jQuery.class`
		 * 
		 * @method getUnixTime
		 * @member ep.Date
		 * 
		 * @since 6.11.0
		 */
		getUnixTime: function(){
			return Math.round( this.getTime() / 1000 );
		},
		/**
		 * The `.setUnixTime()` method set the current date to the givn unixtime.
		 * 
		 * ### Dependencies
		 * 
		 *  + `ep`
		 *  + `jQuery.i18n`
		 *  + `jQuery.class`
		 * 
		 * @param {Integer} unixtime A unixtime (seconds since Januar 1th 1970).
		 * 
		 * @method setUnixTime
		 * @member ep.Date
		 * 
		 * @since 6.11.0
		 */
		setUnixTime: function( set ){
			this.setTime( set * 1000 );
			return this;
		},
		// UTC unix time
		/**
		 * The `.getUTCUnixTime()` method returns the date as unixtime (seconds since Januar 1th 1970).
		 * However, it is not the local time but the Universal Coordinated Time (UTC) time get.
		 * 
		 * ### Dependencies
		 * 
		 *  + `ep`
		 *  + `jQuery.i18n`
		 *  + `jQuery.class`
		 * 
		 * @method getUTCUnixTime
		 * @member ep.Date
		 * 
		 * @since 6.11.0
		 */
		getUTCUnixTime: function(){
			return this.getUnixTime() - this.getTimezoneOffset()*60;
		},
		/**
		 * The `.setUTCUnixTime()` method is the same as `.setUnixTime()`. However, it is not the local time but the Universal Coordinated Time (UTC) time set.
		 * 
		 * ### Dependencies
		 * 
		 *  + `ep`
		 *  + `jQuery.i18n`
		 *  + `jQuery.class`
		 * 
		 * @param {Integer} unixtime A unixtime (seconds since Januar 1th 1970).
		 * 
		 * @method setUTCUnixTime
		 * @member ep.Date
		 * 
		 * @since 6.11.0
		 */
		setUTCUnixTime: function( set ){
			this.setUnixTime(set);
			this.addTime( this.getTimezoneOffset()*60000 );
			return this;
		}
	});

	// compare
	$.each({
		'Date': 'Hours',
		'Time': 'FullYear'
	},function( name, set ){
		proto[ 'compare' + name ] = function( date ){
			if( !date){
				date = new Date();
			}
			var thisDate = new Date( this.getTime() ),
				compDate = new Date( date.getTime() );

			thisDate[ 'set' + set ](0,0,0,0);
			compDate[ 'set' + set ](0,0,0,0);

			var thisTime = thisDate.getTime(),
				compTime = compDate.getTime();

			if( thisTime > compTime ){
				return 1;
			}
			else if( thisTime < compTime ){
				return -1;
			}
			else{
				return 0;
			}
		};
	});

	// get only
	$.each([
		'toGMTString',
		'toLocaleString',
		'getTimezoneOffset'
	],function( i, name ){
		proto[ name ] = function(){
			return this.date[ name ]();
		};
	});

	// add, get, set, diff
	$.each({
		'FullYear':			31536000000,
		'Month':			2592000000,
		'Day':				604800000,
		'Date':				86400000,
		'Hours':			3600000,
		'Minutes':			60000,
		'Seconds':			1000,
		'Milliseconds':		1,
		'Time':				1,
		'UTCDate':			0,
		'UTCFullYear':		0,
		'UTCHours':			0,
		'UTCMilliseconds':	0,
		'UTCMinutes':		0,
		'UTCMonth':			0,
		'UTCSeconds':		0,
		'UnixTime':			1000
	},function( name, math ){
		// get methods
		if( !noGetExp.test(name) ){
			proto[ 'get' + name ] = function(){
				return this.date[ 'get' + name ]();
			};
		}
		// set methods
		if( !noSetExp.test(name) ){
			proto[ 'set' + name ] = function(){
				this.date[ 'set' + name ].apply( this.date, arguments );
				return this;
			};
		}
		if( !noAddExp.test(name) ){
		// add methods
			proto[ 'add' + name ] = function( add ){
				this[ 'set' + name ]( this[ 'get' + name ]() + add );
				return this;
			};
		// diff methods
			proto[ 'diff' + name ] = function( date ){
				if( !date){
					date = new Date();
				}
				return Math.round( ( date.getTime() - this.getTime() ) / math );
			};
		}
	});

	Class('ep.Date', proto);

	return ep;

});