/*

Name: jsDate
Desc: VBScript native Date functions emulated for Javascript
Author: Rob Eberhardt, Slingshot Solutions - http://slingfive.com/
History:
	2005-08-04	v0.94		scrapped new dateDiff approach to better match VBScript's simplistic Y/M/Q
	2005-08-03	v0.93		fixed dateDiff/leapyear bug with yyyy/m/q intervals
	2004-11-26	v0.91		fixed datePart/ww bug, added weekdayName() & monthName()
	2004-08-30	v0.9		brand new
	
*/

// used by dateAdd, dateDiff, datePart, weekdayName, and monthName
// note: less strict than VBScript's isDate, since JS allows invalid dates to overflow (e.g. Jan 32 transparently becomes Feb 1)
function isDate(p_Expression){
	return !isNaN(new Date(p_Expression));		// <<--- this needs checking
}
// handle a specific date format 2004-11-05T00:00:00Z
function getWhoisDate(d){
	var dVal = d.toUpperCase().replace("Z","");
	var dAry = dVal.split("T")[0].split("-");
	var tAry = dVal.split("T")[1].split(":")
	//dAry[1] + "/" + dAry[2] + "/" + dAry[0];
	return (new Date(dAry[1] + "/" + dAry[2] + "/" + dAry[0]));
}

// REQUIRES: isDate()
function dateAdd(p_Interval, p_Number, p_Date){
	if(!isDate(p_Date)){return "invalid date: '" + p_Date + "'";}
	if(isNaN(p_Number)){return "invalid number: '" + p_Number + "'";}	

	p_Number = new Number(p_Number);
	var dt = new Date(p_Date);
	switch(p_Interval.toLowerCase()){
		case "yyyy": {// year
			dt.setFullYear(dt.getFullYear() + p_Number);
			break;
		}
		case "q": {		// quarter
			dt.setMonth(dt.getMonth() + (p_Number*3));
			break;
		}
		case "m": {		// month
			dt.setMonth(dt.getMonth() + p_Number);
			break;
		}
		case "y":		// day of year
		case "d":		// day
		case "w": {		// weekday
			dt.setDate(dt.getDate() + p_Number);
			break;
		}
		case "ww": {	// week of year
			dt.setDate(dt.getDate() + (p_Number*7));
			break;
		}
		case "h": {		// hour
			dt.setHours(dt.getHours() + p_Number);
			break;
		}
		case "n": {		// minute
			dt.setMinutes(dt.getMinutes() + p_Number);
			break;
		}
		case "s": {		// second
			dt.setSeconds(dt.getSeconds() + p_Number);
			break;
		}
		case "ms": {		// second
			dt.setMilliseconds(dt.getMilliseconds() + p_Number);
			break;
		}
		default: {
			return "invalid interval: '" + p_Interval + "'";
		}
	}
	return dt;
}




// REQUIRES: isDate()
// NOT SUPPORTED: firstdayofweek and firstweekofyear (defaults for both)
function dateDiff(p_Interval, p_Date1, p_Date2, p_firstdayofweek, p_firstweekofyear){
	if(!isDate(p_Date1)){return "invalid date: '" + p_Date1 + "'";}
	if(!isDate(p_Date2)){return "invalid date: '" + p_Date2 + "'";}
	var dt1 = new Date(p_Date1);
	var dt2 = new Date(p_Date2);

	// get ms between dates (UTC) and make into "difference" date
	var iDiffMS = dt2.valueOf() - dt1.valueOf();
	var dtDiff = new Date(iDiffMS);

	// calc various diffs
	var nYears  = dt2.getUTCFullYear() - dt1.getUTCFullYear();
	var nMonths = dt2.getUTCMonth() - dt1.getUTCMonth() + (nYears!=0 ? nYears*12 : 0);
	var nQuarters = parseInt(nMonths/3);	//<<-- different than VBScript, which watches rollover not completion
	
	var nMilliseconds = iDiffMS;
	var nSeconds = parseInt(iDiffMS/1000);
	var nMinutes = parseInt(nSeconds/60);
	var nHours = parseInt(nMinutes/60);
	var nDays  = parseInt(nHours/24);
	var nWeeks = parseInt(nDays/7);


	// return requested difference
	var iDiff = 0;		
	switch(p_Interval.toLowerCase()){
		case "yyyy": return nYears;
		case "q": return nQuarters;
		case "m": return nMonths;
		case "y": 		// day of year
		case "d": return nDays;
		case "w": return nDays;
		case "ww":return nWeeks;		// week of year	// <-- inaccurate, WW should count calendar weeks (# of sundays) between
		case "h": return nHours;
		case "n": return nMinutes;
		case "s": return nSeconds;
		case "ms":return nMilliseconds;	// millisecond	// <-- extension for JS, NOT available in VBScript
		default: return "invalid interval: '" + p_Interval + "'";
	}
}



