/**
 * enhance Date Object's function( 
 	Date.format("yyyy-MM-dd")
 	Date.parse("yyyy-MM-dd");
   )
 */
Date.prototype.pad = function (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;
}
Date.prototype._defaultFormat = "yyyy-MM-dd";
Date.prototype._format = Date.prototype._defaultFormat;
Date.prototype.format = function(pattern) {  
	if(pattern != null){
		this._format = pattern;
	}

    var bits = new Array();
    // work out what each bit should be
    var date = this;
    bits['d'] = date.getDate();
    bits['dd'] = this.pad(date.getDate(),2);

    bits['M'] = date.getMonth()+1;
    bits['MM'] = this.pad(date.getMonth()+1,2);
    
    var yearStr = "" + 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;
    for (sect in bits) {
      frm = eval("frm.replace(/\\b" + sect + "\\b/,'" + bits[sect] + "');");
    }

    return frm;
}

/**
 *	enhance String Object's function( String.trim() )
 */
String.prototype.trim = function()
{
    return this.replace(/(^[\s]*)|([\s]*$)/g, "");
}

// arrays for month and weekday names
var parseMonthNames = "January February March April May June July August September October November December".split(" ");
var parseWeekdayNames = "Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" ");

/* Takes a string, returns the index of the month matching that string, throws
   an error if 0 or more than 1 matches
*/
function parseMonth(month) {
    var matches = parseMonthNames.filter(function(item) { 
        return new RegExp("^" + month, "i").test(item);
    });
    if (matches.length == 0) {
        throw new Error("Invalid month string");
    }
    if (matches.length < 1) {
        throw new Error("Ambiguous month");
    }
    return parseMonthNames.indexOf(matches[0]);
}

/* Same as parseMonth but for days of the week */
function parseWeekday(weekday) {
    var matches = parseWeekdayNames.filter(function(item) {
        return new RegExp("^" + weekday, "i").test(item);
    });
    if (matches.length == 0) {
        throw new Error("Invalid day string");
    }
    if (matches.length < 1) {
        throw new Error("Ambiguous weekday");
    }
    return parseWeekdayNames.indexOf(matches[0]);
}

function DateInRange( yyyy, mm, dd ){
   // if month out of range
   if ( mm < 0 || mm > 11 )
      throw new Error('Invalid month value.  Valid months values are 1 to 12');

   // get last day in month
   var d = (11 == mm) ? new Date(yyyy + 1, 0, 0) : new Date(yyyy, mm + 1, 0);

   // if date out of range
   if ( dd < 1 || dd > d.getDate() )
      throw new Error('Invalid date value.  Valid date values for ' + parseMonthNames[mm] + ' are 1 to ' + d.getDate().toString());

   return true;
}

