/*

Name: jsDate
Desc: VBScript native Date functions emulated for Javascript
Author: Rob Eberhardt, Slingshot Solutions - http://slingfive.com/
History:
	2007-06-08  v0.95		new functions added by Mindlend AG
	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
}

// 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()){
		// years
		case 'yyyy': {dt.setFullYear(dt.getFullYear() + p_Number);break;}
		// quarters
		case 'q': {dt.setMonth(dt.getMonth() + (p_Number*3));break;}
		// months
		case 'm': {dt.setMonth(dt.getMonth() + p_Number);break;}
		// day of year, days, weekdays
		case 'y': case 'd': case 'w': {dt.setDate(dt.getDate() + p_Number);break;}
		// week of year
		case 'ww': {dt.setDate(dt.getDate() + (p_Number*7));break;}
		// hour
		case 'h': {dt.setHours(dt.getHours() + p_Number);break;}
		// minutes
		case 'n': {dt.setMinutes(dt.getMinutes() + p_Number);break;}
		// seconds
		case 's': {dt.setSeconds(dt.getSeconds() + p_Number);break;}
		// milliseconds
		case 'ms': {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.getFullYear() - dt1.getFullYear();
	// var nMonths = dt2.getUTCMonth() - dt1.getUTCMonth() + (nYears!=0 ? nYears*12 : 0); /*strange: getUTCMonth returns the month before if the dateTime is within the first hour of a month (???), e.g. 11 if dateTime is 2007-01-01 00:59:59, but 0 if dateTime is 2007-01-01 01:00:00! getMonth() always returns the correct value*/
	var nMonths = dt2.getMonth() - dt1.getMonth() + (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 'yy': return dtPart.getFullYear().toString().substr(2,2);
		case 'q': return parseInt(dtPart.getMonth()/3)+1;
		case 'm': return dtPart.getMonth()+1;
		case 'mm': {m=dtPart.getMonth()+1;return m<10?'0'+m:m;break;}
		case 'y': return dateDiff('y', '1/1/' + dtPart.getFullYear(), dtPart);			// day of year
		case 'd': return dtPart.getDate();
		case 'dd': {d=dtPart.getDate();return d<10?'0'+d:d;break;}
		case 'w': return dtPart.getDay();	// weekday
		case 'ww': {w=dateDiff('ww', dateAdd('d',-datePart('w','1/1/'+dtPart.getFullYear()),'1/1/'+dtPart.getFullYear()), dtPart)+1;return w<=52?w:1;break;}		// week of year
		case 'h': return dtPart.getHours();
		case 'hh': {h=dtPart.getHours();return h<10?'0'+h:h;break;}
		case 'n': return dtPart.getMinutes();
		case 'nn': {n=dtPart.getMinutes();return n<10?'0'+n:n;break;}
		case 's': return dtPart.getSeconds();
		case 'ss': {s=dtPart.getSeconds();return s<10?'0'+s:s;break;}
		case 'ms','l':return dtPart.getMilliseconds();	// millisecond
		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;
}


