/*	**	**	**	**	**	**	**	**	**	**	**	**	**	*/
/*														*/
/*  solar.js - Solar Date Utility Functions							*/
/*  Copyright(C) 2002-2003 Mahmood Shafiee Zargar, all rights reserved.		*/
/*  sobh@softhome.net											*/
/*  http://sobh.netfirms.com										*/
/*														*/
/*   Edited by Babak H. Seradjeh on April 22, 2003						*/
/*   to convert latin numerals into Unicode persian numerals				*/
/*   http://www.sfu.ca/~bhosseyn/									*/
/*   Debugged on May 9th, 2003 by B.H.S. Now the "0" at the beginning of the		*/
/*   Month, Day or Year parts of the date are removed.					*/
/*   Debugged again on April 23, 2004 by B.H.S. for Mozilla and Netscape to 		*/
/*   show the dates correctly.									*/
/*														*/
/*														*/
/*  Original Pascal Code By Kambiz R. Khojaste							*/
/*														*/
/*  This file is provided "AS IS" without any warranty of any  kind, either		*/
/*  express or implied. The entire  risk as to the quality  and performance		*/
/*  of the functions provided in this  unit are with you. The author is NOT		*/
/*  liable for  any DAMAGES resulting from the use  and misuse of the unit,		*/
/*  especially he is NOT liable for DAMAGES that were caused BY ANY VERSION		*/
/*  WHICH HAS NOT BEEN PROGRAMMED BY THE AUTHOR HIMSELF.					*/
/*														*/
/*	**	**	**	**	**	**	**	**	**	**	**	**	**	*/

/*	**	**	**	**	**	**	**	**	**	**	**	**	**	*/
/*														*/
/*  Usage:													*/
/*														*/
/*  ConvertDateTag(DateStr, Format)									*/
/*  DateStr: A date string formatted as "m/d/yyyy" or "mm/dd/yyyy".			*/
/*  Format: An optional number between 0 and 9 that appoints output format.		*/
/*    Default is 0.		       								*/
/*  Returns a date string formatted in one of ten provided formats.			*/
/*														*/
/*  ConvertArchiveTag(DatesStr, Format)								*/
/*  DatesStr: A string containing two dates formatted as "m/d/yyyy - m/d/yyyy"	*/
/*    or "mm/dd/yyyy - mm/dd/yyyy".									*/
/*  Format: An optional number between 0 and 9 that appoints output format.		*/
/*    Default is 0.											*/
/*  Returns a string containing two dates formatted in one of ten provided		*/
/*    formats, separated by " - ".									*/
/*														*/
/*  If you want to change the input format, you should make changeds in		*/
/*      ConvertStr function.										*/
/*  * ConvertStr function uses GregorianToSolar function to do the date		*/
/*      convertion. There is also a SolarToGregorian function which can be used	*/
/*      to convert Solar dates into Gregorian dates. (May be applied into date	*/
/*      entry forms.) Both of these methods are complete in implementation and	*/
/*      the only reason of not implenting a ConvertStr for the reverse			*/
/*      functionality was the lack of usage for myself. Feel free to use it if	*/
/*      needed.												*/
/*														*/
/*	**	**	**	**	**	**	**	**	**	**	**	**	**	*/

var dkSolar = 0;
var dkGregorian = 1;

var UTFdigit = new Array();
UTFdigit = ["&#1776;","&#1777;","&#1778;","&#1779;","&#1780;","&#1781;","&#1782;","&#1783;","&#1784;","&#1785;"];

DaysOfMonths = [[31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29], [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]];
LeapMonth = [12, 2];
MonthToDays = [[0, 31, 62, 93, 124, 155, 186, 216, 246, 276, 306, 336, 365], [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]];

