/**
* Filename.......: calendar.js
* Project........: Popup Calendar
* Last Modified..: $Date: 2002/07/22 18:17:05 $
* CVS Revision...: $Revision: 1.2 $
* Copyright......: 2001, 2002 Richard Heyes
*/

/**
* Global variables
*/
    dynCalendar_layers          = new Array();
    dynCalendar_mouseoverStatus = false;
    dynCalendar_mouseX          = 0;
    dynCalendar_mouseY          = 0;
		limit_from = false;
		limit_thru = false;
		is_a_package = false;
/**
* The calendar constructor
*
* @access public
* @param string objName      Name of the object that you create
* @param string callbackFunc Name of the callback function
* @param string OPTIONAL     Optional layer name
* @param string OPTIONAL     Optional images path
*/
    function dynCalendar(objName, callbackFunc)
    {
        /**
        * Properties
        */
        // Todays date
        this.today          = new Date();
        this.date           = this.today.getDate();
        this.month          = this.today.getMonth();
        this.year           = this.today.getFullYear();

        this.objName        = objName;
        this.callbackFunc   = callbackFunc;
        this.imagesPath     =  '/images/';
        this.layerID        = arguments[3] ? arguments[3] : 'dynCalendar_layer_' + dynCalendar_layers.length;

        this.offsetX        = 5;
        this.offsetY        = 5;

        this.useMonthCombo  = true;
        this.useYearCombo   = true;
        this.yearComboRange = 5;

        this.currentMonth   = this.month;
        this.currentYear    = this.year;

        /**
        * Public Methods
        */
        this.show              = dynCalendar_show;
        this.writeHTML         = dynCalendar_writeHTML;

        // Accessor methods
        this.setOffset         = dynCalendar_setOffset;
        this.setOffsetX        = dynCalendar_setOffsetX;
        this.setOffsetY        = dynCalendar_setOffsetY;
        this.setImagesPath     = dynCalendar_setImagesPath;
        this.setMonthCombo     = dynCalendar_setMonthCombo;
        this.setYearCombo      = dynCalendar_setYearCombo;
        this.setCurrentMonth   = dynCalendar_setCurrentMonth;
        this.setCurrentYear    = dynCalendar_setCurrentYear;
        this.setYearComboRange = dynCalendar_setYearComboRange;
				
			// ARR100:limit year/month display
			// calandar months are 0 bases so January = 0
			this.minMonth          = (this.year * 100) + (this.month);
			this.maxMonth          = ((this.year+10) * 100) + (this.month);
			this.setMinMonth       = dynCalendar_setMinMonth;
			this.setMaxMonth       = dynCalendar_setMaxMonth;
			// ARR100:limit year/month display
				
				
			// DJ:set month and year of this calendar to those in another
			this.copyState = dynCalendar_copyState;

				
        /* Private methods
        */
        // Layer manipulation
        this._getLayer         = dynCalendar_getLayer;
        this._hideLayer        = dynCalendar_hideLayer;
        this._showLayer        = dynCalendar_showLayer;
        this._setLayerPosition = dynCalendar_setLayerPosition;
        this._setHTML          = dynCalendar_setHTML;

        // Miscellaneous
        this._getDaysInMonth   = dynCalendar_getDaysInMonth;
        this._mouseover        = dynCalendar_mouseover;

        /**
        * Constructor type code
        */
        dynCalendar_layers[dynCalendar_layers.length] = this;
        this.writeHTML();
    }