// functions added by Mindlend AG
function isLeapYear(pYear_i) {
	if(((pYear_i%4)==0)&&(((pYear_i%100)!=0)||(((pYear_i%100)==0)&&((pYear_i%400)==0)))) return true;
	return false;
}
function getDaysInMonth(pDate_s) {
	var monDayArr=[31,28,31,30,31,30,31,31,30,31,30,31];
	if(pDate_s.getMonth()==1&&isLeapYear(pDate_s.getYear())) return 29;
	else return monDayArr[pDate_s.getMonth()];
}
function parseDate(pDate_s){
	var i,deli,deliPos,rposY,posM,posD,dummy;
	try{
		datArr=pDate_s.match(/\d+/g);
		deliPos=pDate_s.search(/\D+/g);
		deli=pDate_s.substr(deliPos,1);
		posY = datArr[2].length > 2 ? 2 : 0;
		if(posY==0&&deli=='.') posY=2;
		posM = deli=='/' && posY==2 && datArr[0]<=12 ? 0 : 1;
		if(posM==0) posD=1;
		else posD = posY==2 ? 0 : 2;
	}
	catch(dummy){return false;}
	if(datArr[posY].length==2)
		if(datArr[posY]<50) datArr[posY]='20'+datArr[posY];
		else datArr[posY]='19'+datArr[posY];
	return new Date(datArr[posY],datArr[posM]-1,datArr[posD],00,00,00,000);
}
function parseDateTime(pDate_s){
	var i,deli,deliPos,rposY,posM,posD,dummy;
	try{
		datArr=pDate_s.match(/\d+/g);
		deliPos=pDate_s.search(/\D+/g);
		deli=pDate_s.substr(deliPos,1);
		posY=datArr[2].length > 2 ? 2 : 0;
		posM=deli=='/' && posY==2 && datArr[0]<=12 ? 0 : 1;
		if(posM==0) posD=1;
		else posD = posY==2 ? 0 : 2;
		for(i=datArr.length;i<=6;i++)datArr.push(0);
	}catch(dummy){return false;}
	return new Date(datArr[posY],datArr[posM]-1,datArr[posD],datArr[3],datArr[4],datArr[5],datArr[6]);
}
function parseTime(pTime_s){
	var i,dummy;
	try{
		datArr=pTime_s.match(/\d+/g);
		for(i=datArr.length;i<=3;i++)datArr.push(0);
	}catch(dummy){return false;}
	return new Date(1970,01,01,datArr[0],datArr[1],datArr[2],datArr[3]);
}
function convertDate(pDate_d,pDateMask_s,pErrorMsg_s){
	var i,pattArr,deli,argDat,tmpVar,refDat,dummy,retVal;
	refDat=new Date(2000,01,01,00,00,00,000);
	argDat=pDate_d;
	try{pDate_d.getDate()}
	catch(dummy){
		pDate_d=parseDate(pDate_d);
		if(!pDate_d) {
			if(pErrorMsg_s.length > 0) alert(pErrorMsg_s);
			return argDat;
		}
	}
	try{
		retVal='';
		pattArr=pDateMask_s.match(/[ymd]+/g);
		deli=pDateMask_s.substr(pDateMask_s.search(/[^ymd]+/g),1);
		for(i=0;i<pattArr.length;i++){
			switch(pattArr[i].substr(0,1)){
				case 'y':{
					tmpVar=refDat.getYear()==100 ? pDate_d.getYear()+1900 : pDate_d.getYear();
					if(pattArr[i].length==2) tmpVar=tmpVar.substr(2,2);
					retVal=retVal.length>0 ? retVal+deli+tmpVar : retVal+tmpVar;
					break;
				}
				case 'm':{
					tmpVar=pDate_d.getMonth()+1;
					if(pattArr[i].length==2 && parseInt(tmpVar)<10) tmpVar='0'+tmpVar;
					retVal=retVal.length>0 ? retVal+deli+tmpVar : retVal+tmpVar;
					break;
				}
				case 'd':{
					tmpVar=pDate_d.getDate();
					if(pattArr[i].length==2 && parseInt(tmpVar)<10) tmpVar='0'+tmpVar;
					retVal=retVal.length>0 ? retVal+deli+tmpVar : retVal+tmpVar;
					break;
				}
			}
		}
	}
	catch(dummy){alert('Could not convert date.');return argDat;}
	return retVal;
}
function dateFormat(pDate_d,pMask_s){
	if(!isDate(pDate_d)){return 'invalid date: \''+pDate_d+'\'';}
	var retVal=pMask_s;
	var patArr=['yyyy','yy','y','q','mm','m','dd','d','ww','w','hh','h','nn','n','ss','ms','s','l'];
	for(var i=0;i<patArr.length;i++) retVal=retVal.replace(new RegExp(patArr[i],'gi'), datePart(patArr[i],pDate_d));
	return retVal;
}


// ====================================
// 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);}
function IsLeapYear(pYear_i){return isLeapYear(pYear_i);}
function GetDaysInMonth(pDate_s){return getDaysInMonth(pDate_s);}
function ParseDate(pDate_s){return parseDate(pDate_s);}
function ParseDateTime(pDate_s){return parseDateTime(pDate_s);}
function ParseTime(pTime_s){return parseTime(pTime_s);}
function ConvertDate(pDate_d,pDateMask_s,pErrorMsg_s){return convertDate(pDate_d,pDateMask_s,pErrorMsg_s);}
function DateFormat(pDate_d,pMask_s){return dateFormat(pDate_d,pMask_s);}
