/**
 * @author	Walter Wimberly
 * @copyright	2007
 * @version	.9
 */

/**
 * @constructor
 * @param {Date} date
 * @classDescription	This class is designed to make it easier to format the date 
 * for placing it into a web page.  This allows for standard MS and PHP formatting techniques
 * of the Date object, without having to know Javascript in detail to get those values.
 * @class	This class is designed to make it easier to format the date 
 * for placing it into a web page.  This allows for standard MS and PHP formatting techniques
 * of the Date object, without having to know Javascript in detail to get those values.
 */
function DateFormater(date) {
	/**
	 * Internal JS Date object to store the date for later retrevial.
	 * @type	JSDate
	 */
	this.date = date ? date : new Date();
	
	/**
	 * Private data type to be used when building the date format.
	 * @type	Array
	 */
	this.arrPos = new Array();
}

DateFormater.prototype = {
	/**
	 * Set the date of the Object with a new JS Date object
	 * @method
	 * @param {Date} newDate
	 */
	setDateJS: function(newDate) {
		this.date = newDate;
	},
	/**
	 * Set the date of the Object by passing in numeric values for the mont, day, and year
	 * 
	 * @method
	 * @param {Number} month
	 * @param {Number} day
	 * @param {Number} year
	 */
	setDateElements: function(month, day, year) {
		if(month) {
			this.date.setMonth(month);
		}
		if(day) {
			this.date.setDate(day);
		}
		if(year) {
			this.date.setFullYear(year);
		}
	},
	
	/**
	 * Essentially a huge switch statement that takes the switching key that is given, 
	 * and spits out the value to be derived from that key.  If there is not a match
	 * that which is passed in, is returned.  If what is passed in is an NA - the nothing
	 * is returned. 
	 * 
	 * @private
	 * @method
	 * @param	{String} format
	 * @return	Returns the part of the date requested as a string.
	 * @type	String
	 */
	getDatePart: function(format) {
		var val = '';
		
		switch(format) {
			// Not Supported
			case 'NA':
				// this isn't supported yet so do nothing.
				break;
			
			////////////////////////////
			// Year Information
			////////////////////////////
			case 'Y':
				val = this.date.getFullYear();			
				break;
			case 'y':
				val = this.date.getYear();
				if(val > 100) {
					val -= 100;
				}
				val = this.addLeadingZero(val);	
				break;
			
			////////////////////////////
			// Month Information
			////////////////////////////
			case 'm':
				// month number with leading zeros
				val = this.date.getMonth() + 1;
				val = this.addLeadingZero(val);		
				break;
			case 'n':
				// numeric month without leading zero
				val = this.date.getMonth() + 1;			
				break;
			case 'M':
				// short month name
				val = monthName[this.date.getMonth()].substr(0,3);			
				break;
			case 'F':
				// full month name
				val = monthName[this.date.getMonth()];			
				break;
				
			// Day Information
			case 'z':
				// what day in the year is this 1 - 366
				// not working as of yet
				// val = this.date.;			
				break;
			case 'w':
				// day of the week - 0-6
				val = this.date.getDay();			
				break;
			case 'l':
				// name of the day of the week
				val = dayName[this.date.getDay()];			
				break;
			case 'D':
				// 3 letter name of the day of the week
				val = dayName[this.date.getDay()].substr(0,3);			
				break;
			case 'j':
				// Day of the month without leading zeros
				val = this.date.getDate();			
				break;
			case 'd':
				// Day of the month, 2 digits with leading zeros
				val = this.date.getDate();
				val = this.addLeadingZero(val);			
				break;
			case 'q':
				// The numeric quarter of the year
				val = ((this.date.getMonth() + 1) % 4) + 1;		
				break;
			
			////////////////////////////
			// Time
			////////////////////////////
			case 'g':
				// 12-hour format of an hour without leading zeros
				val = this.get12Hour();	
				break;
			case 'G':
				// 24-hour format of an hour without leading zeros
				val = this.date.getHours();	
				break;
			case 'h':
				// 12-hour format of an hour with leading zeros
				val = this.get12Hour();
				val = this.addLeadingZero(val);		
				break;
			case 'H':
				// 24-hour format of an hour without leading zeros
				val = this.date.getHours();			
				val = addLeadingZero(val);
				break;
			case 'i':
				// get the minutes with leading zeros
				val = this.date.getMinutes();	
				val = this.addLeadingZero(val);
				break;
			case 's':
				// get the seconds with leading zeros
				val = this.date.getSeconds();	
				val = this.addLeadingZero(val);
				break;				
			case 'A':
				// AM or PM
				if(this.date.getHours() > 12) {
					val = "PM";
				} else {
					val = "AM"
				}	
				break;
			case 'a':
				// am or pm
				if(this.date.getHours() > 12) {
					val = "pm";
				} else {
					val = "am"
				}	
				break;
			case 'P':
				// AM or PM
				if(this.date.getHours() > 12) {
					val = "P";
				} else {
					val = "A"
				}	
				break;
			case 'p':
				// am or pm
				if(this.date.getHours() > 12) {
					val = "p";
				} else {
					val = "a"
				}	
				break;
				
			default:
				val = format;			
		}
		
		return val;
	},
	
	/**
	 * Check to see if a leading zero (0) needs to be added to this number.
	 * 
	 * @method
	 * @param	{Number} val
	 * @return	Returns the value passed with a leading zero if the number was less than 10.
	 * @type	String
	 */
	addLeadingZero: function(val) {
		if(val < 10) {
			val = '0' + val;
		}
		return val;	
	},
	
	/**
	 * Gets the 12 hour time from the 24 hour time, which is all that JS returns.
	 * 
	 * @method
	 * @return	Returns a 12 hour version of a 24 hour value
	 * @type	String
	 */
	get12Hour: function() {
		var val = this.date.getHours();		
		if(val > 12) {
			val %= 12;
		} else if( val == 0) {
			val = 12;
		}
		return val;	
	},
	
	/**
	 * A <strong>Private</strong> method that looks for the needle in the haystack.  Based upon what is found
	 * it will build and search array to determine what the equivilent PHP format string is, 
	 * if it is applicable.
	 * 
	 * @method
	 * @param {String} haystack
	 * @param {String} needle
	 */
	placeIt: function(haystack, needle) {
				
		var loc = 0;
			
		do { 
			loc = haystack.indexOf(needle[0], loc);
			if(loc != -1 ) {
				if (!this.arrPos[loc]) {
					this.arrPos[loc] = [needle[0], needle[1]];
				}
				loc += needle.length + 1;
			}
		} while(loc > -1 );

	},

	/**
	 * <p>Format the date based upon MS standard formatting techniques. We currently 
	 * support about 95% for the formatting that MS supports:</p>
	 * <ul>
	 * <li>General Date	== 4/3/93 05:34:00 PM.</li>
	 * <li>Long Date	== Saturday, April 3, 1993</li>
	 * <li>Medium Date	== 20-Jan-05</li>
	 * <li>Short Date	== 4/3/93</li>
	 * <li>Long Time	== 5:34:23 PM</li>
	 * <li>Medium Time	== 5:34 PM</li>
	 * <li>Short Time	== 17:34</li>
	 * </ul>
	 * <p>Individual date parts that you can pass:</p>
	 * <ul>
	 * <li>d Day of the month in one or two numeric digits, as needed (1 to 31).</li>
	 * <li>dd Day of the month in two numeric digits (01 to 31).</li>
	 * <li>ddd First three letters of the weekday (Sun to Sat).</li>
	 * <li>dddd Full name of the weekday (Sunday to Saturday).</li>
	 * <li>w Day of the week (1 to 7).</li>
	 * <li>ww Week of the year (1 to 53).</li>
	 * <li>m Month of the year in one or two numeric digits, as needed (1 to 12).</li>
	 * <li>mm Month of the year in two numeric digits (01 to 12).</li>
	 * <li>mmm First three letters of the month (Jan to Dec).</li>
	 * <li>mmmm Full name of the month (January to December).</li>
	 * <li>q Date displayed as the quarter of the year (1 to 4).</li>
	 * <li>y Number of the day of the year (1 to 366).</li>
	 * <li>yy Last two digits of the year (01 to 99).</li>
	 * <li>yyyy Full year (0100 to 9999).</li>
	 * <li>h Hour in one or two digits, as needed (0 to 23).</li>
	 * <li>hh Hour in two digits (00 to 23).</li>
	 * <li>n Minute in one or two digits, as needed (0 to 59).</li>
	 * <li>nn Minute in two digits (00 to 59).</li>
	 * <li>s Second in one or two digits, as needed (0 to 59).</li>
	 * <li>ss Second in two digits (00 to 59).</li>
	 * <li>AM/PM Twelve-hour clock with the uppercase letters "AM" or "PM", as appropriate.</li>
	 * <li>am/pm Twelve-hour clock with the lowercase letters "am" or "pm", as appropriate.</li>
	 * <li>A/P Twelve-hour clock with the uppercase letter "A" or "P", as appropriate.</li>
	 * <li>a/p Twelve-hour clock with the lowercase letter "a" or "p", as appropriate.</li>
	 * </ul>
	 * <p>THESE we have added</p>
	 * <ul>
	 * <li>z Hour in one or two digits, as needed (0 to 12)</li>
	 * </ul>
	 * 
	 * @method
	 * @param	{String} formatString
	 * @return	Returns a String formated date using the MS style formatting rules 
	 * @type	String
	 */
	customFormatMSStyle: function(formater) {
		var leaving = '';
		this.arrPos = new Array();
		
		if(!formater) {
			// if nothing is passed, make it format as a general date type
			formatString = 'general date';
		} else {
			// make sure the format passed in is all lower case to eliminate 
			// any case sensitivity issues that might arise.
			formatString = formater.toLowerCase();
		}
		
		// check to see if it came in as a MS Predertmined String
		if(formatString == "general date") {
			formatString = "m/d/yy";
		} else if(formatString == "long date") {
			formatString = "dddd, mmmm d, yyyy";
		} else if(formatString == "medium date") {
			formatString = "dd-mmm-yy";
		} else if(formatString == "short date") {
			formatString = "m/d/yy";
		} else if(formatString == "long time") {
			formatString = "z:nn:ss AM";
		} else if(formatString == "medium time") {
			formatString = "z:nn AM";
		} else if(formatString == "short time") {
			formatString = "h:nn";
		} 
		
		
		for(var k = 0; k < this.MSFormatting.length; k++) {
			this.placeIt(formatString, this.MSFormatting[k])
		}
		
		for(var i = 0; i<this.arrPos.length; i++)  {
			if(this.arrPos[i]) {
				leaving += this.getDatePart(this.arrPos[i][1]);
				i+= this.arrPos[i][0].length - 1;
			} else {
				leaving += formatString.substr(i,1);
			}
		}
		leaving += formatString.substr(i);
			
		return leaving;
	},
	
	/**
	 * Format the date based upon PHP style of date formatting. We currently support 
	 * about 85% of the formatting techniques that PHP supports.
	 * 
	 * @method
	 * @param	{String} formatString
	 * @return	Returns the formated string of the JavaScript date object, using PHP 
	 * style formatting
	 * @type	String
	 */
	customFormatPHPStyle: function(formatString) {
		var output = '';
		
		for(var i=0; i<formatString.length; i++) {
				output += this.getDatePart(formatString.subStr(i,1));		
		}
		
		return output;
	},
	
	/**
	 * Returns	A string to determine if it is in the morning, the afternoon, or the evening
	 * 
	 * @method
	 * @return	A string to determine if it is in the morning, the afternoon, or the evening
	 * @type	String
	 */
	getMornAfterEven: function() {
		var str = '';
		if(this.date.getHours() < 13 ) {
			str = 'Morning';
		} else if(this.date.getHours() < 18){
			str = 'Afternoon';
		} else {
			str = 'Evening';
		}
		return str;
	},
	
	/**
	 * Converstion array to convert MS date formatting strings into PHP which as 
	 * single characters is easier to work with.
	 * @type	Array
	 */ 
	MSFormatting: [
		['yyyy', 'Y'], ['yy', 'y'],
		['y', 'NA'],
		['dddd', 'l'] , ['ddd', 'D'], ['dd', 'd'], ['d', 'j'],
		['ww', 'NA'], ['w', ''],
		['mmmm', 'F'], ['mmm', 'M'], ['mm', 'm'], ['m', 'n'],
		['q','q'],
		['h','G'], ['hh','H'], 
		['n','NA'], ['nn','i'],
		['s','NA'], ['ss','s'],
		['AM','A'], ['am','a'],
		['A','P'], ['a','p'],
		['z', 'g']
	]
}

// create a default object for others to use
var dateFormater = new DateFormater();