﻿function NACC_CleanTime ( pContainerId, pPathToNACC, pUseCookie, pChained, pHideTags ) {

	/******************************* SYSTEM GLOBALS *******************************/
	// These are some settings that you can specify to customize the NACC.
	
    // Set this to true to use the purple "Decades" tag for every 10 years after 10 (20, 30, etc.)
    var gUseDecadesTag = true;
    
    // Select the calendar type ("Persian", "Gregorian" or null, which equates to "Gregorian")
    // Gregorian is the standard calendar used throughout the West. It is the default calendar.
    // Persian is the Shamsi calendar, used in Iran, Aghanistan and other nations (also called the "Solar" calendar)
    var gCalendarType = "Gregorian";
//	gCalendarType = "Persian";	// Uncomment this line to turn on the Persian calendar.

	/******************************* LOCALIZATION SECTION *******************************
        BEGIN LOCALIZATION SECTION

        These globals are the displayed strings. This means they need to be changed in order to make this work in
        languages other than English.

        NOTE- the function BuildCleantimeMessage() has NOT been localized!!! If you need a non-English message,
        you'll have to change it accordingly until we get to it.
	/******************************************************************************/

    var gTitle_lang = null;
    var gPrompt_lang = null;
    var gCalcBtn_lang = null;
    var gMonthsFull_lang = null;
    var gResetLinkText_lang = null;
    var gChangeLinkText_lang = null;
    var gFutureWarning_lang = null;
    
    switch ( gCalendarType ) {
    	default:
    		gMonthsFull_lang = new Array ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
			gTitle_lang = 'SVGNA Cleantime Calculator';
			gPrompt_lang = 'Please enter your Clean Date';
			gCalcBtn_lang = 'Calculate';
			gResetLinkText_lang = new Array('Click to reset your cleantime', 'Reset Cleantime');
			gChangeLinkText_lang = new Array('Click to change how key tags are laid out', 'Change Key Tag Layout');
			gFutureWarning_lang = 'Error! Clean Date is in the future!';
    	break;
    	
    	case "Persian":
    		gMonthsFull_lang = new Array ('فروردین', 'اردیبهشت', 'خرداد', 'تیر', 'مرداد / امرداد', 'شهریور', 'مهر', 'آبان', 'آذر', 'دی', 'بهمن', 'اسپند / اسفند');
			gTitle_lang = 'محاسبه کننده سن پاکی';
			gPrompt_lang = 'تاریخ شروع پاکی خود را وارد کنید';
			gCalcBtn_lang = 'حساب کن';
			gResetLinkText_lang = new Array('Click to reset your cleantime', 'پاک کردن');
			gChangeLinkText_lang = new Array('Click to change how key tags are laid out', 'تغییر دادن چیدمان');
			gFutureWarning_lang = 'Error! Clean Date is in the future!';
    	break;
    }

    /********************
        This function constructs a plain-English phrase that summarizes the results. It would need to be
        completely rewritten for non-English implementations.

        Parameters:
            totalDays  integer - The total number of days between the cleandate and today.
            years      integer - The total number of years between the cleandate and today.
            months     integer - The total number of months between the cleandate's last year anniversary and today
            days       integer - The total number of days between the cleandate's last year/month anniversary and today
    */
    function BuildCleantimeMessageGregorian (totalDays, years, months, days) {
        var msg = 'You have been clean for '+ totalDays;

        if (totalDays > 90) {
        	msg += ' total';
		}
	
        if (totalDays > 1) {
            msg += ' days';
        } else {
            if ( totalDays ) {
                msg = 'Congratulations! You have been clean for one day!';
            } else {
                msg = 'Welcome to NA! Pick up a white tag, and keep coming back!';
            }
        }

        if (years || months || days) {
            msg += ', which is ';
            if (years > 0) {
                msg += years + ' year';
                if (years > 1)  msg += 's';
            }

            if (months > 0) {
                if (years) {
                    if (!days) {
                        msg += ' and ';
                    } else {
                        msg += ', ';
                    }
                }
                msg += months + ' month';
                if (months > 1) msg += 's';
            }

            if (days > 0) {
                if (years || months) msg += ' and ';
                msg += days + ' day';
                if (days > 1) msg += 's';
            }
        }

        msg += '!';

        return msg;
    }
    
	/******************
		This is a Persian localized version of the cleantime message.
	*/
    function BuildCleantimeMessagePersian (totalDays, years, months, days) {
        var msg = 'پاکی شما عبارتست از'+ totalDays;

        if (totalDays > 90) {
        	msg += ' ';
        }

        if (totalDays > 1) {
            msg += 'روز';
        } else {
            if ( totalDays ) {
                msg = 'مبارک باشه! پاکی شما عبارتست از یک روز!';
            } else {
                msg = 'به انجمن معتادان گمنام خوش آمدید ! بازهم بیایید';
            }
        }

        if (years || months || days) {
            msg += ', و یا  ';
            if (years > 0) {
                msg += years + ' سال';
                if (years > 1)  msg += ' ';
            }

            if (months > 0) {
                if (years) {
                    if (!days) {
                        msg += ' و ';
                    } else {
                        msg += 'و ';
                    }
                }
                msg += months + ' ماه';
                if (months > 1) msg += ' ';
            }

            if (days > 0) {
                if (years || months) msg += ' و ';
                msg += days + ' روز';
                if (days > 1) msg += ' ';
            }
        }

        msg += '!';

        return msg;
    }

    /*****************************************************
        END LOCALIZATION SECTION
	/***********************************************************************************/

    // This is today.
    var gTodayDate;
	var gTodayYear;
	var gTodayMonth;
	var gTodayDay;
    
    // Set the globals that reflect the input parameters.
    var gContainerEl = document.getElementById(pContainerId);

    if (gContainerEl == null) {
        alert('ERROR: There is no element on the page whose ID is "' + pContainerId + '"!');
        return;
    }

     // Fix pPathToNACC directory param before setting global var
     // Fixes missing or multiple forward slashes at end
     // Gives end user leeway if they forget to add one
     if (typeof(pPathToNACC) == 'string') {
          // Trim white space from beginning and end
          pPathToNACC = pPathToNACC.replace(/^\s+|\s*$/g, '');

          if (pPathToNACC.length > 0) {
                // Trim forward slash(es) from end
                pPathToNACC = pPathToNACC.replace(/\/*$/, '');

                // Add forward slash back
                pPathToNACC += '/';
          }
     }
     else {
          pPathToNACC = '';
     }

    var gPathToNACC = pPathToNACC;

    // Set global variable based on param passed to function
    var gChained = (pChained == true);

    // Set global variable based on param passed to function
    var gCookieName = (pUseCookie == true) ? 'nacc_cleantime' : '';

    // Set global variable based on param passed to function
    var gHideTags = (pHideTags == true);

    // This is one day, in milliseconds. It is needed to break down the getTime() results.
    var gDay = (24 * 60 * 60 * 1000);

    // Determine whether the browser is IE6 or older
    var gOldIE = (NACC_browser() == 'msie');
    
    // These reflect the current cleandate, parsed into a simple format.
    var gSelMonth;
    var gSelDay;
    var gSelYear;

    /********************
    	Convert the given date to the Gregorian Calendar from whatever calendar is selected as local.
		
		Returns:
			A new Date object, with the Gregorian date.
    */
	function To_Gregorian (in_year, in_month, in_day ) {
		switch ( gCalendarType ) {
			default:
				var td_date = new Date();
				td_date.setFullYear(in_year);
				td_date.setMonth(in_month - 1);
				td_date.setDate(in_day);
				
				return td_date;
			break;
			
			case "Persian":
				return solarToGregorian ( in_year, in_month, in_day );
			break;
		}
		
		return null;
	}

    /********************
    	Convert the given date to the local Calendar from the Gregorian Calendar.
 		
		Returns:
			An array, with [0] = year, [1] = month, [2] = day of month (In Local Calendar)
   */
	function To_Local (in_year, in_month, in_day) {
		switch ( gCalendarType ) {
			default:
				return new Array( in_year, in_month, in_day );
			break;
			
			case "Persian":
				return gregorianToSolar ( in_year, in_month, in_day );
			break;
		}
		
		return null;
	}

    /********************
    	Convert the given date to a Julian day.
 		
		Returns:
			An integer (The Julian day).
   */
	function To_JulianDay (in_year, in_month, in_day) {
		switch ( gCalendarType ) {
			default:
				return gregorianToJd (in_year, in_month, in_day);
			break;
			
			case "Persian":
				return persianToJd (in_year, in_month, in_day);
			break;
		}
		
		return null;
	}

    /********************
        Given a month and a year, returns the number of days in that month.

        Parameters:
            inYear  integer - The year in question
            inMonth integer - The month of that year (0-based, so it is 0-11).
            inGregorian boolean (optional -default is false). 	Set to true if the calculation should ignore localization
            													and work in Gregorian.

        Function Return:
            integer - The number of days in the given month.
    */
    function DaysInMonth ( inYear, inMonth ) {
		switch ( gCalendarType ) {
			default:
		        return 32 - new Date(inYear, inMonth, 32).getDate();
			break;
			
			case "Persian":
				if ( inMonth < 6 ) {
					return 31;
				} else if ( inMonth < 11 ) {
					return 30;
				} else {
					return (((((((inYear - ((inYear > 0) ? 474 : 473)) % 2820) + 474) + 38) * 682) % 2816) < 682) ? 30 : 29;
				}
			break;
		}
    }

	/*********************************************
		These Persian converters came from here:
			http://osp.ir/projects/facal/
	*/
	var PERSIAN_EPOCH = 1948320.5;
	var GREGORIAN_EPOCH = 1721425.5;
		
	//  leapPersian  --  Is a given year a leap year in the Persian calendar ?
	function leapPersian(year){
		return ((((((year - ((year > 0) ? 474 : 473)) % 2820) + 474) + 38) * 682) % 2816) < 682;
	}
	
	//  persianToJd  --  Determine Julian day from Persian date
	function persianToJd(year, month, day){
		var epbase, epyear;
	
		epbase = year - ((year >= 0) ? 474 : 473);
		epyear = 474 + (epbase % 2820);
	
		return day +
				((month <= 7) ?
					((month - 1) * 31) :
					(((month - 1) * 30) + 6)
				) +
				Math.floor(((epyear * 682) - 110) / 2816) +
				(epyear - 1) * 365 +
				Math.floor(epbase / 2820) * 1029983 +
				(PERSIAN_EPOCH - 1); 
	}
	
	//  jdToPersian  --  Calculate Persian date from Julian day
	function jdToPersian(jd){
		var year, month, day, depoch, cycle, cyear, ycycle,
			aux1, aux2, yday;
	
		jd = Math.floor(jd) + 0.5;
	
		depoch = jd - persianToJd(475, 1, 1);
		cycle = Math.floor(depoch / 1029983);
		cyear = (depoch % 1029983);
		if (cyear == 1029982) {
			ycycle = 2820;
		} else {
			aux1 = Math.floor(cyear / 366);
			aux2 = (cyear % 366);
			ycycle = Math.floor(((2134 * aux1) + (2816 * aux2) + 2815) / 1028522) + aux1 + 1;
		}
		year = ycycle + (2820 * cycle) + 474;
		if (year <= 0) {
			year--;
		}
		yday = (jd - persianToJd(year, 1, 1)) + 1;

		month = (yday <= 186) ? Math.ceil(yday / 31) : Math.ceil((yday - 6) / 30);
		day = (jd - persianToJd(year, month, 1)) + 1;

		return new Array(year, month-1, day);
	}
	
	//  leapGregorian  --  Is a given year in the Gregorian calendar a leap year ?
	function leapGregorian(year){
		return ((year % 4) == 0) &&
				(!(((year % 100) == 0) && ((year % 400) != 0)));
	}
	
	//  gregorianToJd  --  Determine Julian day number from Gregorian calendar date
	function gregorianToJd(year, month, day){
		return (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 : (leapGregorian(year) ? -1 : -2) ) + day);
	}
	
	//  jdToGregorian  --  Calculate Gregorian calendar date from Julian day
	function jdToGregorian(jd) {
		var wjd, depoch, quadricent, dqc, cent, dcent, quad, dquad,
			yindex, dyindex, year, yearday, leapadj;
	
		wjd = Math.floor(jd - 0.5) + 0.5;
		depoch = wjd - GREGORIAN_EPOCH;
		quadricent = Math.floor(depoch / 146097);
		dqc = (depoch % 146097);
		cent = Math.floor(dqc / 36524);
		dcent = (dqc % 36524);
		quad = Math.floor(dcent / 1461);
		dquad = (dcent % 1461);
		yindex = Math.floor(dquad / 365);
		year = (quadricent * 400) + (cent * 100) + (quad * 4) + yindex;
		if (!((cent == 4) || (yindex == 4))) {
			year++;
		}
		yearday = wjd - gregorianToJd(year, 1, 1);
		leapadj = ((wjd < gregorianToJd(year, 3, 1)) ? 0 : (leapGregorian(year) ? 1 : 2)
				  );
		month = Math.floor((((yearday + leapadj) * 12) + 373) / 367);
		day = (wjd - gregorianToJd(year, month, 1)) + 1;
	
		return new Array(year, month, day);
	}
	
	function gregorianToSolar(gYear, gMonth, gDay) {
	  var dDate = new Date();
	  if (gDay == 0 && gMonth == 0 && gYear == 0)	{
		gDay = dDate.getDate();
		gMonth = dDate.getMonth();
		gYear = dDate.getFullYear();
	  } else {
		dDate = new Date(gYear, gMonth, gDay);
	  }
	  j = gregorianToJd ( dDate.getFullYear(), dDate.getMonth() + 1, dDate.getDate());
	  return jdToPersian(j);
	}
	
	function solarToGregorian(sYear, sMonth, sDay) {
	
		if (sDay == 0 && sMonth == 0 && sYear == 0) {
				dDate = new Date();
	
				return dDate;
		}
		
		var gregorianDate = jdToGregorian(persianToJd(sYear, sMonth, sDay));
		
		return new Date(gregorianDate[0], gregorianDate[1] - 1, gregorianDate[2]);
	}
		
    /********************
        This function actually constructs the cleantime form. It does this by pure DOM construction, and places
        everything into the container whose ID is passed in by the pContainerId element.

        Parameters:
            initDate    string - This is the initial date and keytag setting.
                        It is a string in the following format:
                            [M]M/[D]D/YYYY-[1|0]
                        The first part is the month (1-12)
                        The second part is the day of the month (1-31)
                        The third part is the year, as a 4-digit number.
                        There is a dash. After that, is either a 1 (Chained) or a 0 (Tabletop).
                        If this parameter is omitted, the default values (today, pChained) will be used.
    */
    function Initialize (initDate) {
        // Start DOM creation section

        // This is an overall wrapper <div>
        var wrapperDiv = document.createElement('div');
        wrapperDiv.id = 'nacc_wrapper';
        wrapperDiv.className = 'nacc_wrapper';

        // Create main <div>- contains title, prompt and form
        var mainDiv = document.createElement('div');
        mainDiv.id = 'nacc_main';

        // adjust class for IE peekaboo bug fix css selector
        if (NACC_browser()&&NACC_browser().indexOf('msie') != -1) {
            mainDiv.className = 'nacc_main nacc_pb_fix';
        }
        else {
            mainDiv.className = 'nacc_main';
        }

        // Create title <span>
        var titleSpan = document.createElement('span');
        titleSpan.id = 'nacc_title';
        titleSpan.className = 'nacc_title';
        titleSpan.innerHTML = gTitle_lang;

        // Add title <span> to main <div>
        mainDiv.appendChild(titleSpan);

        // Create prompt <span> and add it to main <div>
        var promptSpan = document.createElement('span');
        promptSpan.id = 'nacc_prompt';
        promptSpan.className = 'nacc_prompt';
        promptSpan.innerHTML = gPrompt_lang;

        mainDiv.appendChild(promptSpan);

        // Create <form> The controls live within this <form>

        var theForm = document.createElement('form');
        theForm.action = "#";   // Required for valid XHTML.
        theForm.id = 'nacc_form';
        theForm.className = 'nacc_form';

        // Submitting the form calculates cleantime, but does not cause a page to be submitted to server.
        theForm.onsubmit = SubmitForm;

        // Create empty month <select> and add it to <form>. It will be filled later.
        var selectMonth = document.createElement('select');
        selectMonth.id = 'nacc_month_sel';
        selectMonth.className = 'nacc_month_sel';

        theForm.appendChild(selectMonth);

        // Create empty day <select> and add it to <form>. It will be filled later.
        var selectDay = document.createElement('select');
        selectDay.id = 'nacc_day_sel';
        selectDay.className = 'nacc_day_sel';

        theForm.appendChild(selectDay);

        // Create empty year <select> and add it to <form>. It will be filled later.
        var selectYear = document.createElement('select');
        selectYear.id = 'nacc_year_sel';
        selectYear.className = 'nacc_year_sel';

        theForm.appendChild(selectYear);

        // Create the calculate button and add it to <form>
        var calcBtn = document.createElement('input');
        calcBtn.id = 'nacc_calc_btn';
        calcBtn.className = 'nacc_calc_btn';
        calcBtn.type = 'submit';
        calcBtn.value = gCalcBtn_lang;

        theForm.appendChild(calcBtn);

        // Create reset <a> and add it to the <form>
        var resetLink = document.createElement('a');

        resetLink.id = 'nacc_reset_link';
        resetLink.className = 'nacc_reset_link';
        resetLink.href = '#';
        resetLink.title = gResetLinkText_lang[0];
        resetLink.innerHTML = gResetLinkText_lang[1];

        // Clicking link resets everything
        resetLink.onclick = ResetForm;

        theForm.appendChild(resetLink);

        // Create a clearing <div> and add it to the form to clear floated elements
        var clearingDiv = document.createElement('div');
        clearingDiv.className = 'nacc_clearing_div';

        theForm.appendChild(clearingDiv);

        // Add <form> to main <div>
        mainDiv.appendChild(theForm);

        // Add main <div> to wrapper <div>
        wrapperDiv.appendChild(mainDiv);

        // Create results <div>- contains cleantime message and key tag display
        var resultsDiv = document.createElement('div');
        resultsDiv.id = 'nacc_results';
        resultsDiv.className = 'nacc_results';

        // adjust class for IE peekaboo bug fix css selector
        if (NACC_browser()&&NACC_browser().indexOf('msie') != -1) {
            resultsDiv.className = 'nacc_results  nacc_pb_fix';
        }
        else {
            resultsDiv.className = 'nacc_results';
        }

        // Add results <div> to wrapper <div>
        wrapperDiv.appendChild(resultsDiv);

        // Put the whole schmeel into the user-supplied container
        gContainerEl.appendChild(wrapperDiv);

        // End DOM creation section

        // If we have an initial date, it will be in the cookie format, so we parse it out.
        if (initDate) {
            var mycookie = initDate.split('-');
            var parts = mycookie[0].split('/');
            gSelMonth = parts[0];
            gSelDay = parts[1];
            gSelYear = parts[2];

            gChained = parseInt(mycookie[1], 10) == 1;
        }
        else {
			var td_date = new Date();
	
			var dArray = To_Local(td_date.getFullYear(),td_date.getMonth(),td_date.getDate());
			
			gSelYear = dArray[0];
			gSelMonth = dArray[1] + 1;
			gSelDay = dArray[2];
        }

        // Set up the contents of the three date <select> elements.
        FillYearSelect();
        FillMonthSelect();
        FillDaySelect();
    }

    /*****************************************************
        COOKIE FUNCTIONS

        These are simple JavaScript cookie functions. They use the
        cookie name in gCookieName.
    */

    /********************
        Get the cookie value.

        Parameters:
            inCookieName    string - The name of the cookie

        Function Return:
            string - The value of the cookie
    */
    function GetCookie (inCookieName) {
        if ( inCookieName ) {
            var nameEq = inCookieName + '=';
            var ca = document.cookie.split(';');
            for (var i = 0; i < ca.length; i++) {
                var c = ca[i];
                while (c.charAt(0) == ' ') {
                    c = c.substring(1, c.length);
                }
                if (c.indexOf(nameEq) == 0) {
                    return unescape(c.substring(nameEq.length, c.length));
                }
            }
        }
        return null;
    }

    /********************
        Set a new cookie.

        Parameters:
            inCookieName    string - The name of the cookie
            value          string - The value of the cookie.
    */
    function SetCookie (inCookieName, value) {
        if ( inCookieName ) {
            var nameEq = inCookieName + '=';
            var date = new Date();
            date.setTime(date.getTime() + (gDay * 366));
            var expires = "; expires=" + date.toGMTString();
            document.cookie = nameEq + escape(value) + expires;
        }
    }

    /********************
        Clear the cookie.

        Parameters:
            inCookieName    string - The name of the cookie
    */
    function RemoveCookie (inCookieName) {
        if ( inCookieName ) {
            var nameEq = inCookieName + '=';
            var date = new Date();
            date.setTime(date.getTime() - gDay);
            var expires = "; expires=" + date.toGMTString();
            document.cookie = nameEq + expires;
        }
    }

    /*****************************************************
        CALCULATION FUNCTIONS

        These are the functions where the calculation is actually done.
    */

    /********************
        The Big Kahuna. This calculates the total number of cleandays, the years, months and days, etc.
        It returns an associative array of Cleandate numbers ('total_days', 'years', 'months', and 'days')
        Or false if clean date is in the future
    */
    function CalcCleantime () {
		var	cYear = parseInt ( gSelYear );
		var	cMonth = parseInt ( gSelMonth );
		var	cDay = parseInt ( gSelDay );
		var cd_date = To_Gregorian(cYear,cMonth,cDay);
		
		var td_date = new Date();

		// We gotta use round here rather than parseInt or floor because of floating point issues
		var totalDays = parseInt(Math.round((td_date.getTime() / (1000 * 60 * 60 * 24))
									- Math.round(cd_date.getTime()) / (1000 * 60 * 60 * 24)));
        if (totalDays>=0) {
            var years = null;
            var months = null;
            var days = null;

            if (totalDays > 90) {
                var startYear = cd_date.getFullYear();
                var startMonth = cd_date.getMonth();
                var startDay = cd_date.getDate();

				var date_array = To_Local(startYear,startMonth,startDay);
                startYear = date_array[0];
                startMonth = date_array[1];
                startDay = date_array[2];

                var endYear = td_date.getFullYear();
                var endMonth = td_date.getMonth();
                var endDay = td_date.getDate();
                
				date_array = To_Local(endYear,endMonth,endDay);
                endYear = date_array[0];
                endMonth = date_array[1];
                endDay = date_array[2];

                // We first see how many years have passed.
                years = endYear - startYear;
                // We then check months.
                months = (endMonth - startMonth);
                // We do a similar thing with days.
                days = endDay - startDay;


                // If this month is earlier than the cleandate month, we reduce the
                // year by one, and figure out how many months it's been since the
                // last annual anniversary of the clean date.
                if (months < 0) {
                    months = 12 - startMonth;
                    months += endMonth;
                    if (years > 0) years--;
                    }
                
                // We need to figure out how many days it was between the last monthly
                // anniversary and today.
                if (days < 0) {
                    months--;
                    // If we went too far with the months, we go back to the previous year
					if (months < 0) {
						months = 11 - startMonth;
						months += endMonth;
						if (years > 0) years--;
						}
					// Here's my editing for accuracy, we should be using last months # of days in month
                    days = DaysInMonth(endYear, endMonth - 1) - startDay;
                    days += endDay;
                }
            }

            if (totalDays >= 0) {

                // Return associative array of Cleandate numbers
                var retArray = new Array();
                retArray['total_days'] = totalDays;
                retArray['years'] = years;
                retArray['months'] = months;
                retArray['days'] = days;

                return retArray;
            }
        }
        return false;
    }

    /********************
        This fills the year <select> element.
        1953 is when NA was formed.
    */
    function FillYearSelect () {
        var obj = document.getElementById('nacc_year_sel');

        obj.onchange = null;
        obj.options.length = 0;
        obj.selectedIndex = -1;

        var sel = -1;
        var i = 0;
		
		var start_year = 1953;
		
		var dArray = To_Local(start_year,7,17);
		
		start_year = dArray[0];

		var td_date = new Date();

		dArray = To_Local(td_date.getFullYear(),td_date.getMonth(),td_date.getDate());
		
		var final_year = dArray[0];

        for (var c = start_year; c <= final_year; c++) {
            var opt = document.createElement('option');
            opt.value = c;
            opt.text = c;

            if (gSelYear == c) {
                sel = c - start_year;
            }

            obj.options[i++] = opt;
        }

        if (sel == -1) {
            obj.selectedIndex = obj.options.length - 1;
        }
        else {
            obj.selectedIndex = sel;
        }

       // Make sure that the day <select> element is corrected for leap years.
       obj.onchange = function () { gSelYear = document.getElementById('nacc_year_sel').value;FillDaySelect()};
    }


    /********************
        This fills the month <select> element.
    */
    function FillMonthSelect () {
        var obj = document.getElementById('nacc_month_sel');

        obj.onchange = null;
        obj.options.length = 0;
        obj.selectedIndex = -1;

        var max_month = 12;
        var sel = -1;
        var i = 0;

        for (var c = 1; c <= max_month; c++) {
            var opt = document.createElement('option');

            opt.value = c;
            opt.text = gMonthsFull_lang[c - 1];

            if (gSelMonth == c) {
                sel = c - 1;
            }

            obj.options[i++] = opt;
        }

        if (sel == -1) {
            obj.selectedIndex = obj.options.length - 1;
        }
        else {
            obj.selectedIndex = sel;
        }

        // Make sure that the day <select> element reflects the correct number of days for this month.
       obj.onchange = function () { gSelMonth = document.getElementById('nacc_month_sel').value;FillDaySelect()};
    }

    /********************
        This fills the day <select> element.
    */
    function FillDaySelect () {
        var iSelYear = gSelYear;
        var iSelMonth = gSelMonth;

        if ( document.getElementById('nacc_year_sel').value ) {
            iSelYear = parseInt(document.getElementById('nacc_year_sel').value, 10);
        }
        if ( document.getElementById('nacc_month_sel').value ) {
            iSelMonth = parseInt(document.getElementById('nacc_month_sel').value, 10);
        }
        var obj = document.getElementById('nacc_day_sel');

        obj.onchange = null;
        obj.options.length = 0;
        obj.selectedIndex = -1;

        var max_days = DaysInMonth(iSelYear, iSelMonth - 1);

        var sel = -1;
        var i = 0;

        for (var c = 1; c <= max_days; c++) {
            var opt = document.createElement('option');
            opt.value = c;
            opt.text = c;

            if (gSelDay == c) {
                sel = c - 1;
            }

            obj.options[i++] = opt;
        }

        if (sel == -1) {
            obj.selectedIndex = obj.options.length - 1;
        }
        else {
            obj.selectedIndex = sel;
        }
       // FIX ADDED 8/31/07: The gSelDay was not being set when we changed the last day.
       gSelDay = document.getElementById('nacc_day_sel').value;
       obj.onchange = function () { gSelDay = document.getElementById('nacc_day_sel').value };
    }

    /********************
        When the reset control is activated, we remove the cookie and set the date to today.
        We clear the key tag and message displays.
        We do not change the layout preference.
    */
    function ResetForm () {
        RemoveCookie(gCookieName);

        EmptyObject('nacc_results');

        ResetCleantime();

        FillYearSelect();
        FillMonthSelect();
        FillDaySelect();
        
        return false;
    }

    /********************
        When the form is submitted (either with return key or button click), we clear the message and keytag displays.
        Then we do the calculations, render displays and set cookie.
    */
    function SubmitForm () {
        EmptyObject('nacc_results');

        var result = CalcCleantime();

        // Check if result is not false to determine if it's an array (can't safely check if its an array due to limitations of language)
        if (result !== false) {
            var rTotalDays = result['total_days'];
            var rYears = result['years'];
            var rMonths = result['months'];
            var rDays = result['days'];

			var	msg;
			
			switch ( gCalendarType ) {
				default:
					msg = BuildCleantimeMessageGregorian(rTotalDays, rYears, rMonths, rDays);
				break;
				
				case "Persian":
					msg = BuildCleantimeMessagePersian(rTotalDays, rYears, rMonths, rDays);
				break;
			}
		
            RenderMessage(msg);
            
            RenderKeyTags(BuildKeyTagList(rTotalDays, rYears, rMonths, rDays));

            var mycookie = gSelMonth + '/' + gSelDay + '/' + gSelYear + '-' + (gChained ? '1' : '0');
            SetCookie(gCookieName, mycookie);
        }
        else {
            alert(gFutureWarning_lang);
        }

        return false;
    }

    /********************
        Toggle key tag layout between chained and tabletop and reruns everything
    */
    function ChangeLayout () {
        gChained = (!gChained);

        return SubmitForm();
    }

    /********************
        Simple. Empties DOM object whose id is passed in param.

        Parameters:
            objId string - the id of the DOM object to empty.
    */
    function EmptyObject (objId) {
        if (objId) {
            obj = document.getElementById(objId);
            if (obj) {
                // Add event removal here?!?
                
                obj.innerHTML = '';
            }
        }
    }

    /********************
        Simple. We just set the cleantime to today.
    */
    function ResetCleantime () {
		var td_date = new Date();

		var dArray = To_Local(td_date.getFullYear(),td_date.getMonth(),td_date.getDate());
		
		gSelYear = dArray[0];
		gSelMonth = dArray[1] + 1;
		gSelDay = dArray[2];
    }

    /********************
        This simply writes out the message to the message <div>

        Parameters:
            msg string - The message to be displayed.
    */
    function RenderMessage (msg) {
        var resultsDiv = document.getElementById('nacc_results');

        var msgDiv = document.getElementById('nacc_msg');

        if (!msgDiv) {
            msgDiv = document.createElement('div');
            msgDiv.id = 'nacc_msg';
            msgDiv.className = 'nacc_msg';
            resultsDiv.appendChild(msgDiv);
        }

        msgDiv.innerHTML = msg;
    }

    /********************
        This builds a list of keytags that should be displayed for given cleandate.

        Parameters:
            totalDays   integer - The total number of days between the cleandate and today.
            years      integer - The total number of years between the cleandate and today.
            months    integer - The total number of months between the cleandate's last year anniversary and today
            days        integer - The total number of days between the cleandate's last year/month anniversary and today

        Function Return:
            array of string - The list of tag images, given as src URIs.
    */
    function BuildKeyTagList (totalDays, years, months, days) {
        if (gChained) {
            var fileEnd = '.png';
        }
        else {
            var fileEnd = '_H.png';
        }

        var imageList = new Array();

        imageList[0] = gPathToNACC + 'images/Day_1' + fileEnd;

        if (totalDays >= 30) {
            imageList[1] = gPathToNACC + 'images/Day_30' + fileEnd;
        }

        if (totalDays >= 60) {
            imageList[2] = gPathToNACC + 'images/Day_60' + fileEnd;
        }

        if (totalDays >= 90) {
            imageList[3] = gPathToNACC + 'images/Day_90' + fileEnd;
        }

        if (!years) {
            if (months >= 6) {
                imageList[4] = gPathToNACC + 'images/Month_6' + fileEnd;
            }
            if (months >= 9) {
                imageList[5] = gPathToNACC + 'images/Month_9' + fileEnd;
            }
        }
        else {
            imageList[4] = gPathToNACC + 'images/Month_6' + fileEnd;
            imageList[5] = gPathToNACC + 'images/Month_9' + fileEnd;
            imageList[6] = gPathToNACC + 'images/Month_12' + fileEnd;

            if ((years == 1 && months >= 6) || (years > 1)) {
                imageList[7] = gPathToNACC + 'images/Month_18' + fileEnd;
            }
            
            decades = gUseDecadesTag && (years > 19);
            
            for (var c = 8, year = 2; year <= years; c++, year++) {
                imageList[c] = gPathToNACC + 'images/Month_24' + fileEnd;
                if ( decades && (year > 10) && !(year % 10)) {
                    imageList[c] = gPathToNACC + 'images/Decades' + fileEnd;
                    }
                else {
                    imageList[c] = gPathToNACC + 'images/Month_24' + fileEnd;
                    }
            }
        }

        return imageList;
    }

    /********************
        This takes the calculated list of tags, and creates a bunch of floated <img> elements that correspond to the list.
        This will take the keytag layout preference into account, and will select the correct images accordingly.

        Parameters:
            imageList   array of string - The list of image src names.
    */
    function RenderKeyTags (imageList) {
        if (gHideTags) {
            return;
        }

        if (imageList.length == 0) {
            return;
        }

        var resultsDiv = document.getElementById('nacc_results');


        var keyTagsDiv = document.getElementById('nacc_keytags');

        if (!keyTagsDiv) {
            keyTagsDiv = document.createElement('div');
            keyTagsDiv.id = 'nacc_keytags';
            keyTagsDiv.className = 'nacc_keytags';
            resultsDiv.appendChild(keyTagsDiv);
        }

        var changeLink = document.createElement('a');

        changeLink.id = 'nacc_change_link';
        changeLink.className = 'nacc_change_link';
        changeLink.href = '#';
        changeLink.title = gChangeLinkText_lang[0];
        changeLink.innerHTML = gChangeLinkText_lang[1];
        changeLink.onclick = ChangeLayout;

        keyTagsDiv.appendChild(changeLink);

        var innerDiv = document.createElement('div');

        if (gChained) {
            innerDiv.id = 'nacc_keytags_chained';
            innerDiv.className = 'nacc_keytags_layout_chained';
        }
        else {
            innerDiv.id = 'nacc_keytags_tabletop';
            innerDiv.className = 'nacc_keytags_layout_tabletop';
        }

        keyTagsDiv.appendChild(innerDiv);

        var max = imageList.length;

        if (gOldIE) {
            for (var c = 0; c < max; c++) {
                var imgSpan = document.createElement('span');

                if (gChained) {
                    imgSpan.className = 'nacc_keytag_img_chained';
                }
                else {
                    imgSpan.className = 'nacc_keytag_img_tabletop';
                }

                imgSpan.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod='image',src='" + imageList[c] + "');";

                innerDiv.appendChild(imgSpan);
            }
        }
        else {
            for (var c = 0; c < max; c++) {
                var img = document.createElement('img');
                img.alt = 'Key Tag';

                if (gChained) {
                    img.className = 'nacc_keytag_img_chained';
                }
                else {
                    img.className = 'nacc_keytag_img_tabletop';
                }

                img.src = imageList[c];

                innerDiv.appendChild(img);
            }
        }
    }

	/*
		Function to determine browser
	
		Does not determine version except in the case of MSIE
	
		Return values by browser are:
			Opera               opera
			MSIE 7              msie7
			MSIE 6 (and below)  msie
			Safari              safari
			Gecko-based         gecko
			Other               false
	*/
	function NACC_browser () {
		var ua = navigator.userAgent.toLowerCase();
	
		if (ua.indexOf('opera') != -1) { // Opera (check first in case of spoof)
			return 'opera';
		}
		else if (ua.indexOf('msie 7') != -1) { // IE7
			return 'msie7';
		}
		else if (ua.indexOf('msie') != -1) { // IE
			return 'msie';
		}
		else if (ua.indexOf('safari') != -1) { // Safari (check before Gecko because it includes "like Gecko")
			return 'safari';
		}
		else if (ua.indexOf('gecko') != -1) { // Gecko
			return 'gecko';
		}
		else {
			return false;
		}
	}
	
	/*
		We need to add the following code so that IE6 will cache background images.
		By design it will not!!!
		IE5.x and IE7 will, but not IE6.
	
		Though not well documented, apparently it won't work when called in onload().
		So we have to call it inline when this JS file is included.
	
		Documented at http://www.mister-pixel.com/ and other
	*/
	if (NACC_browser() == 'msie') {
		try {
			document.execCommand("BackgroundImageCache", false, true);
		}
		catch (err) {
		}
	}
	
    // The first thing we do when the function is called is to create the <form>. Everything after that is up to the user.
    Initialize(GetCookie(gCookieName));
}