/**
* Shows the calendar, or updates the layer if
* already visible.
*
* @access public
* @param integer month Optional month number (0-11)
* @param integer year  Optional year (YYYY format)
*/
    function dynCalendar_show()
    {
        // Variable declarations to prevent globalisation
        var month, year, monthnames, numdays, thisMonth, firstOfMonth;
        var ret, row, i, cssClass, linkHTML, previousMonth, previousYear;
        var nextMonth, nextYear, prevImgHTML, prevLinkHTML, nextImgHTML, nextLinkHTML;
        var monthComboOptions, monthCombo, yearComboOptions, yearCombo, html;
        
        this.currentMonth = month = arguments[0] != null ? arguments[0] : this.currentMonth;
        this.currentYear  = year  = arguments[1] != null ? arguments[1] : this.currentYear;

        monthnames = new Array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
        numdays    = this._getDaysInMonth(month, year);

        thisMonth    = new Date(year, month, 1);
        firstOfMonth = thisMonth.getDay();

        // First few blanks up to first day
        ret = new Array(new Array());
        for(i=0; i<firstOfMonth; i++){
            ret[0][ret[0].length] = '<td>&nbsp;</td>';
        }

        // Main body of calendar
        row = 0;
        i   = 1;
        while(i <= numdays){
            if(ret[row].length == 7){
                ret[++row] = new Array();
            }

            /**
            * Generate this cells' HTML
            */
            cssClass = (i == this.date && month == this.month && year == this.year) ? 'dynCalendar_today' : 'dynCalendar_day';
						if((limit_from) || (limit_thru)){
						  linkok=true;
						  if(limit_from){
						    if((year==from_year) && (month == (from_month-1)) && (i < from_day)){
								  linkok = false;
								}
							}
						  if(limit_thru){
						    if((year==thru_year) && (month == (thru_month-1)) && (i > thru_day)){
								  linkok = false;
								}
							}
						} else {
						  linkok = true;
						}
						if ((month == this.month) && (year == this.year) && (i < this.date)){
						  linkok= false;
						}
						
						
						
						if(linkok){
              linkHTML = '<a href="javascript: ' + this.callbackFunc + '(' + i + ', ' + (Number(month) + 1) + ', ' + year + '); ' + this.objName + '._hideLayer()">' + (i++) + '</a>';
						} else {
						  linkHTML = '<font color="A9A8A8">'+ (i++) +'</font>';
						}
            ret[row][ret[row].length] = '<td align="center" class="' + cssClass + '">' + linkHTML + '</td>';
        }

        // Format the HTML
        for(i=0; i<ret.length; i++){
            ret[i] = ret[i].join('\n') + '\n';
        }

        previousYear  = thisMonth.getFullYear();
        previousMonth = thisMonth.getMonth() - 1;
        if(previousMonth < 0){
            previousMonth = 11;
            previousYear--;
        }
        
        nextYear  = thisMonth.getFullYear();
        nextMonth = thisMonth.getMonth() + 1;
        if(nextMonth > 11){
            nextMonth = 0;
            nextYear++;
        }

				//ARR100: Don't show < minMonth
				if (((previousYear * 100) + previousMonth) >= this.minMonth){
				//ARR100: Don't show < minMonth
          prevImgHTML  = '<img src="' + this.imagesPath + '/calendar/prev.gif" alt="<<" border="0" />';
          prevLinkHTML = '<a href="javascript: ' + this.objName + '.show(' + previousMonth + ', ' + previousYear + ')">' + prevImgHTML + '</a>';
				//ARR100: Don't show < minMonth
        } else {
				  prevImgHTML  = '&nbsp;'
				  prevLinkHTML  = '&nbsp;'
				}
				//ARR100: Don't show < minMonth

				//ARR100: Don't show > maxMonth
				if (((nextYear * 100) + nextMonth) <= this.maxMonth){
				  nextImgHTML  = '<img src="' + this.imagesPath + '/calendar/next.gif" alt=">>" border="0" />';
          nextLinkHTML = '<a href="javascript: ' + this.objName + '.show(' + nextMonth + ', ' + nextYear + ')">' + nextImgHTML + '</a>';
				} else {
				  nextImgHTML  = '&nbsp;'
				  nextLinkHTML  = '&nbsp;'
				}
				//ARR100: Don't show < maxMonth

        /**
        * Build month combo
        */
        if (this.useMonthCombo) {
            monthComboOptions = '';
            for (i=0; i<12; i++) {
                selected = (i == thisMonth.getMonth() ? 'selected="selected"' : '');
                monthComboOptions += '<option value="' + i + '" ' + selected + '>' + monthnames[i] + '</option>';
            }
            monthCombo = '<select name="months" onchange="' + this.objName + '.show(this.options[this.selectedIndex].value, ' + this.objName + '.currentYear)">' + monthComboOptions + '</select>';
        } else {
            monthCombo = monthnames[thisMonth.getMonth()];
        }
        
        /**
        * Build year combo
        */
        if (this.useYearCombo) {
            yearComboOptions = '';
            for (i = thisMonth.getFullYear() - this.yearComboRange; i <= (thisMonth.getFullYear() + this.yearComboRange); i++) {
                selected = (i == thisMonth.getFullYear() ? 'selected="selected"' : '');
                yearComboOptions += '<option value="' + i + '" ' + selected + '>' + i + '</option>';
            }
            yearCombo = '<select style="border: 1px groove" name="years" onchange="' + this.objName + '.show(' + this.objName + '.currentMonth, this.options[this.selectedIndex].value)">' + yearComboOptions + '</select>';
        } else {
            yearCombo = thisMonth.getFullYear();
        }

        html = '<table border="0" bgcolor="#eeeeee">';
        html += '<tr><td class="dynCalendar_header">' + prevLinkHTML + '</td><td colspan="5" align="center" class="dynCalendar_header">' + monthCombo + ' ' + yearCombo + '</td><td align="right" class="dynCalendar_header">' + nextLinkHTML + '</td></tr>';
        html += '<tr>';
        html += '<td class="dynCalendar_dayname">Sun</td>';
        html += '<td class="dynCalendar_dayname">Mon</td>';
        html += '<td class="dynCalendar_dayname">Tue</td>';
        html += '<td class="dynCalendar_dayname">Wed</td>';
        html += '<td class="dynCalendar_dayname">Thu</td>';
        html += '<td class="dynCalendar_dayname">Fri</td>';
        html += '<td class="dynCalendar_dayname">Sat</td></tr>';
        html += '<tr>' + ret.join('</tr>\n<tr>') + '</tr>';
        html += '</table>';

        this._setHTML(html);
        if (!arguments[0] && !arguments[1]) {
            this._showLayer();
            this._setLayerPosition();
        }
    }

