text: dojo.provide("dojox.date.islamic.Date");
  
  dojo.require("dojo.date");
  dojo.requireLocalization("dojo.cldr", "islamic");
  
  dojo.declare("dojox.date.islamic.Date", null, {
  	// summary: The component defines the Islamic (Hijri) Calendar Object
  	//
  	// description:
  	//	This module is similar to the Date() object provided by JavaScript
  	//
  	// example:
  	// |	dojo.require("dojox.date.islamic.Date");
  	// |
  	// |	var date = new dojox.date.islamic.Date();
  	// |	document.writeln(date.getFullYear()+'\'+date.getMonth()+'\'+date.getDate());
  
  
  	_date: 0,
  	_month: 0,
  	_year: 0,
  	_hours: 0,
  	_minutes: 0,
  	_seconds: 0,
  	_milliseconds: 0,
  	_day: 0,
  	_GREGORIAN_EPOCH : 1721425.5,
  	_ISLAMIC_EPOCH : 1948439.5,
  
  	constructor: function(){
  		// summary: This is the constructor
  		// description:
  		//	This function initialize the date object values
  		//
  		// example:
  		// |		var date1 = new dojox.date.islamic.Date();
  		// |
  		// |		var date2 = new dojox.date.islamic.Date("12\2\1429");
  		// |
  		// |		var date3 = new dojox.date.islamic.Date(date2);
  		// |
  		// |		var date4 = new dojox.date.islamic.Date(1429,2,12);
  
  		var len = arguments.length;
  		if(!len){// use the current date value, added "" to the similarity to date
  			this.fromGregorian(new Date());
  		}else if(len == 1){
  			var arg0 = arguments[0];
  			if(typeof arg0 == "number"){ // this is time "valueof"
  				arg0 = new Date(arg0);
  			}
  
  			if(arg0 instanceof Date){
  				this.fromGregorian(arg0);
  			}else if(arg0 == ""){
  				// date should be invalid.  Dijit relies on this behavior.
  				this._date = new Date(""); //TODO: should this be NaN?  _date is not a Date object
  			}else{  // this is Islamic.Date object
  				this._year = arg0._year;
  				this._month =  arg0._month;
  				this._date = arg0._date;
  				this._hours = arg0._hours;
  				this._minutes = arg0._minutes;
  				this._seconds = arg0._seconds;
  				this._milliseconds = arg0._milliseconds;
  			}
  		}else if(len >=3){
  			// YYYY MM DD arguments passed, month is from 0-12
  			this._year += arguments[0];
  			this._month += arguments[1];
  			this._date += arguments[2];
  			this._hours += arguments[3] || 0;
  			this._minutes += arguments[4] || 0;
  			this._seconds += arguments[5] || 0;
  			this._milliseconds += arguments[6] || 0;
  		}
  	},
  
  	getDate:function(){
  		// summary: This function returns the date value (1 - 30)
  		//
  		// example:
  		// |		var date1 = new dojox.date.islamic.Date();
  		// |
  		// |		document.writeln(date1.getDate);
  		return this._date;
  	},
  	
  	getMonth:function(){
  		// summary: This function return the month value ( 0 - 11 )
  		//
  		// example:
  		// |		var date1 = new dojox.date.islamic.Date();
  		// |
  		// |		document.writeln(date1.getMonth()+1);
  
  		return this._month;
  	},
  
  	getFullYear:function(){
  		// summary: This function return the Year value
  		//
  		// example:
  		// |		var date1 = new dojox.date.islamic.Date();
  		// |
  		// |		document.writeln(date1.getFullYear());
  
  		return this._year;
  	},
  		
  	getDay:function(){
  		// summary: This function return Week Day value ( 0 - 6 )
  		//
  		// example:
  		// |		var date1 = new dojox.date.islamic.Date();
  		// |
  		// |		document.writeln(date1.getDay());
  
  		return this.toGregorian().getDay();
  	},
  		
  	getHours:function(){
  		//summary: returns the Hour value
  		return this._hours;
  	},
  	
  	getMinutes:function(){
  		//summary: returns the Minuites value
  		return this._minutes;
  	},
  
  	getSeconds:function(){
  		//summary: returns the seconde value
  		return this._seconds;
  	},
  
  	getMilliseconds:function(){
  		//summary: returns the Milliseconds value
  		return this._milliseconds;
  	},
  
  	setDate: function(/*number*/date){
  		// summary: This function sets the Date
  		// example:
  		// |		var date1 = new dojox.date.islamic.Date();
  		// |		date1.setDate(2);
  
  		date = parseInt(date);
  
  		if(date > 0 && date <= this.getDaysInIslamicMonth(this._month, this._year)){
  			this._date = date;
  		}else{
  			var mdays;
  			if(date>0){
  				for(mdays = this.getDaysInIslamicMonth(this._month, this._year);
  					date > mdays;
  						date -= mdays,mdays =this.getDaysInIslamicMonth(this._month, this._year)){
  					this._month++;
  					if(this._month >= 12){this._year++; this._month -= 12;}
  				}
  
  				this._date = date;
  			}else{
  				for(mdays = this.getDaysInIslamicMonth((this._month-1)>=0 ?(this._month-1) :11 ,((this._month-1)>=0)? this._year: this._year-1);
  						date <= 0;
  							mdays = this.getDaysInIslamicMonth((this._month-1)>=0 ? (this._month-1) :11,((this._month-1)>=0)? this._year: this._year-1)){
  					this._month--;
  					if(this._month < 0){this._year--; this._month += 12;}
  
  					date+=mdays;
  				}
  				this._date = date;
  			}
  		}
  		return this;
  	},
  
  	setFullYear:function(/*number*/year){
  		// summary: This function set Year
  		//
  		// example:
  		// |		var date1 = new dojox.date.islamic.Date();
  		// |		date1.setYear(1429);
  
  		this._year = +year;
  	},
  
  	setMonth: function(/*number*/month) {
  		// summary: This function set Month
  		//
  		// example:
  		// |		var date1 = new dojox.date.islamic.Date();
  		// |		date1.setMonth(2);
  
  		this._year += Math.floor(month / 12);
  		if(month > 0){
  			this._month = Math.floor(month % 12);
  		}else{
  			this._month = Math.floor(((month % 12) + 12) % 12);
  		}
  	},
  
  	setHours:function(){
  		//summary: set the Hours
  		var hours_arg_no = arguments.length;
  		var hours = 0;
  		if(hours_arg_no >= 1){
  			hours = parseInt(arguments[0]);
  		}
  
  		if(hours_arg_no >= 2){
  			this._minutes = parseInt(arguments[1]);
  		}
  
  		if(hours_arg_no >= 3){
  			this._seconds = parseInt(arguments[2]);
  		}
  
  		if(hours_arg_no == 4){
  			this._milliseconds = parseInt(arguments[3]);
  		}
  
  		while(hours >= 24){
  			this._date++;
  			var mdays = this.getDaysInIslamicMonth(this._month, this._year);
  			if(this._date > mdays){
  					this._month ++;
  					if(this._month >= 12){this._year++; this._month -= 12;}
  					this._date -= mdays;
  			}
  			hours -= 24;
  		}
  		this._hours = hours;
  	},
  
  	setMinutes:function(/*number*/minutes){
  		//summary: set the Minutes
  
  		while(minutes >= 60){
  			this._hours++;
  			if(this._hours >= 24){
  				this._date++;
  				this._hours -= 24;
  				var mdays = this.getDaysInIslamicMonth(this._month, this._year);
  				if(this._date > mdays){
  						this._month ++;
  						if(this._month >= 12){this._year++; this._month -= 12;}
  						this._date -= mdays;
  				}
  			}
  			minutes -= 60;
  		}
  		this._minutes = minutes;
  	},
  		
  		
  	setSeconds:function(/*number*/seconds){
  		//summary: set Seconds
  		while(seconds >= 60){
  			this._minutes++;
  			if(this._minutes >= 60){
  				this._hours++;
  				this._minutes -= 60;
  				if(this._hours >= 24){
  					this._date++;
  					this._hours -= 24;
  					var mdays = this.getDaysInIslamicMonth(this._month, this._year);
  					if(this._date > mdays){
  						this._month ++;
  						if(this._month >= 12){this._year++; this._month -= 12;}
  						this._date -= mdays;
  					}
  				}
  			}
  			seconds -= 60;
  		}
  		this._seconds = seconds;
  	},
  		
  	setMilliseconds:function(/*number*/milliseconds){
  		//summary: set the Millisconds
  		while(milliseconds >= 1000){
  			this.setSeconds++;
  			if(this.setSeconds >= 60){
  				this._minutes++;
  				this.setSeconds -= 60;
  				if(this._minutes >= 60){
  					this._hours++;
  					this._minutes -= 60;
  					if(this._hours >= 24){
  						this._date++;
  						this._hours -= 24;
  						var mdays = this.getDaysInIslamicMonth(this._month, this._year);
  				if(this._date > mdays){
  					this._month ++;
  					if(this._month >= 12){this._year++; this._month -= 12;}
  					this._date -= mdays;
  					}
  				}
  			}
  		}
  			milliseconds -= 1000;
  		}
  		this._milliseconds = milliseconds;
  	},
  		
  		
  	toString:function(){
  		// summary: This returns a string representation of the date in "DDDD MMMM DD YYYY HH:MM:SS" format
  		// example:
  		// |		var date1 = new dojox.date.islamic.Date();
  		// |		document.writeln(date1.toString());
  
  		//FIXME: TZ/DST issues?
  		var x = new Date();
  		x.setHours(this._hours);
  		x.setMinutes(this._minutes);
  		x.setSeconds(this._seconds);
  		x.setMilliseconds(this._milliseconds);
  		return this._month+" "+ this._date + " " + this._year + " " + x.toTimeString();
  	},
  		
  		
  	toGregorian:function(){
  		// summary: This returns the equevalent Grogorian date value in Date object
  		// example:
  		// |		var dateIslamic = new dojox.date.islamic.Date(1429,11,20);
  		// |		var dateGregorian = dateIslamic.toGregorian();
  
  		var hYear = this._year;
  		var hMonth = this._month;
  		var hDate = this._date;
  		var julianDay = hDate + Math.ceil(29.5 * hMonth) + (hYear - 1) * 354
  						+ Math.floor((3 + (11 * hYear)) / 30) + this._ISLAMIC_EPOCH - 1;
  
  		var wjd = Math.floor(julianDay - 0.5) + 0.5,
  			depoch = wjd - this._GREGORIAN_EPOCH,
  			quadricent = Math.floor(depoch / 146097),
  			dqc = this._mod(depoch, 146097),
  			cent = Math.floor(dqc / 36524),
  			dcent = this._mod(dqc, 36524),
  			quad = Math.floor(dcent / 1461),
  			dquad = this._mod(dcent, 1461),
  			yindex = Math.floor(dquad / 365),
  			year = (quadricent * 400) + (cent * 100) + (quad * 4) + yindex;
  		if(!(cent == 4 || yindex == 4)){
  			year++;
  		}
  		
  		var gYearStart = this._GREGORIAN_EPOCH + (365 * (year - 1)) + Math.floor((year - 1) / 4)
  						- ( Math.floor((year - 1) / 100)) + Math.floor((year - 1) / 400);
  						
  		var yearday = wjd - gYearStart;
  		
  		var tjd = (this._GREGORIAN_EPOCH - 1) + (365 * (year - 1)) + Math.floor((year - 1) / 4)
  				-( Math.floor((year - 1) / 100)) + Math.floor((year - 1) / 400) + Math.floor( (739 / 12)
  				+ ( (dojo.date.isLeapYear(new Date(year,3,1)) ? -1 : -2)) + 1);
  			
  		var leapadj = ((wjd < tjd ) ? 0 : (dojo.date.isLeapYear(new Date(year,3,1)) ? 1 : 2));
  					
  		var month = Math.floor((((yearday + leapadj) * 12) + 373) / 367);
  		var tjd2 = (this._GREGORIAN_EPOCH - 1) + (365 * (year - 1))
  					+ Math.floor((year - 1) / 4) - (Math.floor((year - 1) / 100))
  					+ Math.floor((year - 1) / 400) + Math.floor((((367 * month) - 362) / 12)
  					+ ((month <= 2) ? 0 : (dojo.date.isLeapYear(new Date(year,month,1)) ? -1 : -2)) + 1);
  					
  		var day = (wjd - tjd2) + 1;
  
  		var gdate = new Date(year, (month - 1), day, this._hours, this._minutes, this._seconds, this._milliseconds);
  
  		return gdate;
  	},
  
  	//TODO: would it make more sense to make this a constructor option? or a static?
  	// ported from the Java class com.ibm.icu.util.IslamicCalendar from ICU4J v3.6.1 at http://www.icu-project.org/
  	fromGregorian:function(/*Date*/gdate){
  		// summary: This function returns the equivalent Islamic Date value for the Gregorian Date
  		// example:
  		// |		var dateIslamic = new dojox.date.islamic.Date();
  		// |		var dateGregorian = new Date(2008,10,12);
  		// |		dateIslamic.fromGregorian(dateGregorian);
  
  		var date = new Date(gdate);
  		var gYear = date.getFullYear(),
  			gMonth = date.getMonth(),
  			gDay = date.getDate();
  		
  		var julianDay = (this._GREGORIAN_EPOCH - 1) + (365 * (gYear - 1)) + Math.floor((gYear - 1) / 4)
  					+ (-Math.floor((gYear - 1) / 100)) + Math.floor((gYear - 1) / 400)
  					+ Math.floor((((367 * (gMonth+1)) - 362) / 12)
  					+ (((gMonth+1) <= 2) ? 0 : (dojo.date.isLeapYear(date) ? -1 : -2)) + gDay);
  		julianDay = Math.floor(julianDay) + 0.5;
  
  		var days = julianDay - this._ISLAMIC_EPOCH;
  		var hYear  = Math.floor( (30 * days + 10646) / 10631.0 );
  		var hMonth = Math.ceil((days - 29 - this._yearStart(hYear)) / 29.5 );
  		hMonth = Math.min(hMonth, 11);
  		var hDay = Math.ceil(days - this._monthStart(hYear, hMonth)) + 1;
  
  		this._date = hDay;
  		this._month = hMonth;
  		this._year = hYear;
  		this._hours = date.getHours();
  		this._minutes = date.getMinutes();
  		this._seconds = date.getSeconds();
  		this._milliseconds = date.getMilliseconds();
  		this._day = date.getDay();
  		return this;
  	},
  	
  	valueOf:function(){
  		// summary: This function returns The stored time value in milliseconds
  		// since midnight, January 1, 1970 UTC
  
  		return this.toGregorian().valueOf();
  	},
  
  	// ported from the Java class com.ibm.icu.util.IslamicCalendar from ICU4J v3.6.1 at http://www.icu-project.org/
  	_yearStart:function(/*Number*/year){
  		//summary: return start of Islamic year
  		return (year-1)*354 + Math.floor((3+11*year)/30.0);
  	},
  
  	// ported from the Java class com.ibm.icu.util.IslamicCalendar from ICU4J v3.6.1 at http://www.icu-project.org/
  	_monthStart:function(/*Number*/year, /*Number*/month){
  		//summary: return the start of Islamic Month
  		return Math.ceil(29.5*month) +
  			(year-1)*354 + Math.floor((3+11*year)/30.0);
  	},
  
  	// ported from the Java class com.ibm.icu.util.IslamicCalendar from ICU4J v3.6.1 at http://www.icu-project.org/
  	_civilLeapYear:function(/*Number*/year){
  		//summary: return Boolean value if Islamic leap year
  		return (14 + 11 * year) % 30 < 11;
  	},
  
  	// ported from the Java class com.ibm.icu.util.IslamicCalendar from ICU4J v3.6.1 at http://www.icu-project.org/
  	getDaysInIslamicMonth:function(/*Number*/month, /*Number*/ year){
  		//summary: returns the number of days in the given Islamic Month
  		var length = 0;
  		length = 29 + ((month+1) % 2);
  		if(month == 11 && this._civilLeapYear(year)){
  			length++;
  		}
  		return length;
  	},
  
  	_mod:function(a, b){
  		return a - (b * Math.floor(a / b));
  	}
  });
  
  //TODOC
  dojox.date.islamic.Date.getDaysInIslamicMonth = function(/*dojox.date.islamic.Date*/month){
  	return new dojox.date.islamic.Date().getDaysInIslamicMonth(month.getMonth(),month.getFullYear()); // dojox.date.islamic.Date
  };
  