/********************************************************************
This work is licensed under the Creative Commons NonCommercial-
ShareAlike License. To view a copy of this license, visit 
http://creativecommons.org/licenses/nc-sa/1.0 
And sticking with the theme, I'm making an additional request: if 
you do end up using the code, do a good deed in return - donate some
money to your favorite charity, help out at a food kitchen, etc.

The software is provided "as is" and "with all faults." The author makes 
no representations or warranties of any kind concerning the quality, 
accuracy or suitability of the software, either express or implied.
********************************************************************/

/********************************************************************
zcalendar.js

Javascript methods to perform calculations based on the Shenshai/Fasli 
calendar.  Generally speaking, with regard to function names, "Roj"
indicates a Zoroastrian Calendar

	convertRojToDate(roj, mah, yzYear)
		converts roj/mah/yzYear to gregorian date
		
	convertRojToDateInYear(roj, mah, gregorianYear)	
		Determines date that roj and mah occurs in gregorian year.
	
	convertDateToRoj(aDate) - 
		converts a gregorian date to roj/mah/yzYear. returns a 
		ZCalendar.CalendarDate.
	
	convertDateToRojInYear(aDate, year) - 
		converts a gregorian date to roj/mah/yzYear and determines 
		when the roj occurs in the given gregorian year. returns a 
		ZCalendar.CalendarDate

	mapRojToYear(aDate,aYear) - 	
		Determines roj date for a given year based on a given date.
		
	getNavrozeDate(aYear) - 
		Calculate Navroze (New Year) for a given year.
	
	getPrecedingNavrozeDate(date) - 
		Calculate preceding Navroze (New Year) for a given date.
		
	getRojNamesForMonth(aDate) -
		Returns a DayMonthPair array of the names of the roj/mah for 
		the days in the month of the given date.
		
	buildCalendar(aDate) -
		builds a calendar month in HTML showing roj/mah names.

Dependencies - 
	prototype.js
		
********************************************************************/

// check dependencies
if(typeof Prototype=='undefined')
      throw("ZCalendar requires the Prototype JavaScript framework >= 1.3");


Array.prototype.indexOf = function(value) {
	for (var i=0; i<this.length; i++) {
		if (value == this[i]) return i;
	}
	return -1;
}

/**
 * ZCalendar class for Zoroastrian Calendar functions.
 */
var ZCalendar = {

  	Version: '0.6',

	SHENSHAI: "shenshai",
	
	FASLI: "fasli",
	
	KADMI: "kadmi",
	
	calendarType: "shenshai", // default calendar type
	
	/**
	 * Set the calendar type
	 * @param calType - calendar type (either "shenshai" or "fasli")
	 */
	setCalendarType: function(calType) {
		this.calendarType = calType;
	},
	
	/**
	 * Return the calendar type.
	 * Returns "shenshai" if no calendar type set
	 * @return the calendar type
	 */
	getCalendarType: function() {
		if (this.calendarType==null)
			this.setCalendarType(this.SHENSHAI);
		return this.calendarType;
	},
	
	/**
	 * Returns a Zoroastrian Calendar implementation based on calendar type.
	 * Fasli & Shenshai calendar implementations are supported.
	 * @param cType - the calendar type (optional).  If unspecified, then
	 * ZCalendar.calendarType is used.
	 * @return a fasli or shenshai calendar implementation
	 */
	getCalendar: function(cType /*optional*/) {
		var calType = this.getCalendarType();
		if (arguments.length>0 && calType!=null)
			calType = cType;
		
		if (calType==this.FASLI) {
			return ZCalendar.Fasli;
		} else if (calType==this.KADMI) {
			return ZCalendar.Kadmi;
		} else { // use Shenshai calendar by default
			return ZCalendar.Shenshai;
		}
	},
	
	/**
	 * Gets a calendar implementation and renders an HTML calendar.
	 * @param aDate - Gregorian date specifying month/year to render
	 * @return an HTML string of the calendar for the month
	 */
	buildCalendar: function(aDate) {
		// delegate to specific calendar implementation
		return this.getCalendar().buildCalendar(aDate);
	}
};