// REQUIRES: isDate(), dateDiff()
// NOT SUPPORTED: firstdayofweek and firstweekofyear (does system default for both)
function datePart(p_Interval, p_Date, p_firstdayofweek, p_firstweekofyear){
	if(!isDate(p_Date)){return "invalid date: '" + p_Date + "'";}

	var dtPart = new Date(p_Date);
	switch(p_Interval.toLowerCase()){
		case "yyyy": return dtPart.getFullYear();
		case "q": return parseInt(dtPart.getMonth()/3)+1;
		case "m": return dtPart.getMonth()+1;
		case "y": return dateDiff("y", "1/1/" + dtPart.getFullYear(), dtPart);			// day of year
		case "d": return dtPart.getDate();
		case "w": return dtPart.getDay();	// weekday
		case "ww":return dateDiff("ww", "1/1/" + dtPart.getFullYear(), dtPart);		// week of year
		case "h": return dtPart.getHours();
		case "n": return dtPart.getMinutes();
		case "s": return dtPart.getSeconds();
		case "ms":return dtPart.getMilliseconds();	// millisecond	// <-- extension for JS, NOT available in VBScript
		default: return "invalid interval: '" + p_Interval + "'";
	}
}

// REQUIRES: isDate()
// NOT SUPPORTED: firstdayofweek (does system default)
function weekdayName(p_Date, p_abbreviate){
	if(!isDate(p_Date)){return "invalid date: '" + p_Date + "'";}
	var dt = new Date(p_Date);
	var retVal = dt.toString().split(' ')[0];
	var retVal = Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday')[dt.getDay()];
	if(p_abbreviate==true){retVal = retVal.substring(0, 3)}	// abbr to 1st 3 chars
	return retVal;
}

// REQUIRES: isDate()
function monthName(p_Date, p_abbreviate){
	if(!isDate(p_Date)){return "invalid date: '" + p_Date + "'";}
	var dt = new Date(p_Date);	
	var retVal = Array('January','February','March','April','May','June','July','August','September','October','November','December')[dt.getMonth()];
	if(p_abbreviate==true){retVal = retVal.substring(0, 3)}	// abbr to 1st 3 chars
	return retVal;
}


/* my date funtions
-------------------------------*/
function smallDate(p_Date,returnAsDateObj){
	if(!isDate(p_Date)){return "invalid date: '" + p_Date + "'";}
	var smallDateText = datePart("m",p_Date) + "/" + datePart("d",p_Date) + "/" + datePart("yyyy",p_Date);
	if (returnAsDateObj){
		return new Date(smallDateText);
	}else{
		return smallDateText;
	}
}

function smallDateTime(p_Date,returnAsDateObj){
	if(!isDate(p_Date)){return "invalid date: '" + p_Date + "'";}
	var smallDateText = datePart("m",p_Date) + "/" + datePart("d",p_Date) + "/" + datePart("yyyy",p_Date);
	smallDateText += " " + datePart("h",p_Date) + ":" + datePart("n",p_Date) + ":" + datePart("s",p_Date);
	if (returnAsDateObj){
		return new Date(smallDateText);
	}else{
		return smallDateText;
	}
}

