﻿PersianMonthName = [
		"فروردین", "اردیبهشت", "خرداد",	"تير", "مرداد", "شهريور",
                "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند"
    ];
    DInM = [0, 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29];
    Solar = 365.25;

    // Distance in days of origin of Jalali calendar from Origin of Gregorian calendar
    GYearOff = 226894;

    GDayTab = [
        [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
        [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    ];

    JDayTab = [
        [0, 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29],
        [0, 31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 30]
    ];

    /* Decides if Jalali year a leap one:  those years that have a remainder of
       1, 5, 9, 13, 17, 22, 26, and 30 when divided by 33 */
    function Jleap(year) {
        tmp = year % 33;
        if ((tmp == 1) || (tmp == 5) || (tmp == 9) || (tmp == 13) || (tmp == 17) || (tmp == 22) || (tmp == 26) || (tmp == 30))
            return 1;
        else
            return 0;
    }

    /* Decides if Gregorian year a leap one:  those years that are divisible by
   (4 but not 100) & those that are dvisible by 400.  */
    function Gleap(year) {
        if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
            return 1;
        else
            return 0;
    }

    /* find all Jalali leap years until JYear */
    function JLeapYears(JYear) {
        Leap = 0;
        CurrentCycle = 0;
        Div33 = 0;
        i = 0;
        Div33 = Math.floor(JYear / 33);	/* number of 33-year-periods */
        CurrentCycle = JYear - (Div33 * 33);
        Leap = Div33 * 8;
        if (CurrentCycle > 0) {
            i = 1;
            while ((i <= CurrentCycle) && (i <= 18)) {
                ++Leap;
                i = i + 4;
            }
        }
        if (CurrentCycle > 21) {
            i = 22;
            while ((i <= CurrentCycle) && (i <= 30)) /* for (i=22; i<=30; i+=4) */ {
                ++Leap;
                i = i + 4;
            }
        }
        return Math.floor(Leap);
    }

    /* Compute Jalali Day Of Year from Year, Month, and Day */
    function JDayOfYear(year, month, day) {
        i = 0;
        leap = 0;
        leap = Jleap(year);
        for (i = 1; i <= month - 1; i++){
			day = day + JDayTab[leap][i];
		}
        return day;
    }

    /* Compute Gregorian Day Of Year from Year, Month, and Day */
    function GDayOfYear(year, month, day) {
        i = 0;
        leap = 0;
        leap = Gleap(year);
        for (i = 1; i <= month - 1; i++)
            day = day + GDayTab[leap][i];
        return day;
    }

    function JalaliDays(JYear, JMonth, JDay) {
        TotalDays = 0;
        Leap = 0;
        tmp = 0;
        Leap = JLeapYears(JYear - 1);		/* find all leap years that have passed */
        tmp = JDayOfYear(JYear, JMonth, JDay);
        TotalDays = ((JYear - 1) * 365) + Leap + tmp;
        return TotalDays;
    }

    function GregDays(GYear, GMonth, GDay) {
        Div4 = 0;
        Div100 = 0;
        Div400 = 0;
        TotalDays = 0;
        tmp = 0;
        Div4 = Math.floor((GYear - 1) / 4);
        Div100 = Math.floor((GYear - 1) / 100);
        Div400 = Math.floor((GYear - 1) / 400);
        tmp = GDayOfYear(GYear, GMonth, GDay);
        TotalDays = Math.floor((GYear - 1) * 365 + tmp + Div4 - Div100 + Div400);
        return TotalDays;
    }

    /* Set Jalali Month & Day from Jalali Year & Day Of Year */
    function JMonthDay(JYear, JDayOfYear, py, pm, pd) {
        leap = Jleap(JYear);
        i = 1;
        while (JDayOfYear > JDayTab[leap][i]) {
            JDayOfYear = JDayOfYear - JDayTab[leap][i];
            ++i;
        }
        pm.value = i;
        pd.value = JDayOfYear;
    }

    /* Compute Jalali date from Gregorian Total Days */
    function JalaliYMD(TotalDays, py, pm, pd) {
        jDays = 0;
        leap = 0;
        jYear = 0;
        TotalDays = TotalDays - this.GYearOff;

        /* estimate full Jalai years passed */
        jYear = Math.floor(TotalDays / (this.Solar - 0.25 / 33));
        /* find all leap years that have passed */
        leap = JLeapYears(jYear);

        jDays = TotalDays - (365 * jYear + leap);
        jYear = jYear + 1;

        if (jDays == 0) {
            jYear = jYear - 1;
            if (Jleap(jYear) == 1)
                jDays = 366;
            else
                jDays = 365;
        } else if ((jDays == 366) && (Jleap(jYear) == 0)) {
            jDays = 1;
            jYear = jYear + 1;
        }
        JMonthDay(jYear, jDays, py, pm, pd);
        py.value = jYear;
    }

    function GregorianToJalaliDate(GDate, py, pm, pd) {                                                                                        // for JYear & JMonth & JDay
        TotalDays = 0;
        GYear = 0;
        GMonth = 0;
        GDay = 0;
        GYear = GDate.getFullYear();
        GMonth = GDate.getMonth();
        ++GMonth;
        GDay = GDate.getDate();
        //DecodeDate(GDate, GYear, GMonth, GDay);
        TotalDays = GregDays(GYear, GMonth, GDay);
        JalaliYMD(TotalDays, py, pm, pd);
    }

    /* Set Gregorian Month & Day from Gergorian Year & Day Of Year */
    function GMonthDay(GYear, GDayOfYear, gy, gm, gd) {                                                                            // for Month & Day
        i = 0;
        leap = 0;
        leap = Gleap(GYear);
        i = 1;
        while (GDayOfYear > GDayTab[leap][i]) {
            GDayOfYear = GDayOfYear - GDayTab[leap][i];
            ++i;
        }
        gm.value = i;
        gd.value = Math.floor(GDayOfYear);
    }

    /* Compute Gregorian date from Jalali Total Days */
    function GregorianYMD(TotalDays, gy, gm, gd) {                                                                                        // for GYear & GMonth & GDay
        Div4 = 0;
        Div100 = 0;
        Div400 = 0;
        GDays = 0;
        TotalDays = TotalDays + this.GYearOff;		/* Total Gregorian days passed */
        gy.value = Math.floor ( TotalDays / (this.Solar - 0.25 / 33));
        Div4 = Math.floor (gy.value / 4);
        Div100 = Math.floor (gy.value / 100);
        Div400 = Math.floor (gy.value / 400);

        /* find Gregorian day of year */
        GDays = TotalDays - (365 * gy.value) - (Div4 - Div100 + Div400);
        gy.value = gy.value + 1;
        if (GDays == 0) {
            gy.value = gy.value - 1;
            if (Gleap(gy.value) == 1)
                GDays = 366;
            else
                GDays = 365;
        } else if ((GDays == 366) && (Gleap(gy.value) == 0)) {
            GDays = 1;
            gy.value = gy.value + 1;
        }
        GMonthDay(gy.value, GDays, gy, gm, gd);
    }

    /* Compute Gregorian date from Jalali Year, Month & Day */
    function JalaliToGregorianDate(JYear, JMonth, JDay) {
        TotalDays = 0;
        var gy = new Object(); var gm = new Object(); var gd = new Object();
        TotalDays = JalaliDays(JYear, JMonth, JDay);
        GregorianYMD(TotalDays, gy, gm, gd);
        //d = new Date(gy.value, gm.value - 1, gd.value);
        d = new Date(gy.value, Number(gm.value) - 1, gd.value, 12, 0, 0, 0);
        return d;
    }

    function IsValidJalaliDate(JYear, JMonth, JDay) {
        return ((JMonth <= 12) && (JDay <= JDayTab[Jleap(JYear)][JMonth]));
    }

    function ZeroChain(i) {
        result = "";
        while (i > 0) {
            result = result + "0";
            --i;
        }
        return result;
    }

    function milady2Shamsi(date, py, pm, pd) {  // for year & month & day
        GregorianToJalaliDate(date, py, pm, pd);
    }

    function shamsi2Milady(y, m, d) {
        return JalaliToGregorianDate(y, m, d);
    }

    function isPersianLeapYear(Year) {
        return (Jleap(Year) == 1);
    }

    function DayOfWeek(date) {
        result = (date.getDay()+1)%7;
        return result;
    }

    function shamsiDayOfWeek(year, month, day) {
        tempDate = JalaliToGregorianDate(year, month, day);
        result = DayOfWeek(tempDate);
        return result;
    }

    function isValidPersianDate(year, month, day) {
        return IsValidJalaliDate(year, month, day);
    }

    function shamsiDate2Str(date) {
        var py = new Object(); var pm = new Object(); var pd = new Object();
        milady2Shamsi(date, py, pm, pd);

        sy = "" + py.value;
        sm = "" + pm.value;
        sd = "" + pd.value;

        sy = ZeroChain(4 - (sy.length)) + sy;
        sm = ZeroChain(2 - (sm.length)) + sm;
        sd = ZeroChain(2 - (sd.length)) + sd;

        return sy + "/" + sm + "/" + sd;
    }

    function shamsiYear(date) {
        var py = new Object(); var pm = new Object(); var pd = new Object();
        GregorianToJalaliDate(date, py, pm, pd);
        return py.value;
    }

    function shamsiMonth(date) {
        var py = new Object(); var pm = new Object(); var pd = new Object();
        GregorianToJalaliDate(date, py, pm, pd);
        return pm.value;
    }

    function shamsiDay(date) {
        var py = new Object(); var pm = new Object(); var pd = new Object();
        GregorianToJalaliDate(date, py, pm, pd);
        return pd.value;
    }

    function shamsiMonthDaysCount(year, month) {
        result = -1;
        if ((month > 12) || (month < 1))
            return -1;
        if ((month == 12) && isPersianLeapYear(year))
            result = 30;
        else
            result = this.DInM[month];
        return result;
    }



//
// calendar -- a javascript date picker
//
//
// Author:
//
// Based on "javascript date picker" Datepicker by Per Norrman (pernorrman@telia.com)
//
//
// The normal setup would be to have one text field for displaying the
// selected date, and one button to show/hide the date picker control.
// This is  the recommended javascript code:
//
//	<script language="javascript">
//		var cal;
//
//		function init() {
//			cal = new Calendar();
//			cal.setIncludeWeek(true);
//			cal.setFormat("yyyy-MM-dd");
//			cal.setMonthNames(.....);
//			cal.setShortMonthNames(....);
//			cal.setDateParser(dateParser);
//			cal.create();
//
//			document.form.button1.onclick = function() {
//				cal.toggle(document.form.button1);
//			}
//			cal.onchange = function() {
//				document.form.textfield1.value  = cal.formatDate();
//			}
//		}
//
//		function dateParser(){
//			//return Date after parsing document.form.textfield1.value
//		}
//	</script>
//
// The init function is invoked when the body is loaded.
//


function Calendar(date) {
	if (arguments.length == 0) {
		this._currentDate = new Date();
		this._selectedDate = null;
	}
	else {
		this._currentDate = new Date(date);
                this._selectedDate = new Date(date);
  	}

	// Accumulated days per month, for normal and for leap years.
	// Used in week number calculations.
    Calendar.NUM_DAYS = [0,31,62,93,124,155,186,216,246,276,306,336];

    Calendar.LEAP_NUM_DAYS = [0,31,62,93,124,155,186,216,246,276,306,336];


	this._bw = new bw_check();
	this._showing = false;
	this._includeWeek = false;
	this._hideOnSelect = true;
	this._alwaysVisible = false;

	this._dateSlot = new Array(42);
	this._weekSlot = new Array(6);

	this._monthNames = [
		"فروردین", "اردیبهشت", "خرداد",	"تير", "مرداد", "شهريور",
                "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند"
	];

	this._shortMonthNames = [
		"1", "2", "3", "4", "5", "6",
		"7", "8", "9", "10", "11", "12"
	];

	// Week days start with Sunday=0, ... Saturday=6
	this._weekDayNames = ["شنبه", "يکشنبه", "دوشنبه", "سه شنبه", "چهارشنبه", "پنجشنبه", "جمعه"];

	this._shortWeekDayNames = ["ش", "ی", "د", "س", "چ", "پ", "ج"];

	this._holiday = 6;
	this._defaultFormat = "yyyy/MM/dd";

	this._format = this._defaultFormat;

	this._calDiv = null;
	
	this._dateParser = null;
}

/**
 *	CREATE the Calendar DOM element
 */
Calendar.prototype.create = function(id) {
	var div;
	var table;
	var tbody;
	var tr;
	var td;
	var dp = this;

	// Create the top-level div element
	
	//	substitute createElement("div") with defined div, that id's passed to function
	//	to remove IE 'Operation aborted' bug
	this._calDiv = document.getElementById(id); //document.createElement("div");
	if (this._calDiv == null) { return; }

	this._calDiv.className = "calendar";
	this._calDiv.style.display = "none";
	this._calDiv.style.position = "absolute";
	this._calDiv.style.direction = "ltr";
	
    // header div
	div = document.createElement("div");
	div.className = "calendarHeader";
    div.align = "center";
	this._calDiv.appendChild(div);

	table = document.createElement("table");
	table.className = "headerTable";
    div.appendChild(table);

	tbody = document.createElement("tbody");
	table.appendChild(tbody);

	tr = document.createElement("tr");
	tbody.appendChild(tr);

	// Previous Month Button
	td = document.createElement("td");
	this._previousMonth = document.createElement("button");
	this._previousMonth.className = "calendarbutton"
	this._previousMonth.appendChild(document.createTextNode("<<"));
	//this._previousMonth.appendChild(document.createTextNode(String.fromCharCode(9668)));
	td.appendChild(this._previousMonth);
	tr.appendChild(td);



	//
	// Create the month dropdown
	//
	td = document.createElement("td");
	tr.appendChild(td);
	this._monthSelect = document.createElement("select");
	this._monthSelect.className = "select"
    for (var i = 0 ; i < this._monthNames.length ; i++) {
        var opt = document.createElement("option");
        opt.innerHTML = this._monthNames[i];
        opt.value = i;
        if (i == shamsiMonth(this._currentDate)-1) {
            opt.selected = true;
        }
        this._monthSelect.appendChild(opt);
    }
	td.appendChild(this._monthSelect);


	//
	// Create the year dropdown
	//
	td = document.createElement("td");
	tr.appendChild(td);
	this._yearSelect = document.createElement("select");
	this._yearSelect.className = "select";
	for(var i=1300; i < 1450; ++i) {
		var opt = document.createElement("option");
		opt.innerHTML = i;
		opt.value = i;
		if (i == shamsiYear(this._currentDate)) {
			opt.selected = false;
		}
		this._yearSelect.appendChild(opt);
	}
	td.appendChild(this._yearSelect);


	td = document.createElement("td");
	this._nextMonth = document.createElement("button");
	this._nextMonth.appendChild(document.createTextNode(">>"));
	//this._nextMonth.appendChild(document.createTextNode(String.fromCharCode(9654)));
	this._nextMonth.className = "calendarbutton";
	td.appendChild(this._nextMonth);
	tr.appendChild(td);

	// Calendar body
	div = document.createElement("div");
	div.className = "calendarBody";
    div.align = "center";
    this._calDiv.appendChild(div);
	this._table = div;

	// Create the inside of calendar body

	var text;
	table = document.createElement("table");
	//table.style.width="100%";
	table.className = "bodyTable";
	table.style.direction = "ltr";
	
    div.appendChild(table);
	var thead = document.createElement("thead");
	table.appendChild(thead);
	tr = document.createElement("tr");
	thead.appendChild(tr);

	// weekdays header
	for(i=0; i < 7; ++i) {
		td = document.createElement("th");
		text = document.createTextNode(this._shortWeekDayNames[6-i%7]);
		td.appendChild(text);
		td.className = "weekDayHead";
		if((6-i%7)==this._holiday) td.className += " holiday"; 	
		tr.appendChild(td);
	}
	if (this._includeWeek) {
		td = document.createElement("th");
		text = document.createTextNode("هفته");
		td.appendChild(text);
		td.className = "weekNumberHead";
		tr.appendChild(td);
	}

	// Date grid
	tbody = document.createElement("tbody");
    table.appendChild(tbody);

	for(week=0; week<6; ++week) {
		tr = document.createElement("tr");
		tbody.appendChild(tr);


		for(day=0; day<7; ++day) {
			td = document.createElement("td");
			td.className = "weekDay";
			if(i==this._holiday) td.className += " holiday"; 	
			text = document.createTextNode(String.fromCharCode(160));
			td.appendChild(text);
            setCursor(td);
			tr.appendChild(td);
			var tmp = new Object();
			tmp.tag = "DATE";
			tmp.value = -1;
			tmp.data = text;
			this._dateSlot[(week*7)+6-day] = tmp;

		}
		if (this._includeWeek) {
			td = document.createElement("td");
			td.className = "weekNumber";
			text = document.createTextNode(String.fromCharCode(160));
			td.appendChild(text);
			//setCursor(td);
			tr.appendChild(td);
			var tmp = new Object();
			tmp.tag = "WEEK";
			tmp.value = -1;
			tmp.data = text;
			this._weekSlot[week] = tmp;
		}

	}

	// Calendar Footer
	div = document.createElement("div");
	div.className = "calendarFooter";
    div.align = "center";
    this._calDiv.appendChild(div);

	table = document.createElement("table");
	//table.style.width="100%";
	table.className = "footerTable";
	div.appendChild(table);

	tbody = document.createElement("tbody");
	table.appendChild(tbody);

	tr = document.createElement("tr");
	tbody.appendChild(tr);

	//
	// The TODAY button
	//
	td = document.createElement("td");
	this._todayButton = document.createElement("button");
	this._todayButton.className = "calendarbutton";
	var today = new Date();
	var buttonText = this._weekDayNames[DayOfWeek(today)]+ " "+
                         shamsiDay(today) + " " +
                         this._monthNames[shamsiMonth(today)-1] + " " +
                         shamsiYear(today);
	this._todayButton.appendChild(document.createTextNode(buttonText));
	td.appendChild(this._todayButton);
	tr.appendChild(td);

	//
	// The CLEAR button
	//
	td = document.createElement("td");
	this._clearButton = document.createElement("button");
	this._clearButton.className = "calendarbutton";
	this._clearButton.style.display = "none";
	var today = new Date();
	buttonText = "حذف";
	this._clearButton.appendChild(document.createTextNode(buttonText));
	td.appendChild(this._clearButton);
	tr.appendChild(td);


	this._update();
	this._updateHeader();



	// IE55+ extension
	this._previousMonth.hideFocus = true;
	this._nextMonth.hideFocus = true;
	this._todayButton.hideFocus = true;
	// end IE55+ extension

	// hook up events
	// buttons
	this._previousMonth.onclick = function () {
                dp.nextMonth();
	};

	this._nextMonth.onclick = function () {
                dp.prevMonth();
	};

	this._todayButton.onclick = function () {
		dp.setSelectedDate(new Date());
		dp.hide();
	};

	this._clearButton.onclick = function () {
		dp.clearSelectedDate();
		dp.hide();
	};


	this._calDiv.onselectstart = function () {
		return false;
	};

	this._table.onclick = function (e) {
                // find event
		if (e == null) e = document.parentWindow.event;

		// find td
		var el = e.target != null ? e.target : e.srcElement;
		while (el.nodeType != 1)
			el = el.parentNode;
		while (el != null && el.tagName && el.tagName.toLowerCase() != "td")
			el = el.parentNode;

		// if no td found, return
		if (el == null || el.tagName == null || el.tagName.toLowerCase() != "td")
			return;

		var d = new Date(dp._currentDate);
		var n = Number(el.firstChild.data);
		if (isNaN(n) || n <= 0 || n == null)
			return;

		if (el.className == "weekNumber")
			return;

        d = shamsi2Milady(shamsiYear(d), shamsiMonth(d), n);
        dp.setSelectedDate(new Date(d));

		if (!dp._alwaysVisible && dp._hideOnSelect) {
			dp.hide();
		}

	};


	this._calDiv.onkeydown = function (e) {
		if (e == null) e = document.parentWindow.event;
		var kc = e.keyCode != null ? e.keyCode : e.charCode;

		if(kc == 13) {
			var d = new Date(dp._currentDate).valueOf();
			dp.setSelectedDate(d);

			if (!dp._alwaysVisible && dp._hideOnSelect) {
				dp.hide();
			}
			return false;
		}

		if(kc == 27) {
			if (!dp._alwaysVisible && dp._hideOnSelect) {
				dp.hide();
			}
			return false;
		}
		
		if (kc < 37 || kc > 40) return true;

		var d = new Date(dp._currentDate).valueOf();
		if (kc == 37) // left
			d += 24 * 60 * 60 * 1000;
		else if (kc == 39) // right
			d -= 24 * 60 * 60 * 1000;
		else if (kc == 38) // up
			d -= 7 * 24 * 60 * 60 * 1000;
		else if (kc == 40) // down
			d += 7 * 24 * 60 * 60 * 1000;

		dp.setCurrentDate(new Date(d));
		return false;
	}

	// ie6 extension
	this._calDiv.onmousewheel = function (e) {
                //ToDo: bad setPersianmonth not work 
                if (e == null) e = document.parentWindow.event;
		var n = - e.wheelDelta / 120;
		var d = new Date(dp._currentDate);
		var m = shamsiMonth(d)+n;//d.getMonth() + n;
		dp.setPersianMonth(m);

		return false;
	}

	this._monthSelect.onchange = function(e) {
                if (e == null) e = document.parentWindow.event;
				e = getEventObject(e);
				dp.setPersianMonth(parseInt(e.value)+1);
	}

	this._monthSelect.onclick = function(e) {
		if (e == null) e = document.parentWindow.event;
		e = getEventObject(e);
		e.cancelBubble = true;
	}

	this._yearSelect.onchange = function(e) {
                if (e == null) e = document.parentWindow.event;
		e = getEventObject(e);
		dp.setPersianYear(e.value);
	}


	//	this line replaced with defined div, that id's passed to create(id) function
	//	to remove IE 'Operation aborted' bug
	//document.body.appendChild(this._calDiv);

	return this._calDiv;
}

Calendar.prototype._update = function() {


	// Calculate the number of days in the month for the selected date
	var date = this._currentDate;
	var today = toISODate(new Date());


	var selected = "";
	if (this._selectedDate != null) {
		selected = toISODate(this._selectedDate);
	}
	var current = toISODate(this._currentDate);

        var d1 = new Date(date.getFullYear(), date.getMonth(), 1);
            py = shamsiYear(date);
	    pm = shamsiMonth(date);
	    pld = shamsiMonthDaysCount(py, pm);
	    d1 = shamsi2Milady(py, pm, 1);
        var d2 = new Date(date.getFullYear(), date.getMonth()+1, 1);
            d2 = shamsi2Milady(py, pm, pld);
	var monthLength = Math.round((d2 - d1) / (24 * 60 * 60 * 1000))+1;

	// Find out the weekDay index for the first of this month
        var firstIndex = DayOfWeek(d1) % 7 ;
    if (firstIndex < 0) {
    	firstIndex += 7;
    }

	var index = 0;
	while (index < firstIndex) {
		this._dateSlot[index].value = -1;
		this._dateSlot[index].data.data = String.fromCharCode(160);
		this._dateSlot[index].data.parentNode.className = "weekDay";
		if(DayOfWeek(d1)==this._holiday)	
			this._dateSlot[index].data.parentNode.className += " holiday";	
		index++;
	}

    for (i = 1; i <= monthLength; i++, index++) {
		this._dateSlot[index].value = i;
		this._dateSlot[index].data.data = i;
		this._dateSlot[index].data.parentNode.className = "weekDay";
		if (toISODate(d1) == today) {
			this._dateSlot[index].data.parentNode.className = "today";
		}
		if(DayOfWeek(d1)==this._holiday)	
			this._dateSlot[index].data.parentNode.className += " holiday";	
		if (toISODate(d1) == current) {
			this._dateSlot[index].data.parentNode.className += " current";
		}
		if (toISODate(d1) == selected) {
			this._dateSlot[index].data.parentNode.className += " selected";
		}
		d1 = new Date(d1.getFullYear(), d1.getMonth(), d1.getDate()+1);
	}

	var lastDateIndex = index;

    while(index < 42) {
		this._dateSlot[index].value = -1;
		this._dateSlot[index].data.data = String.fromCharCode(160);
		this._dateSlot[index].data.parentNode.className = "weekDay";
		if(DayOfWeek(d1)==this._holiday)	
			this._dateSlot[index].data.parentNode.className += " holiday";	
		++index;
	}

        // Week numbers
	if (this._includeWeek) {
                py = shamsiYear(date);
                pm = shamsiMonth(date);
                nd = JDayOfYear(py, pm, 1)+shamsiDayOfWeek(py, 1, 1);
                week = Math.floor((nd-1) / 7)+1;

		for (var i=0; i < 6; ++i) {
			if (i == 5 && lastDateIndex < 36) {
				this._weekSlot[i].data.data = String.fromCharCode(160);
				this._weekSlot[i].data.parentNode.className = ""
			} else {
				this._weekSlot[i].data.data = week;
				this._weekSlot[i].data.parentNode.className = "weekNumber"
 			}
			week++;
		}
	}
}

Calendar.prototype.show = function (element) {
    if (!this._showing) {
        if (this._dateParser != null) {
            d = this._dateParser();
            if (d != null)
                this.setSelectedDate(d);
        }

        var p = getPoint(element);
        // Calendar displayed in wrong place when placed in another div
        document.body.appendChild(this._calDiv);
        this._calDiv.style.display = "block";
        this._calDiv.style.top = parseInt(p.y + element.offsetHeight + 1) + "px";
        this._calDiv.style.left = parseInt(p.x /*- this._calDiv.offsetWidth*/) + "px";
        this._calDiv.style.position = 'absolute';

        //this.parent = element.parent;
        this._showing = true;

        /* -------- */
        if (this._bw.ie6) {
            dw = this._calDiv.offsetWidth;
            dh = this._calDiv.offsetHeight;
            var els = document.getElementsByTagName("body");
            var body = els[0];
            if (!body) return;

            //paste iframe under the modal
            var underDiv = this._calDiv.cloneNode(false);
            underDiv.style.zIndex = "390";
            underDiv.style.margin = "0px";
            underDiv.style.padding = "0px";
            underDiv.style.display = "block";
            underDiv.style.width = dw;
            underDiv.style.height = dh;
            underDiv.innerHTML = "<iframe width=\"100%\" height=\"100%\" frameborder=\"0\"></iframe>";
            body.appendChild(underDiv);
            this._underDiv = underDiv;
        }

        this._calDiv.focus();
    }
};

Calendar.prototype.hide = function() {
	if(this._showing) {
		this._calDiv.style.display = "none";
		this._showing = false;
		if( this._bw.ie6 ) {
		    if( this._underDiv ) this._underDiv.removeNode(true);
		}
	}
}

Calendar.prototype.toggle = function(element) {
    if(this._showing) {
		this.hide();
	} else {
		this.show(element);
	}
}



Calendar.prototype.onchange = function() {};


Calendar.prototype.setCurrentDate = function(date) {
	if (date == null) {
		return;
	}

	// if string or number create a Date object
	if (typeof date == "string" || typeof date == "number") {
		date = new Date(date);
	}


	// do not update if not really changed
	if (this._currentDate.getDate() != date.getDate() ||
		this._currentDate.getMonth() != date.getMonth() ||
		this._currentDate.getFullYear() != date.getFullYear()) {

		this._currentDate = new Date(date);

                this._updateHeader();
		this._update();
	}
}

Calendar.prototype.setSelectedDate = function(date) {
	this._selectedDate = new Date(date);
	this.setCurrentDate(this._selectedDate);
	if (typeof this.onchange == "function") {
		this.onchange();
	}
}

Calendar.prototype.clearSelectedDate = function() {
	this._selectedDate = null;
	if (typeof this.onchange == "function") {
		this.onchange();
	}
}

Calendar.prototype.getElement = function() {
	return this._calDiv;
}

Calendar.prototype.setIncludeWeek = function(v) {
	if (this._calDiv == null) {
		this._includeWeek = v;
	}
}

Calendar.prototype.getSelectedDate = function () {
	if (this._selectedDate == null) {
		return null;
	} else {
		return new Date(this._selectedDate);
	}
}


Calendar.prototype._updateHeader = function () {

	//
	var options = this._monthSelect.options;
	var m = shamsiMonth(this._currentDate)-1;
        for(var i=0; i < options.length; ++i) {
		options[i].selected = false;
		if (options[i].value == m) {
			options[i].selected = true;
		}
	}

	options = this._yearSelect.options;
	var year = shamsiYear(this._currentDate);
	for(var i=0; i < options.length; ++i) {
		options[i].selected = false;
		if (options[i].value == year) {
			options[i].selected = true;
		}
	}

}

Calendar.prototype.setPersianYear = function(year) {
	var d = new Date(this._currentDate);
            d = shamsi2Milady(year, shamsiMonth(d), shamsiDay(d));//ToDo: chack setted date is valid. 
        // d.setFullYear(year);
	this.setCurrentDate(d);
}

Calendar.prototype.setPersianMonth = function (month) {
	var d = new Date(this._currentDate);
            if(month<1){
               d = shamsi2Milady(shamsiYear(d)-1, 12, shamsiDay(d));//ToDo: chack setted date is valid. 
            }
            else d = shamsi2Milady(shamsiYear(d), month, shamsiDay(d));//ToDo: chack setted date is valid. 
	this.setCurrentDate(new Date(d));
}

Calendar.prototype.nextMonth = function () {
        this.setPersianMonth(shamsiMonth(this._currentDate)+1);
}

Calendar.prototype.prevMonth = function () {
 this.setPersianMonth(shamsiMonth(this._currentDate)-1);
}

Calendar.prototype.setMonthNames = function(a) {
	// sanity test
	this._monthNames = a;
}

Calendar.prototype.setShortMonthNames = function(a) {
	// sanity test
	this._shortMonthNames = a;
}

Calendar.prototype.setWeekDayNames = function(a) {
	// sanity test
	this._weekDayNames = a;
}

Calendar.prototype.setShortWeekDayNames = function(a) {
	// sanity test
	this._shortWeekDayNames = a;
}

Calendar.prototype.getFormat = function() {
	return this._format;
}

Calendar.prototype.setFormat = function(f) {
	this._format = f;
}


Calendar.prototype.setDateParser = function(f) {
	this._dateParser = f;
}


Calendar.prototype.formatDate = function() {
	if (this._selectedDate == null) {
		return "";
	}

    var bits = new Array();
    // work out what each bit should be
    var date = this._selectedDate;
    bits['d'] = shamsiDay(date);   //date.getDate();
    bits['dd'] = pad(shamsiDay(date), 2);   //pad(date.getDate(),2);
    bits['ddd'] = this._shortWeekDayNames[DayOfWeek(date)];   //this._shortWeekDayNames[date.getDay()];
    bits['dddd'] = this._weekDayNames[DayOfWeek(date)];  //this._weekDayNames[date.getDay()];

    bits['M'] = shamsiMonth(date);   //date.getMonth()+1;
    bits['MM'] = pad(shamsiMonth(date),2);  //pad(date.getMonth()+1,2);
    bits['MMM'] = this._shortMonthNames[shamsiMonth(date)-1]; //this._shortMonthNames[date.getMonth()];
    bits['MMMM'] = this._monthNames[shamsiMonth(date)-1]; //this._monthNames[date.getMonth()];

    var yearStr = "" + shamsiYear(date);  //"" + date.getFullYear();
    yearStr = (yearStr.length == 2) ? '19' + yearStr: yearStr;
    bits['yyyy'] = yearStr;
    bits['yy'] = bits['yyyy'].toString().substr(2,2);

    // do some funky regexs to replace the format string
    // with the real values
    var frm = new String(this._format);
    var sect;
    var i = 0;//for ignore javascript bug
    for (sect in bits) {
        if (i==10) break;//for ignore javascript bug
        frm = eval("frm.replace(/\\b" + sect + "\\b/,'" + bits[sect] + "');");
        i++;//for ignore javascript bug
    }

    return frm;
}

function getEventObject(e) {  // utility function to retrieve object from event
    if (navigator.appName == "Microsoft Internet Explorer") {
        return e.srcElement;
    } else {  // is mozilla/netscape
        // need to crawl up the tree to get the first "real" element
        // i.e. a tag, not raw text
        var o = e.target;
        while (!o.tagName) {
            o = o.parentNode;
        }
        return o;
    }
}

function addEvent(name, obj, funct) { // utility function to add event handlers

    if (navigator.appName == "Microsoft Internet Explorer") {
        obj.attachEvent("on"+name, funct);
    } else {  // is mozilla/netscape
        obj.addEventListener(name, funct, false);
    }
}


function deleteEvent(name, obj, funct) { // utility function to delete event handlers

    if (navigator.appName == "Microsoft Internet Explorer") {
        obj.detachEvent("on"+name, funct);
    } else {  // is mozilla/netscape
        obj.removeEventListener(name, funct, false);
    }
}

function setCursor(obj) {
   if (navigator.appName == "Microsoft Internet Explorer") {
        obj.style.cursor = "hand";
    } else {  // is mozilla/netscape
        obj.style.cursor = "pointer";
    }
}

function Point(iX, iY)
{
   this.x = iX;
   this.y = iY;
}


function getPoint(aTag)
{
   var oTmp = aTag;
   var point = new Point(0,0);

   do
   {
      point.x += oTmp.offsetLeft;
      point.y += oTmp.offsetTop;
      oTmp = oTmp.offsetParent;
   }
   while (oTmp.tagName != "BODY");

   return point;
}

function toISODate(date) {
	var s = date.getFullYear();
	var m = date.getMonth() + 1;
	if (m < 10) {
		m = "0" + m;
	}
	var day = date.getDate();
	if (day < 10) {
		day = "0" + day;
	}
	return String(s) + String(m) + String(day);

}

function pad(number,X) {   // utility function to pad a number to a given width
	X = (!X ? 2 : X);
	number = ""+number;
	while (number.length < X) {
	    number = "0" + number;
	}
	return number;
}

function bw_check()
{
    var is_major = parseInt( navigator.appVersion );
    this.nver = is_major;
    this.ver = navigator.appVersion;
    this.agent = navigator.userAgent;
    this.dom = document.getElementById ? 1 : 0;
    this.opera = window.opera ? 1 : 0;
    this.ie5 = ( this.ver.indexOf( "MSIE 5" ) > -1 && this.dom && !this.opera ) ? 1 : 0;
    this.ie6 = ( this.ver.indexOf( "MSIE 6" ) > -1 && this.dom && !this.opera ) ? 1 : 0;
    this.ie4 = ( document.all && !this.dom && !this.opera ) ? 1 : 0;
    this.ie = this.ie4 || this.ie5 || this.ie6;
    this.mac = this.agent.indexOf( "Mac" ) > -1;
    this.ns6 = ( this.dom && parseInt( this.ver ) >= 5 ) ? 1 : 0;
    this.ie3 = ( this.ver.indexOf( "MSIE" ) && ( is_major < 4 ) );
    this.hotjava = ( this.agent.toLowerCase().indexOf( 'hotjava' ) != -1 ) ? 1 : 0;
    this.ns4 = ( document.layers && !this.dom && !this.hotjava ) ? 1 : 0;
    this.bw = ( this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera );
    this.ver3 = ( this.hotjava || this.ie3 );
    this.opera7 = ( ( this.agent.toLowerCase().indexOf( 'opera 7' ) > -1 ) || ( this.agent.toLowerCase().indexOf( 'opera/7' ) > -1 ) );
    this.operaOld = this.opera && !this.opera7;
    return this;
};