/* Array of objects, each has 're', a regular expression and 'handler', a 
   function for creating a date from something that matches the regular 
   expression. Handlers may throw errors if string is unparseable. 
*/
var dateParsePatterns = [
    // Today
    {   re: /^today/i,
        handler: function() { 
            return new Date();
        } 
    },
    // Tomorrow
    {   re: /^tomorrow/i,
        handler: function() {
            var d = new Date(); 
            d.setDate(d.getDate() + 1); 
            return d;
        }
    },
    // Yesterday
    {   re: /^yesterday/i,
        handler: function() {
            var d = new Date();
            d.setDate(d.getDate() - 1);
            return d;
        }
    },
    // mmddyyyy (American style)
    {   re: /(\d{2})(\d{2})(\d{4})/,
        handler: function(bits) {
            var yyyy = parseInt(bits[3], 10);
            var dd = parseInt(bits[2], 10);
            var mm = parseInt(bits[1], 10) - 1;

            if ( DateInRange( yyyy, mm, dd ) )
               return new Date(yyyy, mm, dd);

        }
    },
    // mmddyy (American style) short year
    {   re: /(\d{2})(\d{2})(\d{2})/,
        handler: function(bits) {
            var d = new Date();
            var yyyy = d.getFullYear() - (d.getFullYear() % 100) + parseInt(bits[3], 10);
            var dd = parseInt(bits[2], 10);
            var mm = parseInt(bits[1], 10) - 1;

            if ( DateInRange(yyyy, mm, dd) )
               return new Date(yyyy, mm, dd);

        }
    },
    // 4th
    {   re: /^(\d{1,2})(st|nd|rd|th)?$/i, 
        handler: function(bits) {
            var d = new Date();
            var yyyy = d.getFullYear();
            var dd = parseInt(bits[1], 10);
            var mm = d.getMonth();

            if ( DateInRange( yyyy, mm, dd ) )
               return new Date(yyyy, mm, dd);

        }
    },
    // 4th Jan
    {   re: /^(\d{1,2})(?:st|nd|rd|th)? (\w+)$/i, 
        handler: function(bits) {
            var d = new Date();
            var yyyy = d.getFullYear();
            var dd = parseInt(bits[1], 10);
            var mm = parseMonth(bits[2]);

            if ( DateInRange( yyyy, mm, dd ) )
               return new Date(yyyy, mm, dd);

        }
    },
    // 4th Jan 2003
    {   re: /^(\d{1,2})(?:st|nd|rd|th)? (\w+),? (\d{4})$/i,
        handler: function(bits) {
            var yyyy = parseInt(bits[3], 10);
            var dd = parseInt(bits[1], 10);
            var mm = parseMonth(bits[2]);

            if ( DateInRange( yyyy, mm, dd ) )
               return new Date(yyyy, mm, dd);

        }
    },
    // Jan 4th
    {   re: /^(\w+) (\d{1,2})(?:st|nd|rd|th)?$/i, 
        handler: function(bits) {
            var d = new Date();
            var yyyy = d.getFullYear(); 
            var dd = parseInt(bits[2], 10);
            var mm = parseMonth(bits[1]);

            if ( DateInRange( yyyy, mm, dd ) )
               return new Date(yyyy, mm, dd);

        }
    },
    // Jan 4th 2003
    {   re: /^(\w+) (\d{1,2})(?:st|nd|rd|th)?,? (\d{4})$/i,
        handler: function(bits) {
            var yyyy = parseInt(bits[3], 10); 
            var dd = parseInt(bits[2], 10);
            var mm = parseMonth(bits[1]);

            if ( DateInRange( yyyy, mm, dd ) )
               return new Date(yyyy, mm, dd);

        }
    },
    // next Tuesday - this is suspect due to weird meaning of "next"
    {   re: /^next (\w+)$/i,
        handler: function(bits) {
            var d = new Date();
            var day = d.getDay();
            var newDay = parseWeekday(bits[1]);
            var addDays = newDay - day;
            if (newDay <= day) {
                addDays += 7;
            }
            d.setDate(d.getDate() + addDays);
            return d;

        }
    },
    // last Tuesday
    {   re: /^last (\w+)$/i,
        handler: function(bits) {
            var d = new Date();
            var wd = d.getDay();
            var nwd = parseWeekday(bits[1]);
         
            // determine the number of days to subtract to get last weekday
            // calculates 0 if weekdays are the same so we have to change this to 7
            var addDays = (wd == nwd) ? -7 : (-1 * (wd + 7 - nwd)) % 7;
            
            // adjust date and return
            d.setDate(d.getDate() + addDays);
            return d;

        }
    },
    // Tuesday
    {   re: /^(\w+)$/i,
        handler: function(bits) {
            var d = new Date();
            var wd = d.getDay();
            var nwd = parseWeekday(bits[1]);
         
            // if same weekday, return date         
            if (nwd == wd)
               return d;

            // if new weekday is before current weekday
            if (nwd < wd )
               {
 
               // calculate last weekday
               d.setDate(d.getDate() + ((wd == nwd) ? -7 : (-1 * (wd + 7 - nwd)) % 7));

               }
            // if new weekday is after current weekday
            else
               {

               // calculate next weekday
               d.setDate(d.getDate() + (nwd - wd));

               }
               
            return d;

        }
    },
    // mm/dd/yyyy (American style)
    {   re: /(\d{1,2})\/(\d{1,2})\/(\d{4})/,
        handler: function(bits) {
            var yyyy = parseInt(bits[3], 10);
            var dd = parseInt(bits[2], 10);
            var mm = parseInt(bits[1], 10) - 1;

            if ( DateInRange( yyyy, mm, dd ) )
               return new Date(yyyy, mm, dd);

        }
    },
    // mm/dd/yy (American style) short year
    {   re: /(\d{1,2})\/(\d{1,2})\/(\d{1,2})/,
        handler: function(bits) {
            var d = new Date();
            var yyyy = d.getFullYear() - (d.getFullYear() % 100) + parseInt(bits[3], 10);
            var dd = parseInt(bits[2], 10);
            var mm = parseInt(bits[1], 10) - 1;

            if ( DateInRange(yyyy, mm, dd) )
               return new Date(yyyy, mm, dd);

        }
    },
    // mm/dd (American style) omitted year
    {   re: /(\d{1,2})\/(\d{1,2})/,
        handler: function(bits) {
            var d = new Date();
            var yyyy = d.getFullYear();
            var dd = parseInt(bits[2], 10);
            var mm = parseInt(bits[1], 10) - 1;

            if ( DateInRange(yyyy, mm, dd) )
               return new Date(yyyy, mm, dd);

        }
    },
    // yyyy-mm-dd (ISO style)
    {   re: /(\d{4})-(\d{1,2})-(\d{1,2})/,
        handler: function(bits) {
            var yyyy = parseInt(bits[1], 10);
            var dd = parseInt(bits[3], 10);
            var mm = parseInt(bits[2], 10) - 1;

            if ( DateInRange( yyyy, mm, dd ) )
               return new Date(yyyy, mm, dd);

        }
    },
    // yy-mm-dd (ISO style) short year
    {   re: /(\d{1,2})-(\d{1,2})-(\d{1,2})/,
        handler: function(bits) {
            var d = new Date();
            var yyyy = d.getFullYear() - (d.getFullYear() % 100) + parseInt(bits[1], 10);
            var dd = parseInt(bits[3], 10);
            var mm = parseInt(bits[2], 10) - 1;

            if ( DateInRange( yyyy, mm, dd ) )
               return new Date(yyyy, mm, dd);

        }
    },
    // mm-dd (ISO style) omitted year
    {   re: /(\d{1,2})-(\d{1,2})/,
        handler: function(bits) {
            var d = new Date();
            var yyyy = d.getFullYear();
            var dd = parseInt(bits[2], 10);
            var mm = parseInt(bits[1], 10) - 1;

            if ( DateInRange( yyyy, mm, dd ) )
               return new Date(yyyy, mm, dd);
        }
    }
];