/**
* Writes HTML to document for layer
*
* @access public
*/
    function dynCalendar_writeHTML()
    {
        if (is_ie5up || is_nav6up || is_gecko) {
            document.write('<a href="javascript: ' + this.objName + '.show()"><img align="absmiddle" src="' + this.imagesPath + '/calendar/calendar.gif" border="0" width="16" height="16" /></a>');
            document.write('<div class="dynCalendar" id="' + this.layerID + '" onmouseover="' + this.objName + '._mouseover(true)" onmouseout="' + this.objName + '._mouseover(false)"></div>');
        }
    }

/**
* Sets the offset to the mouse position
* that the calendar appears at.
*
* @access public
* @param integer Xoffset Number of pixels for vertical
*                        offset from mouse position
* @param integer Yoffset Number of pixels for horizontal
*                        offset from mouse position
*/
    function dynCalendar_setOffset(Xoffset, Yoffset)
    {
        this.setOffsetX(Xoffset);
        this.setOffsetY(Yoffset);
    }

/**
* Sets the X offset to the mouse position
* that the calendar appears at.
*
* @access public
* @param integer Xoffset Number of pixels for horizontal
*                        offset from mouse position
*/
    function dynCalendar_setOffsetX(Xoffset)
    {
        this.offsetX = Xoffset;
    }

/**
* Sets the Y offset to the mouse position
* that the calendar appears at.
*
* @access public
* @param integer Yoffset Number of pixels for vertical
*                        offset from mouse position
*/
    function dynCalendar_setOffsetY(Yoffset)
    {
        this.offsetY = Yoffset;
    }
    
/**
* Sets the images path
*
* @access public
* @param string path Path to use for images
*/
    function dynCalendar_setImagesPath(path)
    {
        this.imagesPath = path;
    }

/**
* Turns on/off the month dropdown
*
* @access public
* @param boolean useMonthCombo Whether to use month dropdown or not
*/
    function dynCalendar_setMonthCombo(useMonthCombo)
    {
        this.useMonthCombo = useMonthCombo;
    }

/**
* Turns on/off the year dropdown
*
* @access public
* @param boolean useYearCombo Whether to use year dropdown or not
*/
    function dynCalendar_setYearCombo(useYearCombo)
    {
        this.useYearCombo = useYearCombo;
    }

/**
* Sets the current month being displayed
*
*  Current month will always be the current month or later
* @access public
* @param boolean month The month to set the current month to
*/
    function dynCalendar_setCurrentMonth(month)
    {
      var today = new Date();
      var thisMonth = today.getMonth();
      var thisYear = today.getFullYear();
      if((month < thisMonth) && (this.currentYear <= thisYear)){
         this.currentMonth = thisMonth;
      } else {
         this.currentMonth = month;
      }
    }

