/*
Utility Functions

DO NOT modify the following information manually.
---------------------------------------------------------------------------
 $Rev: 269 $
 $Date: 2008-07-22 16:27:08 -0500 (Tue, 22 Jul 2008) $
---------------------------------------------------------------------------
*/

if(typeof KD=='undefined')KD={}; // don't overwrite the KD namespace
if(typeof KD.calendar=='undefined')KD.calendar={}; //don't overwrite KD.calendar

if (!KD.calendar.Util) {
  KD.calendar.Util = new function() {

		/* shorthand */
		var E = YAHOO.util.Event;
		var dom = YAHOO.util.Dom;
		var $ = dom.get;
		
		
		this.set2 = function(n)
		{
		  return (n < 10) ? '0'+ n : n;
		}
		
		this.makeDate = function(dt)
		{
		  // expect 2007 03 28 11:00:00
		  var yr = parseInt(dt.substr(0,4),10);
		  var mn = parseInt(dt.substr(5,2),10) - 1;
		  var dy = parseInt(dt.substr(8,2),10);
		  var tm = dt.substr(11, dt.length-1).split(':');
		  return new Date(yr,mn,dy, parseInt(tm[0],10),parseInt(tm[1],10),parseInt(tm[2],10));
		}
		
		
		this.localMonth = function(m)
		{
		  if (m)
		  {
		    if (m.toLowerCase() == "january")   return 0;
		    if (m.toLowerCase() == "february")  return 1;
		    if (m.toLowerCase() == "march")     return 2;
		    if (m.toLowerCase() == "april")     return 3;
		    if (m.toLowerCase() == "may")       return 4;
		    if (m.toLowerCase() == "june")      return 5;
		    if (m.toLowerCase() == "july")      return 6;
		    if (m.toLowerCase() == "august")    return 7;
		    if (m.toLowerCase() == "september") return 8;
		    if (m.toLowerCase() == "october")   return 9;
		    if (m.toLowerCase() == "november")  return 10;
		    if (m.toLowerCase() == "december")  return 11;
		  }
		  return null;
		}
		
		/* returns the month/year from the date string */
		/* expects 'August 1, 2007' */
		this.formatCalDate = function(dt)
		{
		  var calDate;
		  var m = parseInt(this.localMonth(dt.substring(0, dt.indexOf(' '))), 10);
		  var y = parseInt(dt.substring(dt.indexOf(',')+1).replace(' ', ''), 10);
		  // if bad data - return the current month/year
		  if (isNaN(m) || isNaN(y))
		  {
		    var newDate = new Date();
		    calDate = newDate.getMonth() + '/' + newDate.getFullYear();
		    return calDate;
		  }
		  var calDate = m + '/' + y;
		  return calDate;
		}
		
		/**
		 * Checks if the year is a leap year
		 * @param yr an integer value of the full year (2007)
		 * @return true if year is a leap year, else false
		 */
		this.isLeapYear = function(yr)
		{
		  if ( (yr%4 == 0 && !yr%100 == 0) ||
		       (yr%4 == 0 && yr%100 == 0 && yr%400 == 0) ) return true;
		
		  return false;
		};
		
		/**
		 * Returns the number of days in the month for the specified year.
		 * @param yr an integer value of the full year (2007)
		 * @param m an integer value of the month (0 = January)
		 * @return integer value of number of days in month
		 */
		this.getDaysInMonth = function (yr, m)
		{
		  switch(m)
		  {
		    case 0: case 2: case 4: case 6: case 7: case 9: case 11:
		      return 31;
		    case 3: case 5: case 8: case 10:
		      return 30;
		    case 1:
		      // February: check if leap year
		      var numDays = 28;
		      if (this.isLeapYear(yr)) numDays = 29;
		      return numDays;
		    default:
		      // wrong month was passed
		      return 0;
		  }
		}
		
		/**
		 * Converts midnight to the previous day at 23:59:59 for display purposes only.
		 * If the parameter doesn't land on midnight, returns unaltered.
		 * @param dt is a date/time string: 2007 03 28 11:00:00
		 * @return new Date object
		 */
		this.adjustMidnight = function(dt)
		{
		  var newDate = this.makeDate(dt);
		  var yr = parseInt(dt.substr(0,4),10);
		  var mn = parseInt(dt.substr(5,2),10) - 1;
		  var dy = parseInt(dt.substr(8,2),10);
		  var tm = dt.substr(11, dt.length-1).split(':');
		  var hr = parseInt(tm[0],10);
		  var min = parseInt(tm[1],10);
		  var sec = parseInt(tm[2],10);
		
		  if (hr == 0 && min == 0 && sec == 0) // midnight
		  {
		    // if first day of month, need to roll back the month
		    if (dy == 1)
		    {
		      // if january - roll back to December 31
		      if (mn == 0)
		      {
		        mn = 11;
		        dy = 31;
		        yr -= 1;
		      } else {
		        mn -= 1;
		        // determine the end day for the new month
		        dy = this.getDaysInMonth(yr, mn);
		      }
		    } else {
		      dy -= 1;
		    }
		    // set the new Date
		    newDate = new Date(yr,mn,dy,23,59,59);
		  }
		  return newDate;
		};
		
		
		
		/*Builds a table for a single record.  Each row is a new field with
		 * two columns.  First is field name, second is value.  Uses the GetMoreInfo 
		 * servlet default XML response.
		 */
		this.buildSingleRecordTable = function(responseXML){
		  var fields = responseXML.getElementsByTagName("field");
		        
		        if(!fields || fields.length == 0){return;}
		    var theTable=document.createElement('table');
		        var theBody=document.createElement('tbody');
		        var oddEven="odd";
		        for (var i =0; i < fields.length; i++){
		          var thisFieldName="";
		          var thisFieldLabel="";
		          var thisFieldData="";
		          var thisField=fields[i];
		          for (var k = 0; k < thisField.childNodes.length; k++){
		            var fieldInfo=thisField.childNodes[k].nodeName;
		      var theText="";
		      if(thisField.childNodes[k].firstChild){
		            var theText=thisField.childNodes[k].firstChild.nodeValue;
		      }
		            switch(fieldInfo){
		             case 'fieldName':
		             thisFieldName=theText;
		             break;
		             case 'fieldLabel':
		             thisFieldLabel=theText+":";
		             break;
		             case 'fieldData':
		             thisFieldData=theText;
		             break;
		            }
		          }
		          var thisRow=document.createElement('tr');
		          thisRow.id=thisFieldName;
		          thisRow.className="record row_"+oddEven;
		          var nameTd=document.createElement('td');
		          nameTd.className="fieldName";
		          nameTd.appendChild(document.createTextNode(thisFieldLabel));
		          var valueTd=document.createElement('td');
		          valueTd.className="fieldValue";
		          valueTd.appendChild(document.createTextNode(thisFieldData));
		          thisRow.appendChild(nameTd);
		          thisRow.appendChild(valueTd);
		          theBody.appendChild(thisRow);
		          if(oddEven=="odd"){oddEven="even";}else{oddEven="odd";}
		          }
		  theTable.appendChild(theBody);
		    return theTable;
		}
		
		this.currentTZ = function() {
		  // determine currenttimezone
		  var tz = (new Date()).getTimezoneOffset() / 60;
		  var tzs = (tz > 0) ? '-':'+'; // set positive or negative offset
		  if (tz < 0) tz *= -1; // reset tz to positive for math
		  tzs += this.set2(Math.floor(tz)) + this.set2(60 * (tz % 1));
		  return tzs;
		}
		
		this.formatTZ = function(tz) {
		  // format the timezone offset for display purposes
		  var tzM = tz.substring(tz.length - 2);
		  var tzH = tz.substring(0, tz.length - 2);
		  return tzH + ':' + tzM;
		}
		
		this.buildSelectOptions = function(selectObj, optObj) {
		  //remove existing options
		  for (var h=selectObj.options.length-1; h>=0; h--) {
		  selectObj.remove(h);
		  }
		    var blankOption = document.createElement("option");
		    blankOption.setAttribute("value", null);
		    selectObj.appendChild(blankOption);
		    for (var prop in optObj){
		      var nextOption = document.createElement("option");
		      nextOption.setAttribute("value", eval("optObj['"+this.escapePunct(prop)+"']"));
		      nextOption.appendChild(document.createTextNode(prop));
		      selectObj.appendChild(nextOption);
		    }
		return selectObj;
		}
		
		/*
		 * function getParameters
		 * Returns array of parameters from the URL string
		 */
		this.getParameters = function() {
		  var parms = new Array();
		  
		  /* Get the URL parameters */
		  var sGet = window.location.search;
		  if (sGet) 
		  {
		    /* cut off the question mark (?) */
		    sGet = sGet.substr(1);
		    
		    /* Generate a string array of the name value pairs. */
		    var sNVPairs = sGet.split('&');
		    
		    /* Extract each name-value pair */
		    for (var i = 0; i < sNVPairs.length; i++)
		    {
		        /* Assign the pair to the GETDATA array. */
		        var sNV = sNVPairs[i].split('=');
		        parms[sNV[0]] = sNV[1];
		    }
		  }
		  return parms;
		}
		
		/* 
		 * function getParameter
		 * Parameter: key - name of the parameter
		 * Returns the value of the parameter, or null if it doesn't exist
		 */
		this.getParameter = function(key) {
		  var retVal = null;
		  parms = this.getParameters();
		  if (parms[key]) { retVal = parms[key]; }
		  return retVal;
		}
		
		/*
		 * function URLEncode
		 * Parameter: clearString - the string value to encode
		 * Returns the encoded string
		 */
		this.URLEncode = function(clearString) {
		  var output = '';
		  var x = 0;
      var regex = /(^[a-zA-Z0-9_.]*)/;

      if (typeof clearString != 'undefined' ) {
	      clearString = clearString.toString();
	      while (x < clearString.length) {
	        var match = regex.exec(clearString.substr(x));
	        if (match != null && match.length > 1 && match[1] != '') {
	          output += match[1];
	          x += match[1].length;
	        } else {
	          if (clearString[x] == ' ')
	            output += '+';
	          else {
	            var charCode = clearString.charCodeAt(x);
	            var hexVal = charCode.toString(16);
	            output += '%' + ( hexVal.length < 2 ? '0' : '' ) + hexVal.toUpperCase();
	          }
	          x++;
	        }
	      }
			}
		  return output;
		}
		      
    /*
     * function replaceHTMLEntity
     * Parameter: clearString - the string value to check
     * Returns the string with HTML characters replaced with their entities  
     */
    this.replaceHTMLEntity = function(clearString) {
      var output = '';
      var x = 0;
      var regex = /(^[a-zA-Z0-9_.]*)/;

      if (typeof clearString != 'undefined') {
        clearString = clearString.toString();
				while (x < clearString.length) {
					var match = regex.exec(clearString.substr(x));
					if (match != null && match.length > 1 && match[1] != '') {
						output += match[1];
						x += match[1].length;
					}
					else {
						var charCode = clearString.charCodeAt(x);
						output += '&#' + charCode + ';';
						x++;
					}
				}
			}
      return output;
    }

		/*
		 * function escapePunct
		 * Parameter: input string
		 * Returns: escapes all single and double quotes, and backslashes
		 */
    this.escapePunct = function(inString) {
			return inString.replace(/(['"\\])/g, "\\$1");
		}

		/*
		 * function numberOfMonths
		 * Parameter: starting date ("2008 01 01 00:00:00")
		 * Parameter: ending date ("2008 01 01 00:00:00")
		 * Returns integer value for number of months between start and end
		 */
	  this.numberOfMonths = function(start,end) {
	    var numMonths = 0;
	    var numYears = 0;
	    var sYear, sMonth, eYear, eMonth;
	
	    try {
	      sYear  = parseInt(start.substr(0,4),10);
	      sMonth = parseInt(start.substr(5,2),10);
	  
	      eYear    = parseInt(end.substr(0,4),10);
	      eMonth   = parseInt(end.substr(5,2),10);
	  
	      numYears = eYear - sYear;
	      if (numYears > 0) {
	        if (eMonth > sMonth) {
	          numMonths = (eMonth - sMonth + 1) + (12 * numYears);
	        } else {
	          numMonths = (12 - sMonth + 1) + (eMonth) + (12 * (numYears - 1));
	        }
	      } else {
	        numMonths = eMonth-sMonth+1;
	      }
	    } catch (e) {}
	
	    return numMonths;
	  }
	  
	  /*
	   * function incrementMonth
	   * Parameter: current month
	   * Returns an integer representing the next month (1 - 12).
	   * 
	   * This function doesn't care about year.
	   */
	  this.incrementMonth = function(month) {
	    return month == 12 ? 1 : ++month;
	  }
	
	
	  this.getElementsByAttribute = function(attr, val, tag, root)
	  {
	    var method = function(el)
	    {
	      var re = new RegExp('(?:^|\\s+)' + val + '(?:\\s+|$)');
	      if (el.getAttribute(attr) && re.test(el.getAttribute(attr))) {
	        return true;
	      }
	      return false;
	    };
	    return dom.getElementsBy(method, tag, root);
	  };
	
	
	  this.getElementsByTag = function(tag, root)
	  {
	    var method = function(el)
	    {
	      return true;
	    };
	    return dom.getElementsBy(method, tag, root);
	  };
	
	
	  /*
	   * function addValidationError
	   * Parameter: id | element
	   * 
	   * This function adds a class name of 'validationError' to the element, with 
	   * the intent to add styling that indicates an error condition.  Default 
	   * behavior sets the elements border color to red.
	   */
	  this.addValidationError = function(f) {
	    dom.addClass(f, 'validationError');
	  }
	  
	  /*
	   * function removeValidationError
	   * Parameter: id | element
	   * 
	   * This function removes the 'validationError' class from the element if it
	   * is provided, otherwise, will remove the 'validationError' class from all
	   * elements that have it.
	   */
	  this.removeValidationError = function(f) {
	    if (f) {
	      // remove the class from the element provided
	      dom.removeClass(f, 'validationError');
	    } else {
	      // remove the class from all elements that have it
	      var els = dom.getElementsByClassName('validationError', null, 'evtedit');
	      dom.removeClass(els, 'validationError');
	    }
	  }
	  
	  /*
	   * Validates that a date is formatted correctly.  Currently the Java
	   * application only supports English locale.
	   *   
	   * The month name may be all lowercase, all uppercase, or camelcase.  The
	   * first three letters of the month must be supplied, and optionally the
	   * entire month name.
	   * 
	   * i.e. - "Apr 14, 2008" or "April 14, 2008".
	   */
	  this.validateDateFormat = function(val) {
	    var pattern = /^[A-Za-z]{3,}\s\d{1,2},\s\d{4}$/;
	    return pattern.test(val);
	  }
	  
	  /*
	   * Checks a URL to see if begins with a scheme.
	   */
	  this.checkUrlScheme = function(url) {
	    var urlscheme = /^[A-Za-z][A-Za-z0-9+-.]+:[\/]{2,3}[A-Za-z0-9]/;
	    var mailscheme = /^mailto:[A-Za-z]/;
	    if (urlscheme.test(url) || mailscheme.test(url)) {
	      return true;
	    }
	
	    return false;
	  }

  }; // KD.calendar.Util
}


/* JSON string parser
  http://www.json.org/js.html
 */
    (function (s) {

// Augment String.prototype. We do this in an immediate anonymous function to
// avoid defining global variables.

// m is a table of character substitutions.

        var m = {
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        };


        s.parseJSON = function (filter) {
            var j;

            function walk(k, v) {
                var i;
                if (v && typeof v === 'object') {
                    for (i in v) {
                        if (v.hasOwnProperty(i)) {
                            v[i] = walk(i, v[i]);
                        }
                    }
                }
                return filter(k, v);
            }


// Parsing happens in three stages. In the first stage, we run the text against
// a regular expression which looks for non-JSON characters. We are especially
// concerned with '()' and 'new' because they can cause invocation, and '='
// because it can cause mutation. But just to be safe, we will reject all
// unexpected characters.

            if (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.
                    test(this)) {

// In the second stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.

                try {
                    j = eval('(' + this + ')');
                } catch (e) {
                    throw new SyntaxError("parseJSON");
                }
            } else {
                throw new SyntaxError("parseJSON");
            }

// In the optional third stage, we recursively walk the new structure, passing
// each name/value pair to a filter function for possible transformation.

            if (typeof filter === 'function') {
                j = walk('', j);
            }
            return j;
        };


        s.toJSONString = function () {

// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can simply slap some quotes around it.
// Otherwise we must also replace the offending characters with safe
// sequences.

            if (/["\\\x00-\x1f]/.test(this)) {
                return '"' + this.replace(/([\x00-\x1f\\"])/g, function (a, b) {
                    var c = m[b];
                    if (c) {
                        return c;
                    }
                    c = b.charCodeAt();
                    return '\\u00' +
                        Math.floor(c / 16).toString(16) +
                        (c % 16).toString(16);
                }) + '"';
            }
            return '"' + this + '"';
        };
    })(String.prototype);
	
	//KD: Modified function to not use Object.prototype
	toJSONString = function (obj) {
        var a = [],     // The array holding the member texts.
            k,          // The current key.
            v;          // The current value.

// Iterate through all of the keys in the object, ignoring the proto chain.

        for (k in obj) {
            if (obj.hasOwnProperty(k)) {
                v = obj[k];
                switch (typeof v) {
                case 'object':

// Serialize a JavaScript object value. Ignore objects that lack the
// toJSONString method. Due to a specification error in ECMAScript,
// typeof null is 'object', so watch out for that case.

                    if (v) {
                        if (typeof v.toJSONString === 'function') {
                            a.push(k.toJSONString() + ':' + v.toJSONString());
                        }
                    } else {
                        a.push(k.toJSONString() + ':null');
                    }
                    break;

                case 'string':
                case 'number':
                case 'boolean':
                    a.push(k.toJSONString() + ':' + v.toJSONString());

// Values without a JSON representation are ignored.

                }
            }
        }

// Join all of the member texts together and wrap them in braces.

        return '{' + a.join(',') + '}';
    };