function now(justSmall){
	var dt = new Date();
	if (justSmall){
		return new Date(smallDate(dt));
	}else{
		return dt;
	}
	
}

function lastDayOfMonth(p_Date){
	if(!isDate(p_Date)){return "invalid date: '" + p_Date + "'";}
	var d = dateAdd("m",1,p_Date);
	var nd = dateAdd("d",-1,datePart("m",d) + "/1/" + datePart("yyyy",d));
	return smallDate(nd);
}

function firstDayOfMonth(p_Date){
	if(!isDate(p_Date)){return "invalid date: '" + p_Date + "'";}
	return smallDate(datePart("m",p_Date) + "/1/" + datePart("yyyy",p_Date));
}

function weekDaysInMonth(p_Date){
	if(!isDate(p_Date)){return "invalid date: '" + p_Date + "'";}
	var dayCount = datePart("d",lastDayOfMonth(p_Date))
	var thisStartDate = firstDayOfMonth(p_Date);
	wdCount = 0;
	for (var i=0;i<dayCount;i++){
		var cd = dateAdd("d",i,thisStartDate).getDay();
		if (cd!=0 && cd!=6){wdCount ++;}
	}
	return wdCount;
	//console.info("%s weekdays in %s,%s", wdCount,monthName(p_Date),datePart("yyyy",p_Date));
}

function isWeekDay(p_Date){
	if(!isDate(p_Date)){return false;}else{p_Date = new Date(p_Date);}
	//console.info(newDay.dateValue);
	return p_Date.getDay() != 0 && p_Date.getDay() != 6;
}


function getQuarterStart(p_Date){
	if(!isDate(p_Date)){ var p_Date = now();}
	var p_Date = new Date(p_Date);
	var pMonth = datePart("m",p_Date);
	var pYear = datePart("yyyy",p_Date);
	if (pMonth < 4){ return new Date("1/1/" + pYear); }
	if (pMonth >= 4 && pMonth < 7){ return new Date("4/1/" + pYear); }
	if (pMonth >= 7 && pMonth < 10){ return new Date("7/1/" + pYear); }
	if (pMonth >= 10){ return new Date("10/1/" + pYear); }
}


function getQuarterValue(p_Date){
	if(!isDate(p_Date)){ var p_Date = now();}
	var p_Date = new Date(p_Date);
	var pMonth = datePart("m",p_Date);
	var pYear = datePart("yyyy",p_Date);
	if (pMonth < 4){ return 1; }
	if (pMonth >= 4 && pMonth < 7){ return 2; }
	if (pMonth >= 7 && pMonth < 10){ return 3; }
	if (pMonth >= 10){ return 4; }
}




// ====================================

// bootstrap different capitalizations
function IsDate(p_Expression){
	return isDate(p_Expression);
}
function DateAdd(p_Interval, p_Number, p_Date){
	return dateAdd(p_Interval, p_Number, p_Date);
}
function DateDiff(p_interval, p_date1, p_date2, p_firstdayofweek, p_firstweekofyear){
	return dateDiff(p_interval, p_date1, p_date2, p_firstdayofweek, p_firstweekofyear);
}
function DatePart(p_Interval, p_Date, p_firstdayofweek, p_firstweekofyear){
	return datePart(p_Interval, p_Date, p_firstdayofweek, p_firstweekofyear);
}
function WeekdayName(p_Date){
	return weekdayName(p_Date);
}
function MonthName(p_Date){
	return monthName(p_Date);
}