/**
* ARR100 sets the minmonth to allow
* Min month will always be the current month or later
*
* @access public
* @param boolean year The year to set the current year to
*/
    function dynCalendar_setMinMonth(month)
    {
      var today = new Date();
      var thisYear = today.getFullYear();
      var thisMonth = today.getMonth();
      if(String(today.getMonth()).length == 1){
         thisMonth = '0' + thisMonth;
      }
      var thisCombo = Number(String(thisYear) + String(thisMonth));
      if(month < thisCombo){
         this.minMonth = thisCombo;      
      } else {
         this.minMonth = month;
      } 
    }
/**
* ARR100 sets the maxmonth to allow
*
* @access public
* @param boolean year The year to set the current year to
*/
    function dynCalendar_setMaxMonth(month)
    {
        this.maxMonth = month;
    }


/**
* Sets the current month being displayed
*
* @access public
* @param boolean year The year to set the current year to
*/
    function dynCalendar_setCurrentYear(year)
    {
        this.currentYear = year;
    }

/**
* Sets the range of the year combo. Displays this number of
* years either side of the year being displayed.
*
* @access public
* @param integer range The range to set
*/
    function dynCalendar_setYearComboRange(range)
    {
        this.yearComboRange = range;
    }	 
	 
	 
/**
* DJ - 9/16/2005
* Sets the month and year of this calendar to the month and year values
* of the calendar object passed in as @cal
*
* @access public
* @cal a dynCalendar instance from which to copy the month and year
*/
	 function dynCalendar_copyState(cal){
	 	this.currentMonth = cal.currentMonth;
	 	this.currentYear = cal.currentYear;
	 } 
	 

/**
* Returns the layer object
*
* @access private
*/
    function dynCalendar_getLayer()
    {
        var layerID = this.layerID;

        if (document.getElementById(layerID)) {

            return document.getElementById(layerID);

        } else if (document.all(layerID)) {
            return document.all(layerID);
        }
    }

/**
* Hides the calendar layer
*
* @access private
*/
    function dynCalendar_hideLayer()
    {
        this._getLayer().style.visibility = 'hidden';
    }

/**
* Shows the calendar layer
*
* @access private
*/
    function dynCalendar_showLayer()
    {
        this._getLayer().style.visibility = 'visible';
    }

/**
* Sets the layers position
*
* @access private
*/
    function dynCalendar_setLayerPosition()
    {
        this._getLayer().style.top  = (dynCalendar_mouseY + this.offsetY) + 'px';
        this._getLayer().style.left = (dynCalendar_mouseX + this.offsetX) + 'px';
    }

/**
* Sets the innerHTML attribute of the layer
*
* @access private
*/
    function dynCalendar_setHTML(html)
    {
        this._getLayer().innerHTML = html;
    }

/**
* Returns number of days in the supplied month
*
* @access private
* @param integer month The month to get number of days in
* @param integer year  The year of the month in question
*/
    function dynCalendar_getDaysInMonth(month, year)
    {
        monthdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
        if (month != 1) {
            return monthdays[month];
        } else {
            return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0 ? 29 : 28);
        }
    }

/**
* onMouse(Over|Out) event handler
*
* @access private
* @param boolean status Whether the mouse is over the
*                       calendar or not
*/
    function dynCalendar_mouseover(status)
    {
        dynCalendar_mouseoverStatus = status;
        return true;
    }

/**
* onMouseMove event handler
*/
    dynCalendar_oldOnmousemove = document.onmousemove ? document.onmousemove : new Function;

    document.onmousemove = function ()
    {
        if (is_ie5up || is_nav6up || is_gecko) {
            if (arguments[0]) {
                dynCalendar_mouseX = arguments[0].pageX;
                dynCalendar_mouseY = arguments[0].pageY;
            } else {
                dynCalendar_mouseX = event.clientX + document.body.scrollLeft;
                dynCalendar_mouseY = event.clientY + document.body.scrollTop;
                arguments[0] = null;
            }
    
            dynCalendar_oldOnmousemove();
        }
    }

/**
* Callbacks for document.onclick
*/
    dynCalendar_oldOnclick = document.onclick ? document.onclick : new Function;

    document.onclick = function ()
    {
        if (is_ie5up || is_nav6up || is_gecko) {
            if(!dynCalendar_mouseoverStatus){
                for(i=0; i<dynCalendar_layers.length; ++i){
                    dynCalendar_layers[i]._hideLayer();
                }
            }
    
            dynCalendar_oldOnclick(arguments[0] ? arguments[0] : null);
        }
    }