/*
 *	A utility object to hold the roj/mah/year info
 */
ZCalendar.CalendarDate = Class.create();
ZCalendar.CalendarDate.prototype = {
	// constructor
	initialize: function(rojName, mahName, zYear, date) {
		this.roj = rojName;
		this.mah= mahName || "";
		this.yzYear= zYear || "";
		this.gregorianDate = date;
	}, 
	
	equals: function(cal) {
		if (cal == null) return false;
		else if (
				((this.roj==null && cal.roj==null) || this.roj == cal.roj) &&
				((this.mah==null && cal.mah==null) || this.mah == cal.mah) &&
				//((this.yzYear==null && cal.yzYear==null) || this.yzYear == cal.yzYear) &&
				((this.gregorianDate==null && cal.gregorianDate==null) || this.gregorianDate.getTime() == cal.gregorianDate.getTime())
			) {
			
			return true;
		}
		return false;
	},
		
	toString: function() {
		var msg = "" + this.roj + " roj";
		if (this.mah != null && this.mah != "") {
			msg += ", " + this.mah + " mah" ;
		}
		//if (this.yzYear != null && this.yzYear != "") {
		//		msg += ", " + this.yzYear + " Y.Z." ;
		//}
		return msg;
	},
	
	toFullString: function() {
		var msg = this.toString();
		if (this.gregorianDate != null && this.gregorianDate != "") {
			msg += ", occurs on " + this.gregorianDate.format("month dd, yyyy");
		}
		return msg;
	},
	
	debug: function() {
		s = "CalendarDate: roj="+this.roj+" mah="+this.mah+" yzYear="+this.yzYear+" gregorianDate=" + this.gregorianDate;
		return s;
	}
	
};