MonthNames = ["&#1601;&#1585;&#1608;&#1585;&#1583;&#1740;&#1606;", "&#1575;&#1585;&#1583;&#1740;&#1576;&#1607;&#1588;&#1578;", "&#1582;&#1585;&#1583;&#1575;&#1583;", "&#1578;&#1740;&#1585;", "&#1605;&#1585;&#1583;&#1575;&#1583;", "&#1588;&#1607;&#1585;&#1740;&#1608;&#1585;", "&#1605;&#1607;&#1585;", "&#1570;&#1576;&#1575;&#1606;", "&#1570;&#1584;&#1585;", "&#1583;&#1740;", "&#1576;&#1607;&#1605;&#1606;", "&#1575;&#1587;&#1601;&#1606;&#1583;"];
WeekDayNames = ["&#1740;&#1705;&#1588;&#1606;&#1576;&#1607;", "&#1583;&#1608;&#1588;&#1606;&#1576;&#1607;", "&#1587;&#1607; &#1588;&#1606;&#1576;&#1607;", "&#1670;&#1607;&#1575;&#1585; &#1588;&#1606;&#1576;&#1607;", "&#1662;&#1606;&#1580; &#1588;&#1606;&#1576;&#1607;", "&#1580;&#1605;&#1593;&#1607;", "&#1588;&#1606;&#1576;&#1607;"];
MonthDayNames = ["&#1575;&#1608;&#1604;", "&#1583;&#1608;&#1605;", "&#1587;&#1608;&#1605;", "&#1670;&#1607;&#1575;&#1585;&#1605;", "&#1662;&#1606;&#1580;&#1605;", "&#1588;&#1588;&#1605;", "&#1607;&#1601;&#1578;&#1605;", "&#1607;&#1588;&#1578;&#1605;", "&#1606;&#1607;&#1605;", "&#1583;&#1607;&#1605;", "&#1740;&#1575;&#1586;&#1583;&#1607;&#1605;", "&#1583;&#1608;&#1575;&#1586;&#1583;&#1607;&#1605;", "&#1587;&#1740;&#1586;&#1583;&#1607;&#1605;", "&#1670;&#1607;&#1575;&#1585;&#1583;&#1607;&#1605;", "&#1662;&#1575;&#1606;&#1586;&#1583;&#1607;&#1605;", "&#1588;&#1575;&#1606;&#1586;&#1583;&#1607;&#1605;", "&#1607;&#1601;&#1583;&#1607;&#1605;", "&#1607;&#1580;&#1583;&#1607;&#1605;", "&#1606;&#1608;&#1586;&#1583;&#1607;&#1605;", "&#1576;&#1740;&#1587;&#1578;&#1605;", "&#1576;&#1740;&#1587;&#1578; &#1608; &#1740;&#1705;&#1605;", "&#1576;&#1740;&#1587;&#1578; &#1608; &#1583;&#1608;&#1605;", "&#1576;&#1740;&#1587;&#1578; &#1608; &#1587;&#1608;&#1605;", "&#1576;&#1740;&#1587;&#1578; &#1608; &#1670;&#1607;&#1575;&#1585;&#1605;", "&#1576;&#1740;&#1587;&#1578; &#1608; &#1662;&#1606;&#1580;&#1605;", "&#1576;&#1740;&#1587;&#1578; &#1608; &#1588;&#1588;&#1605;", "&#1576;&#1740;&#1587;&#1578; &#1608; &#1607;&#1601;&#1578;&#1605;", "&#1576;&#1740;&#1587;&#1578; &#1608; &#1607;&#1588;&#1578;&#1605;", "&#1576;&#1740;&#1587;&#1578; &#1608; &#1606;&#1607;&#1605;", "&#1587;&#1740; &#1575;&#1605;", "&#1587;&#1740; &#1608; &#1740;&#1705;&#1605;"];
GregMonthName = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
GregMonthsInPersian = ["&#1688;&#1575;&#1606;&#1608;&#1610;&#1607;", "&#1601;&#1608;&#1585;&#1610;&#1607;", "&#1605;&#1575;&#1585;&#1587;", "&#1570;&#1608;&#1585;&#1610;&#1604;", "&#1605;&#1607;", "&#1688;&#1608;&#1575;&#1606;", "&#1688;&#1608;&#1610;&#1610;&#1607;", "&#1575;&#1608;&#1578;", "&#1587;&#1662;&#1578;&#1575;&#1605;&#1576;&#1585;", "&#1575;&#1615;&#1603;&#1578;&#1576;&#1585;", "&#1606;&#1608;&#1575;&#1605;&#1576;&#1585;", "&#1583;&#1587;&#1575;&#1605;&#1576;&#1585;"];