// parses date string input
function parseDateString( strDateInput ){
   // cycle through date parse patterns
   for (var i = 0; i < dateParsePatterns.length; i++){
      // get regular expression for this pattern
      var re = dateParsePatterns[i].re;

      // get handler function for this pattern
      var handler = dateParsePatterns[i].handler;

      // parse input using regular expression
      var bits = re.exec(strDateInput);

      // if there was a match
      if (bits){
         //alert( re );
         // return the result of the handler function (which constitutes bits into a date)
         return handler(bits);
      }

   }

   // if no pattern matched - throw exception
   throw new Error("Invalid date string");
}

Date.parse = function( strDateInput ) {
	return parseDateString(strDateInput);
};

Function.prototype.toSource = function()
{
	 var firstIndex = this.toString().indexOf("{");
	 var lastIndex = this.toString().lastIndexOf("}");
	 return this.toString().substring(firstIndex+1,lastIndex);
    //return /{([^{}]*)}/.exec(this.toString())[1];
}

function TrackCount(fieldObj,maxChars)
{
  //var countField = eval("fieldObj.form."+countFieldName);
  var diff = maxChars - fieldObj.value.length;

  // Need to check & enforce limit here also in case user pastes data
  if (diff < 0)
  {
    fieldObj.value = fieldObj.value.substring(0,maxChars);
    diff = maxChars - fieldObj.value.length;
  }
  //countField.value = diff;
}

function LimitText(fieldObj,maxLength)
{
/*
  var result = true;
  if (fieldObj.value.length >= maxChars)
    result = false;

  if (window.event)
    window.event.returnValue = result;
  return result;
*/
	var length = lengthCount(fieldObj.value);
	var diff = maxLength - length;
  	if (diff < 0)
  	{
  		var tempText = "";
  		var temp = "";
  		var tempLen;
  	
	  	for(var i = 1; i < maxLength; i++){
  			temp = fieldObj.value.substring(0, i);
	  		tempLen = lengthCount(temp);
  			if(tempLen <= maxLength){
  				tempText = temp;
  			}else{
  				break;
  			}
  		}
//  		alert("³¤¶ÈÏÞÖÆ");
  		fieldObj.value = tempText;
  	}
}  

function lengthCount(value){
	var length = value.replace(/[^\x00-\xff]/g, "aa").length;				
	return length;
}

/********************************************************************************************************/
function Point(iX, iY){
	this.x = iX;
	this.y = iY;
}

Point.prototype.toString = function() {
	return "x:"+this.x+" "+"y:"+this.y;
}

/**
 * judge if current point is in the object's area
 */
Point.prototype.isInObject = function(obj){
	var objLT = getLeftTop(obj);
	var objLB = new Point(objLT.x, objLT.y + obj.offsetHeight);
	var objRT = new Point(objLT.x + obj.offsetWidth, objLT.y);
	var objRB = new Point(objLT.x + obj.offsetWidth, objLT.y + obj.offsetHeight);
	//alert(objLT.toString()+"\n"+objLB.toString()+"\n"+objRT.toString()+"\n"+objRB.toString())
	var isIn =false;
	if(this.x > objLT.x && this.x < objRT.x && this.y > objLT.y && this.y < objLB.y){
		isIn = true;
	}
	return isIn;
}