/********************************************************************

	Abstract Base Calendar

********************************************************************/
// try a little oo goodness here... abstract base class containing
// methods common to calendar subclasses
ZCalendar.AbstractBaseCalendar = {
	
	EPOCH_YEAR: 1129,
	
	EPOCH_DATE: new Date(1129, 2, 21),
	
	EQUINOX_DATE: new Date(new Date().getFullYear(), 2, 21),
	
	YZ_EPOCH_DATE: new Date(632, 6, 16),
	
	MAH: new Array(
		"Fravardin","Ardibehesht","Khordad","Tir","Amardad","Shehrevar",
		"Meher","Avan","Adar","Dae","Bahman","Aspandard"),
	
	ROJ: new Array(
	"Hormazd", "Bahman", "Ardibehesht", "Shehrevar", "Aspandard", 
	"Khordad", "Amardad","Dae-Pa-Adar","Adar","Avan",
	"Khorshed","Mohor","Tir", "Gosh","Dae-Pa-Meher",
	"Meher","Srosh","Rashne","Fravardin","Behram",
	"Ram","Govad","Dae-Pa-Din","Din","Ashishvangh",
	"Ashtad","Asman","Zamyad","Mareshpand","Aneran"),
	
	GATHAS: new Array("Ahunavaiti", "Ushtavaiti","Spentamainyu","Vohuxshathra","Vahishtoishti"),
	
	calendarType: "",
	
	/*
	 *	Returns a formatted string showing today's
	 *	Zoroastrian date info (roj,mah,year)
	 */
	getZDateForToday: function() {
		// get the zdate using today's gregorian date
		calDate = this.convertDateToRoj(new Date());

		// build the result message
		msg = "Today is " + calDate.toString();
		msg += " (" + this.calendarType + ")";
		return msg;
	},

	/**
	 * Given a gregorian date, find when the corresponding roj occurs in the given year.
	 * @param aDate - a date to calculate the roj from;
	 * @param aYear - the year in which to calculate when the roj occurs
	 * @returns - a Date object representing the roj on which the date
	 * falls in the gregorian calendar
	 * @deprecated  - use convertDateToRojInYear
	 */
	mapRojToYear: function(aDate, aYear) {
		throw("AbstractBaseCalendar.mapRojToYear() - implement in subclass");
	},
	
	/**
	 * Convert a Zoroastrian Date to Gregorian Date.
	 * @param roj - the roj name
	 * @param mah - the mah name
	 * @param yzYear - the Yazdegard era year
	 * @return - a Date object representing when in the Gregorian calendar the roj occurs
	 */
	convertRojToDate: function(roj, mah, yzYear) {
		throw("AbstractBaseCalendar.convertRojToDate() - unimplemented");
	},

	/**
	 * Determines the date for a given roj and mah in a given year
	 * @param roj - the roj name
  	 * @param mah- the mah name
	 * @param aYear - Gregorian year in which to find when the roj/mah occurs (e.g., 2002)
	 * @returns - a Date object representing the gregorian date on which the roj/mah
	 * occurs in the gregorian calendar
	 */
	convertRojToDateInYear: function(roj, mah, year) {
		var currentDate = new Date();
		var months = 0;
		var days = 0;
		var diff;
		var isLeapYear = new Date(year, 0, 1).isLeapYear();

		// figure out the number of days
		// determine the difference in days between the date given and 
		// the prior navroze
		var gathaIndex = this.GATHAS.indexOf(roj);
		if (gathaIndex > -1) {
			diff = gathaIndex + 360;
		}
		else {
			var rojIndex = this.ROJ.indexOf(roj);
			var mahIndex = this.MAH.indexOf(mah);
			diff = Number(mahIndex * 30) + Number(rojIndex);
			//alert("rx=" +rojIndex+ " mx=" +mahIndex+ " diff=" + diff);
		}
		//alert(" diff=" + diff);
		var resultDate, navroze;
		var navrozeYear = year-1;
		// we need to determine if we should add diff to given year's
		// navroze or previous year's navroze. 
		// if the days to add (diff) to the navroze puts us in the
		// wrong year, recalculate using the previous year's
		// navroze.  This is basically the same calc, only we start
		// with navroze for previous year, and if years don't match, 
		// recalculate for current year.
		do {
			navroze = this.getNavrozeDate(navrozeYear++);
			resultDate = navroze.clone();
			resultDate.addDay(diff);
		} while (resultDate.getFullYear() < year)
		
		return resultDate;
	},


	/**
	 * Returns a CalendarDate containing Zoroastrian Date info (roj/mah/YZ year)
	 * corresponding to the given gregorian date.
	 * If the day has no mah (e.g., gathas), then mah will be set to null.
	 * @param aDate - the gregorian date to convert to zoroastring date
	 * @return - a CalendarDate containing Zoroastrian Date info (roj/mah/YZ year)
	 */
	convertDateToRoj: function(aDate) {
		// the roj/month name is determined by difference in days
		// between the date provided and the newyear (navroze), 
		// then finding the corresponding value in the ROJ/MAH
		// arrays.  For example, if the given date was 65 days past
		// navroze, then that falls on the fifth day of the second month.
		// The exception to the rule is if the difference in days is
		// greater than 360.  In this case, since 12 months * 30 days
		// only adds up to 360, we need to look up the day in the 
		// GATHAS array.

		var months;
		var days;
		var diff;

		// the CalendarDate will hold the roj/mah name
		var calDate = new ZCalendar.CalendarDate();

		// first figure out when navroze is on the year
		var navroze = this.getPrecedingNavrozeDate(aDate);

		// determine the difference in days between the date given and 
		// the prior navroze
		diffInDays = Date.daysDiff(aDate, navroze);

		// if the difference in days greater than 360, then lookup the name
		// in the GATHAS array
		if (diffInDays >= 360) {
			days = diffInDays%30;
			calDate.roj = this.GATHAS[days];
			//calDate.month = "";
		}

		// otherwise figure out how many months + how many days
		// this difference corresponds to, and retrieve the corresponding
		// names from the ROJ/MAH array
		else {
			months = Math.floor(diffInDays/30);
			days = diffInDays%30;
			calDate.roj = this.ROJ[days];
			calDate.mah  = this.MAH[months];
		}
		
		var zyear = this.computeYZYear(aDate);
		calDate.yzYear = zyear;

		return calDate;
	},
	
	/**
	 * Returns a CalendarDate containing Zoroastrian date info (roj/mah/YZ year)
	 * corresponding to the given date in the given year.
	 * Implemented by computing the roj/mah for the given date, then computing
	 * when in the given year that roj/mah occurs.
	 * @param aDate - the gregorian date to convert to zoroastring date
	 * @param year - the gregorian year in which to compute when the roj/mah
	 *  for the given date occurs
	 * @return - a CalendarDate containing month name and roj name and
	 *  the gregorian date on which the roj/mah occurs in the specified year
	 */
	convertDateToRojInYear: function(aDate, year) {
		// get the roj name of the roj
		var zcalDate = this.convertDateToRoj(aDate);

		// either approach should work...
		//var rojDate = calendar.mapRojToYear(inputDate, inputYear);
		zcalDate.gregorianDate = this.convertRojToDateInYear(zcalDate.roj, zcalDate.mah, year);
		
		return zcalDate;
	},
	
	/**
	 * Computes the Yazdegard year for a Gregorian date.
	 * @param aDate - a gregorian date
	 * @returns - the Yazdegard year for the gregorian date in "yyyy" format
	 */
	computeYZYear: function(aDate) {
		return Date.yearsDiff(this.YZ_EPOCH_DATE, aDate);
	},
	
	/**
	 * Calculate Navroze (New Year) for a given year.
 	 * @param aYear - the year ('yyyy' format) for which to calculate navroze
	 * @return - a Date object representing Navroze
	 */
	getNavrozeDate: function(aYear) {
		throw("AbstractBaseCalendar.getNavrozeDate() - implement in subclass");
	},
	
	/** 
	 * Calculate the Navroze (New Year) date occuring on or before the given
	 * date
	 * @param aDate - the date to find preceding Navroze for
	 * @return - a Date object representing the preceding Navroze
	 */
	getPrecedingNavrozeDate: function(aDate) {
		var navroze = this.getNavrozeDate(aDate.getFullYear());
		if (aDate < navroze) {
			navroze = this.getNavrozeDate(aDate.getFullYear() - 1);
		}
		return navroze;
	},

	/**
	 * Returns a CalendarDate array of the names of the roj/mah for 
	 * the days in the month of the given date.
	 *
	 * This function is a helper function to buildCalendar.
	 * @param aDate - the Date to retrieve the roj/mah names for
	 * @return - an array of DayMonthPair objects populated with the
	 *	names of roj/mah for all the days in the month
	 */
	getRojNamesForMonth: function(aDate) {
		throw("AbstractBaseCalendar.getRojNamesForMonth() - implement in subclass");
	},
	
	/**
	 * Returns a string displaying a calendar month in HTML.
	 * The calendar month shows the gregorian calendar date along
	 * with the Zoroastrian calendar roj/mah name.
	 * @param aDate - the date to build the calendar month for
	 * @return - an html string of the month.
	 */
	buildCalendar: function(aDate) {
		var dayCounter = 1;
		var dayOfWeekCounter = 0;
		var s;
		var isCalendarForCurrentMonth = false;

		var currentDate = new Date();
		var currentDayInMonth = currentDate.getDate();

		var calDate = new Date(aDate.getFullYear(), aDate.getMonth(), 1);

		// determine what day of the week the first of the month falls on
		var firstDayOfMonth = calDate.getDay();

		// get the number of days in the month
		var daysInMonth = aDate.getDaysInMonth();

		// figure out if this is calendar is for the current month
		if ( (currentDate.getMonth() == aDate.getMonth()) && currentDate.getFullYear() == aDate.getFullYear()) {
			isCalendarForCurrentMonth = true;
		}

		// html to use for a blank day
		var blankDay = "<td class=\"blankDay\">&nbsp;</td>";

		// get the roj/mah names corressponding to the calendar month
		var rojArray = this.getRojNamesForMonth(calDate);
		//alert("rojArray="+rojArray + " length=" + rojArray.length);

		// open the table and append the header row of day names

		s = "<h2>" + calDate.format("month yyyy") + "</h2>";
		s += "<table>";
		s += "<tr><th>Sun</th> <th>Mon</th> <th>Tue</th> <th>Wed</th> <th>Thu</th> <th>Fri</th> <th>Sat</th></tr><tr>";

		// first build the blank days (e.g. if the first falls on a Fri)
		for (i = 0; i < firstDayOfMonth; i++) {
			s += blankDay;
			dayOfWeekCounter++;
		}

		// next build the calendar for the number of days in the month
		for (i = 1; i <= daysInMonth; i++) {
			// build the cell for the day

			// if the cell is for today (current date)...
			if (isCalendarForCurrentMonth && i == currentDayInMonth) {
				s += "<td class=\"currentDate\">";
			}
			else {
				s +="<td>";
			}
			s += "<span class=\"date\">" + i + "</span><br/><br/>"
				+ rojArray[i-1].roj + "<br/>" 
				+ (rojArray[i-1].mah == ""?"":"("+ rojArray[i-1].mah + ")") 
				+ "</td>";

			dayOfWeekCounter++;
			// if this is the 7th day, add a row break
			if (dayOfWeekCounter % 7 == 0) {
				s += "</tr><tr>";
			  }
		 }

		 // next build the blank days at the end of the month (e.g. if
		 // the month ends on a wed, we need to add a few blank days till
		 // the end of the week.
		 for (i = dayOfWeekCounter % 7; i < 7; i++) {
			s += blankDay;
		 }

		 // close the table
		 s += "</tr></table>"
		 // alert(s);
		return s;
	}

}