function Integer(val)		
{						
	this.value = val;			
}						

function UTFnumber(Nstr)
{
	var i, Rstr, sub;

	Rstr = "";
	for (i=0; i<Nstr.length; i++)
	{
		sub = Nstr.substr(i, 1);
		Rstr = Rstr + UTFdigit[sub.charCodeAt(0)-48];
	}
	return Rstr;	
}

function Tostring(n)
{
	var i, Rstr, m;
	
	Rstr =""; m=n;
	for (i=1; i<=Math.ceil(Math.log(n+1)/Math.LN10); i++)
	{
		Rstr = String.fromCharCode(48+m%10) + Rstr;
		m = (m - m%10)/10;
	}
	return Rstr;
}

function GregMonthNameToPersian (NameOrDigit, MonthStr)
{
/* returns the Gregorian month names, in letters (January,etc.) if NameOrDigit=1 or
   in digits (1, 2, ... 12) if NameOrDigit=0, in persian script */
	var n = 0;

	if (NameOrDigit == 0) {
		while (MonthStr.substr(0,1) == "0") 			
			MonthStr = MonthStr.replace("0", "");		
		n = parseInt(MonthStr);
	}
	else if (NameOrDigit == 1) {
		for (var i=0; i<12; i++)
			if (GregMonthName[i] == MonthStr) n = i+1;
		}
	if (n != 0) return GregMonthsInPersian[n-1];
	else return ("error in conversion!");
}

function IsLeapYear(DateKind, Year)
{
/* returns true if the given year is a leap year, false otherwise */
	if (DateKind == dkSolar) 
		return ((((Year + 38) * 31) % 128) <= 30);
	else
		return (((Year % 4) == 0) && (((Year % 100) != 0) || ((Year % 400) == 0)));
}

function DaysOfMonth(DateKind, Year, Month)
{
/* returns the number of days in a given month of a given year */
	var Result;
	if ((Year != 0) && ((Month <= 12) && (Month >= 1))) 
	{
		Result = DaysOfMonths[DateKind][Month - 1];
		if ((Month == LeapMonth[DateKind]) && (IsLeapYear(DateKind, Year))) Result++;
	}
	else
		Result = 0;
	return Result;
}

function IsDateValid(DateKind, Year, Month, Day)
{
	return ((Year!= 0) && (Month >= 1) && (Month <= 12) && (Day >= 1) && Day <= (DaysOfMonth(DateKind, Year, Month)));
}

function DateOfDays(DateKind, Days, Year, Month, Day)
{
/* takes the number of days into a given year and return the date, i.e. month and day of month */
	var fullDays = 0;

	Month.value = 0;

	for (var m = 1; ((m <= 12)&&(Days>fullDays)); m++) {
		fullDays += DaysOfMonth(DateKind, Year, m);
		Month.value ++;
	}
	Day.value = DaysOfMonth(DateKind, Year, Month.value) - fullDays + Days;

	return IsDateValid(DateKind, Year, Month.value, Day.value);
}

function DateToDays(DateKind, Year, Month, Day)
{
/* given the date (i.e. month and day) returns the number of days into a given year */

	var Result;

	if (IsDateValid(DateKind, Year, Month, Day))
	{
		Result = MonthToDays[DateKind][Month - 1] + Day;
		if ((Month > LeapMonth[DateKind]) && IsLeapYear(DateKind, Year)) Result++;
	}
	else
		Result = 0;
	return Result;
}

function GregorianToSolar(GYear, GMonth, GDay, SYear, SMonth, SDay)
{
	var	LeapDay, Days, PrevGregorianLeap, Result;

	SYear.value = 0; SMonth.value = 0; SDay.value = 0; 
	if (IsDateValid(dkGregorian, GYear, GMonth, GDay))
	{
		PrevGregorianLeap = IsLeapYear(dkGregorian, GYear - 1);
		Days = DateToDays(dkGregorian, GYear, GMonth, GDay);
		SYear.value = GYear-622;
		if (IsLeapYear(dkSolar, SYear.value)) LeapDay = 1;
		else LeapDay = 0;
		if (PrevGregorianLeap && (LeapDay == 1)) Days += 287;
		else Days += 286;
		if (Days > (365 + LeapDay))
		{
			SYear.value++;
			Days -= (365 + LeapDay);
		}
		Result = DateOfDays(dkSolar, Days, SYear.value, SMonth, SDay);
	}
	else Result = false;

	return Result;
}