/**
 * get the relative position of the object's left-top point
 */
function getLeftTop(obj){
	var oTmp = obj;
	var pt = new Point(0,0);
	do {
		pt.x += oTmp.offsetLeft;
		pt.y += oTmp.offsetTop;
		oTmp = oTmp.offsetParent;
	} while(oTmp.tagName!="BODY");

	return pt;
}

/**
 * judge if two object are intersectant
 */
function isIntersect(outerObj,innerObj){
	var outerObjLT = getLeftTop(outerObj);
	var innerObjLT = getLeftTop(innerObj);
	
	return !(outerObjLT.y > (innerObjLT.y + innerObj.offsetHeight)  || (outerObjLT.y + outerObj.offsetHeight) < innerObjLT.y 
			  || outerObjLT.x > (innerObjLT.x + innerObj.offsetWidth) || (outerObjLT.x + outerObj.offsetWidth) < innerObjLT.x 
			 );
}


/**
 * hidden all selects in the page which is intersecting with the upperObj.
 */
function switchCoverItemView(upperObj)
{
	var bottomSelects = null;
	if( "undefine" == upperObj.bottomSelects || null == upperObj.bottomSelects){
		upperObj.bottomSelects = new Array();
	}
	bottomSelects = upperObj.bottomSelects;
	
	var selectElms  = window.document.all.tags("select");
	for(i=0;i<selectElms.length;i++){
		if(isIntersect(buttonBar,selectElms[i])){
			selectElms[i].style.visibility = "hidden";
			bottomSelects[selectElms[i].name] = selectElms[i];
		}else if("hidden" == selectElms[i].style.visibility){
			if("undefine" != bottomSelects[selectElms[i].name] && null != bottomSelects[selectElms[i].name]){
				bottomSelects[selectElms[i].name] = null;
				selectElms[i].style.visibility = "";					
			}				
		}
	}			
}


/***************************************** pressing "enter" to focus ************************************/
/*get the input field's index of the form*/
function getIndex(inputObj){
	var index = -1;
	var isFound = false;
	for(var i = 0 ; i < inputObj.form.elements.length ; i++){
		if(inputObj.form[i] == inputObj){
			isFound = true;
			index = i;
			break;
		}
	}
	return isFound?index:0;
}

function addEventHandler(eventFuncObj,funcStr){
	var funcSource = eventFuncObj.toSource();
	if(funcSource.trim().length > 0){
		if(funcSource.indexOf(";") > -1){
			funcSource = funcSource.substring(0,funcSource.lastIndexOf(";")) + funcStr;
		}else{
			funcSource = funcSource + ";" + funcStr;
		}
	}else{
		funcSource = funcStr;
	}
	//alert(funcSource);
	//eventFuncObj = new Function(funcSource);
	return new Function(funcSource);
}

function keyPressHandler(field,nextFieldName,e){
	if(e.keyCode == 13){
		//alert(e.keyCode + "," + e.ctrlKey);
		e.keyCode = 9;
		//focusToNext(field);
		dbform[nextFieldName].focus();
		return false;
	}
}


/* TODO not work property */
function onTextareaKeyDown(field,e){
	if(e.keyCode == 13 && e.ctrlKey){
		//alert(e.keyCode + "," + e.ctrlKey);
		e.keyCode = 13;
		e.returnvalue = false;		
		return;
	}
	
}


function initEnterToTab(formObj){
	for(var i = 0 ; i < formObj.elements.length ; i++)	{
		var tempField = formObj[i];

		try{
		
			if(!canFocusField(tempField, sortedFields) || tempField.type == "textarea"){
				continue;			
			}			
								
			var nextField;
			for(var j = i+1 ; j < formObj.length ; j++){
				var tempNextField = formObj[j];
				if(canFocusField(tempNextField, sortedFields)){
					nextField = tempNextField;
					break;			
				}			
			}
			
			if(null == nextField) continue;
			
			if(null == tempField.onkeypress){
				tempField.onkeypress = new Function();
			}			
			tempField.onkeypress = addEventHandler(tempField.onkeypress,"keyPressHandler(this,'"+nextField.name+"',event)");
					
			//alert(sortedFields[tempField.name] + "," + tempField.onkeypress);
		}catch(e){
			alert(e.description);
		}
	}
	
	function canFocusField(fieldObj,bizFields){
		if("undefined" == bizFields[fieldObj.name] || null == bizFields[fieldObj.name] || fieldObj.className == "readonly" || fieldObj.type == "hidden"){
			return false;			
		}			
		return true;
	}	
}