/********************************************************************

	Shenshai Calendar

********************************************************************/
// use prototype.js for oo behavior

ZCalendar.Shenshai  = new Object();

// Shenshai calendar extends AbstractBaseCalendar
Object.extend(ZCalendar.Shenshai , ZCalendar.AbstractBaseCalendar);

// Shenshai calendar implementation
Object.extend(ZCalendar.Shenshai , {

	MAH: new Array(
		"Fravardin","Ardibehesht","Khordad","Tir","Amardad","Shehrevar",
		"Meher","Avan","Adar","Dae","Bahman","Aspandard"),
	
	ROJ: new Array(
	"Hormazd", "Bahman", "Ardibehesht", "Shehrevar", "Aspandard", 
	"Khordad", "Amardad","Dae-Pa-Adar","Adar","Avan",
	"Khorshed","Mohor","Tir", "Gosh","Dae-Pa-Meher",
	"Meher","Srosh","Rashne","Fravardin","Behram",
	"Ram","Govad","Dae-Pa-Din","Din","Ashishvangh",
	"Ashtad","Asman","Zamyad","Mareshpand","Aneran"),
	
	GATHAS: new Array("Ahunavaiti", "Ushtavaiti","Spentamainyu","Vohuxshathra","Vahishtoishti"),
	
	
	calendarType: "Shenshai",
	
	/*
	 * @see ZCalendar.AbstractBaseCalendar#getNavrozeDate
	 */
	getNavrozeDate: function(aYear) {
		// Navroze is determined by calculating the difference in days
		// between an "epoch" date and the equinox in the given year.
		// The epoch date is Mar-21-1129, the last navroze when the
		// additional 30 days was intercalated to account for ~1/4 day
		// difference between the solar calendar and the Shenshai calendar.

		var daysInYearUntilEquinox = 69;

		// get the equinox for the current year
		var currentEquinox = this.EQUINOX_DATE.clone();
		currentEquinox.setFullYear(aYear);
		
		// Determine the difference in years between the epoch date and the
		// equinox on the current year

		var yearsDiff = Date.yearsDiff(currentEquinox, this.EPOCH_DATE) + 0;
		
		var currentNavroze = this.EPOCH_DATE.clone()

		// add the difference in years * 365 to the epochDate
		if (yearsDiff > daysInYearUntilEquinox) {
			currentNavroze.addDay((yearsDiff+1) * 365);
		}
		else {
			currentNavroze.addDay(yearsDiff * 365);
		}
		return currentNavroze;
	},
	
	/*
	 * @see ZCalendar.AbstractBaseCalendar#mapRojToYear
	 */
	mapRojToYear: function(aDate, aYear) {
		// to figure out the roj, find the difference in years
		// between the date provided and the year provided
		var rojDate = aDate.clone();
		var calcDate = new Date(aYear, aDate.getMonth(), aDate.getDate());

		var yearsDiff = Date.yearsDiff(calcDate, aDate);

		// the roj is the date provided + (the difference in years * 365)
		rojDate.addDay(yearsDiff * 365);

		return rojDate;
	},
	

	/*
	 * @see ZCalendar.AbstractBaseCalendar#getRojNamesForMonth
	 */
	getRojNamesForMonth: function(aDate) {
		// Similar to calculating the roj name, we need to figure out the 
		// difference in days between the first day of the given month and
		// the prior navroze.  Then map the difference to the ROJ/MAH array,
		// and populate the resulting array with roj/mah values for the 
		// number of days in the month of the given date.

		var months = 0;
		var days = 0;
		var diffInDays = 0;
		var dayOffset = 0;

		// calculate the number of days in the month
		var daysInMonth = aDate.getDaysInMonth();

		// create a new array to hold results
		var result = new Array(daysInMonth);

		// determine the prior navroze for the given year
		var navroze = this.getPrecedingNavrozeDate(aDate);
		//alert("navroz=" + navroze);  

		// determine the difference in days between prior navroze and
		// the given date
		daysFromNavroze = Date.daysDiff(aDate, navroze);

		// loop through the days in the month, getting the roj/mah name for
		// each corresponding day.
		for (i=0; i < daysInMonth; i++) {

			diffInDays = daysFromNavroze + dayOffset;
			days = diffInDays % 30;
			// if the difference in days is > 360, these are gathas which
			// have no corresponding month, so pull values from GATHAS array
			// and leave month blank
			if ((diffInDays >= 360) && (diffInDays < 365)) {
				result[i] = new ZCalendar.CalendarDate(this.GATHAS[days]);
			}

			// if the difference in days is 365, then we need to reset the
			// days arg back to 0 to start at the beginning of the month
			else if (diffInDays == 365) {
				days = 0;
				daysFromNavroze = 0;
				dayOffset = 0;
				result[i] = new ZCalendar.CalendarDate(this.ROJ[days], this.MAH[0], "");
			}
			// otherwise get the roj/mah name from the ROJ/MAH arrays based
			// on the difference in days number.
			else {
				months = Math.floor((diffInDays)/30);
				// alert(months);
				result[i] = new ZCalendar.CalendarDate(this.ROJ[days], this.MAH[months], "");
			}
			dayOffset++;
		}

		// uncomment for debugging
		//alert("" + this.ROJ[days] + " " + this.MAH[months]);
		//var s = "";
		//for (i=0; i<result.length; i++) {
		//	s += "[" + result[i].day + " , " + result[i].month + "]";
		//}
		//alert(s);
		return result;
	}
});