// ====================================
// format values %y,%m,%d,%h,%n,%s
var smartDateDiffFormatString = "";
function smartDateDiff(sDate,eDate,formatString,adPrm){
	
	smartDateDiffFormatString = formatString?formatString:"";
	
	if (!sDate || !eDate){
		return "";
	}else{
		sDate = smallDate(sDate,true)
		eDate = smallDate(eDate,true)
	}

	if (sDate > eDate){ 
		var tDate = eDate;
		eDate = sDate;
		sDate = tDate;
	}
	

	if (adPrm.abbreviate){
		var yName = "yr";
		var mName = "mo";
		var dName = "day";
		var hName = "hr";
		var nName = "min";
		var sName = "sec";
	}else{
		var yName = "year";
		var mName = "month";
		var dName = "day";
		var hName = "hour";
		var nName = "minute";
		var sName = "second";
	}
	console.info(sDate);
	if (adPrm.getlargest){
		smartDateDiffFormatString = "%y";
		if (!getDiff("yyyy",smartDateDiffFormatString,yName,sDate,eDate)){
			smartDateDiffFormatString = "%m";
			if (!getDiff("m",smartDateDiffFormatString,mName,sDate,eDate)){
				smartDateDiffFormatString = "%d";
				if (!getDiff("d",smartDateDiffFormatString,dName,sDate,eDate)){
					smartDateDiffFormatString = "%h";
					if (!getDiff("h",smartDateDiffFormatString,hName,sDate,eDate)){
						smartDateDiffFormatString = "%n";
						if (!getDiff("n",smartDateDiffFormatString,nName,sDate,eDate)){
							smartDateDiffFormatString = "%s";
							getDiff("s",smartDateDiffFormatString,sName,sDate,eDate)
						}
					}
				}
			}
		}
	}else if (adPrm.getall){
		var outVal = {};
		curEndDate = eDate;
		outVal.years = dateDiff("yyyy",sDate,curEndDate);
		if (outVal.years > 0){ curEndDate = dateAdd("yyyy",outVal.years*-1,curEndDate); }
		outVal.months = dateDiff("m",sDate,curEndDate);
		if (outVal.months > 0){ curEndDate = dateAdd("m",outVal.months*-1,curEndDate); }
		outVal.days = dateDiff("d",sDate,curEndDate);
		if (outVal.days > 0){ curEndDate = dateAdd("d",outVal.days*-1,curEndDate); }
		outVal.hours = dateDiff("h",sDate,curEndDate);
		if (outVal.hours > 0){ curEndDate = dateAdd("h",outVal.hours*-1,curEndDate); }
		outVal.minutes = dateDiff("n",sDate,curEndDate);
		if (outVal.minutes > 0){ curEndDate = dateAdd("n",outVal.minutes*-1,curEndDate); }
		outVal.seconds = dateDiff("s",sDate,curEndDate);
		if (outVal.seconds > 0){ curEndDate = dateAdd("n",outVal.seconds*-1,curEndDate); }
		return outVal;		
	}else{
		getDiff("yyyy","%y",yName,sDate,eDate);
		getDiff("m","%m",mName,sDate,eDate);
		getDiff("d","%d",dName,sDate,eDate);
		getDiff("h","%h",hName,sDate,eDate);
		getDiff("n","%n",nName,sDate,eDate);
		getDiff("s","%s",sName,sDate,eDate);	
	}
	return smartDateDiffFormatString
}


function getDiff(intervalType,replaceKey,realName,startDate,endDate){
	var madeChange = false;
	if (smartDateDiffFormatString.indexOf(replaceKey) >= 0){
		intervalDifference = dateDiff(intervalType,startDate,endDate);
		if (dateAdd(intervalType,intervalDifference,startDate) > endDate){ intervalDifference = intervalDifference - 1; }
		startDate = dateAdd(intervalType,intervalDifference,startDate);
		
		if (intervalDifference <= 0){ 
			smartDateDiffFormatString = smartDateDiffFormatString.replace(replaceKey,"");
			
		}
		else if (intervalDifference == 1){
			smartDateDiffFormatString = smartDateDiffFormatString.replace(replaceKey,intervalDifference + " " + realName);
			madeChange = true;
		}
		else if (intervalDifference > 1){
			smartDateDiffFormatString = smartDateDiffFormatString.replace(replaceKey,intervalDifference + " " + realName + "s" );
			madeChange = true;
		}
	}
	return madeChange;
}