function ConvertStr(DateStr, Format)
{
/*	var i; */
	var Result;
	var ObjDate = new Date();
	var SplDate = DateStr.split("/");			
	
	while (SplDate[0].substr(0,1) == "0") 			
			SplDate[0] = SplDate[0].replace("0", "");		
										
	while (SplDate[1].substr(0,1) == "0") 			
			SplDate[1] = SplDate[1].replace("0", "");	
										
	while (SplDate[1].substr(0,1) == "0") 			
			SplDate[1] = SplDate[1].replace("0", "");

	var M = parseInt(SplDate[0]);
	var D = parseInt(SplDate[1]);
	var Y = parseInt(SplDate[2]);

	var SY = new Integer(0);
	var SM = new Integer(0);
	var SD = new Integer(0); 

	ObjDate.setFullYear(Y);
	ObjDate.setMonth(M - 1);
	ObjDate.setDate(D);
	var W = ObjDate.getDay();

	if (GregorianToSolar(Y, M, D, SY, SM, SD)) 
		switch (Format) {
			case 0:
				Result = ( UTFnumber(Tostring(SD.value))+"/"+UTFnumber(Tostring(SM.value))+"/"+UTFnumber(Tostring(SY.value)) );
				break;
			case 1:
				Result = ( UTFnumber(Tostring(SD.value))+"/"+UTFnumber(Tostring(SM.value))+"/"+ ( UTFnumber(Tostring(SY.value - Math.floor(SY.value/100)*100)) ) );
				break;
			case 2:
				Result = ( UTFnumber(Tostring(SD.value))+" "+MonthNames[SM.value-1]+" "+UTFnumber(Tostring(SY.value)) );
				break;
			case 3:
				Result = ( MonthDayNames[SD.value-1]+" "+MonthNames[SM.value-1]+" "+UTFnumber(Tostring(SY.value)) );
				break;
			case 4:
				Result = ( MonthDayNames[SD.value-1]+" "+MonthNames[SM.value-1]+" &#1605;&#1575;&#1607; "+UTFnumber(Tostring(SY.value)) );		
				break;
			case 5:
				Result = ( WeekDayNames[W]+"&#1548; "+UTFnumber(Tostring(SD.value))+"/"+UTFnumber(Tostring(SM.value))+"/"+UTFnumber(Tostring(SY.value)) );
				break;
			case 6:
				Result = ( WeekDayNames[W]+"&#1548; "+UTFnumber(Tostring(SD.value))+"/"+UTFnumber(Tostring(SM.value))+"/"+ ( UTFnumber(Tostring(SY.value-Math.floor(SY.value/100)*100)) ) );
				break;
			case 7:
				Result = ( WeekDayNames[W]+"&#1548; "+UTFnumber(Tostring(SD.value))+" "+MonthNames[SM.value-1]+" "+UTFnumber(Tostring(SY.value)) );
				break;
			case 8:
				Result = ( WeekDayNames[W]+"&#1548; "+MonthDayNames[SD.value-1]+" "+MonthNames[SM.value-1]+" "+UTFnumber(Tostring(SY.value)) );
				break;
			case 9:
				Result = ( WeekDayNames[W]+"&#1548; "+ MonthDayNames[SD.value-1]+" "+MonthNames[SM.value-1]+" &#1605;&#1575;&#1607; "+UTFnumber(Tostring(SY.value)) );
				break;
			default:
				Result = ( UTFnumber(Tostring(SD.value))+"/"+UTFnumber(Tostring(SM.value))+"/"+UTFnumber(Tostring(SY.value)) );
				break;
		}
	else
		Result = "Error converting date";

	return Result;
}	

function ConvertDateTag(DateStr, Format)
{
	return ConvertStr(DateStr, Format);
}