/********************************************************************

	Fasli Calendar

********************************************************************/

ZCalendar.Fasli = new Object();

// Fasli calendar extends AbstractBaseCalendar
Object.extend(ZCalendar.Fasli, ZCalendar.AbstractBaseCalendar);

// Fasli calendar implementation
Object.extend(ZCalendar.Fasli, { 

	GATHAS: new Array("Ahunavaiti", "Ushtavaiti","Spentamainyu","Vohuxshathra","Vahishtoishti", "Avardad-sal-Gah"),
	
	
	calendarType: "Fasli",
	
	/*
	 * @see ZCalendar.AbstractBaseCalendar#mapRojToYear
	 */
	mapRojToYear: function(aDate, aYear) {
		// to figure out the roj, find the difference in years
		// between the date provided and the year provided
		var rojDate = aDate.clone();
		rojDate.setFullYear(aYear);
		return rojDate;
	},


	/*
	 * @see ZCalendar.AbstractBaseCalendar#getNavrozeDate
	 */
	getNavrozeDate: function(aYear) {
		var navroze = this.EQUINOX_DATE.clone();
		navroze.setFullYear(aYear);
		return navroze;
	},
	

	/*
	 * @see ZCalendar.AbstractBaseCalendar#getRojNamesForMonth
	 */
	getRojNamesForMonth: function(aDate) {
		// Similar to calculating the roj name, we need to figure out the 
		// difference in days between the first day of the given month and
		// the prior navroze.  Then map the difference to the ROJ/MAH array,
		// and populate the resulting array with roj/mah values for the 
		// number of days in the month of the given date.

		var months = 0;
		var days = 0;
		var diffInDays = 0;
		var dayOffset = 0;

		// calculate the number of days in the month
		var daysInMonth = aDate.getDaysInMonth();

		// create a new array to hold results
		var result = new Array(daysInMonth);

		// determine the prior navroze for the given year
		var navroze = this.getNavrozeDate(aDate.getFullYear());
		if (aDate < navroze) {
			navroze = this.getNavrozeDate(aDate.getFullYear() - 1);
		}
		
		// determine the difference in days between prior navroze and
		// the given date
		daysFromNavroze = Date.daysDiff(aDate, navroze);

		// loop through the days in the month, getting the roj/mah name for
		// each corresponding day.
		for (i=0; i < daysInMonth; i++) {

			diffInDays = daysFromNavroze + dayOffset;
			days = diffInDays % 30;
			// if the difference in days is > 360, these are gathas which
			// have no corresponding month, so pull values from GATHAS array
			// and leave month blank
			
			// for fasli calendar, if it's a leap year, tack on the extra day
			if ((!aDate.isLeapYear() && (diffInDays >= 360) && (diffInDays < 365)) || 
			    (aDate.isLeapYear() && (diffInDays >= 360) && (diffInDays < 366)) )
			{
				result[i] = new ZCalendar.CalendarDate(this.GATHAS[days],"", "");
			} 
			
			else if (aDate.isLeapYear() && (diffInDays >= 360) && (diffInDays < 366)) {
				result[i] = new ZCalendar.CalendarDate(this.GATHAS[days],"", "");
			}

			// if the difference in days is 365 (or 366 for leap years), then we need to reset the
			// days arg back to 0 to start at the beginning of the month
			else if ((!aDate.isLeapYear() && diffInDays == 365) || (aDate.isLeapYear() && diffInDays == 366)) {
				days = 0;
				daysFromNavroze = 0;
				dayOffset = 0;
				result[i] = new ZCalendar.CalendarDate(this.ROJ[days], this.MAH[0], "");
			}
			// otherwise get the roj/mah name from the ROJ/MAH arrays based
			// on the difference in days number.
			else {
				months = Math.floor((diffInDays)/30);
				// alert(months);
				result[i] = new ZCalendar.CalendarDate(this.ROJ[days], this.MAH[months], "");
			}
			dayOffset++;
		}

		// uncomment for debugging
		//alert("" + this.ROJ[days] + " " + this.MAH[months]);
		//var s = "";
		//for (i=0; i<result.length; i++) {
		//	s += "[" + result[i].day + " , " + result[i].month + "]";
		//}
		//alert(s);
		return result;
	}
});


/********************************************************************

	Kadmi Calendar

********************************************************************/
// use prototype.js for oo behavior

ZCalendar.Kadmi = new Object();

// Shenshai calendar extends AbstractBaseCalendar
Object.extend(ZCalendar.Kadmi, ZCalendar.Shenshai);

// Shenshai calendar implementation
Object.extend(ZCalendar.Kadmi, {

	calendarType: "Kadmi",
	
	EPOCH_DATE: new Date(1006, 2, 21)
	
});