/**
 * @projectDescription	This library contains useful extensions to MooTools release 1.11/1.2
 * 
 * @author 	Den Odell dennis.odell@akqa.com
 */

String.extend({
	/**
	 * Formats a string in order with a series of arguments
	 * 
	 * Example:
	 * 'My favourite pets are {0} and {1}.'.format('dogs', 'cats')
	 * ==> 'My favourite pets are dogs and cats.'
	 * 
	 * @alias String.format
	 * @method
	 * @memberOf String
	 * @param (String) The unformatted string to be formatted
	 * @param (Array) Array of values to substitute into unformatted string in order
	 * @return (String) Returns a formatted string similar to C#'s String.Format() function
	 */
	format: function() {
		var args = ($A(this.format.arguments));
		var string = this.toString();
		args.each(function(argument, i) {
			string = string.replace(new RegExp('\\{' + i + '\\}', 'g'), argument);
		});
		return string;
	}
});

Document.extend({
	/**
	 * @classDescription	Management class for <script> references, allowing dynamic addition of scripts to the page
	 * @alias Document.Scripts
	 */
	Scripts: new Hash({
		/**
		 * Add a new <script> tag to the page
		 * 
		 * @method
		 * @alias Document.Scripts.add
		 * @param {String} componentUrl	The location of the script source file
		 * @param {Object} properties	Correlates directly to MooTools 'properties' for Asset.javascript call
		 */
		add: function(componentUrl, properties) {
			//alert("Adding script:" + componentUrl + " props:" + properties);
			if (!this.preExists(componentUrl)) {
				new Asset.javascript(componentUrl, properties);
			}
		},
		
		/**
		 * Returns a reference to the <script> tag that contains 'componentUrl' in its 'src' attribute
		 * Returns null if no <script> tag found
		 * 
		 * @method
		 * @alias Document.Scripts.find
		 * @param {String} componentUrl
		 * @return (Object) script reference
		 */
		find: function(componentUrl) {
			var returnValue = null;
			$ES('script').each(function(script) {
				if (script.src.contains(componentUrl)) {
					returnValue = script;
				}
			});
			return returnValue;
		},
		
		/**
		 * Determines if a <script> tag of particular 'src' attributes is already loaded
		 * 
		 * @method
		 * @alias Document.Scripts.preExists
		 * @param {String} componentUrl
		 * @return (Bool) 
		 */
		preExists: function(componentUrl) {
			return (this.find(componentUrl) ? true : false)
		},
		
		/**
		 * Returns a comma-separated list of all <script> tags loaded on the current page
		 * 
		 * @method
		 * @alias Document.Scripts.list
		 * @return (String) Comma-separated list of <script> tags loaded on current page
		 */
		list: function() {
			var scriptSrc = new Array();
			$ES('script').each(function(script) {
				scriptSrc.include(script.src);
			});
			return scriptSrc.join(', ');
		}
	})
});
	
Document.extend({
	/**
	 * Adds support for alpha-transparent PNG images to Internet Explorer 6 browser only
	 * 
	 * @alias Document.supportTransparentPNGs
 	 * @method	 
 	 */
	supportTransparentPNGs: function() {
		if (window.ie6) {
			$$('*').each(function(el){
				if (el.tagName.toUpperCase() != 'OBJECT') {
					var imgURL = el.getStyle('background-image');
					var imgURLLength = imgURL.length;
					if (imgURL != 'none' && imgURL.substring(imgURLLength - 5, imgURLLength - 2) == 'png' && imgURL.toLowerCase().contains('transparent')) {
						el.setStyles({
							background: '',
							filter: "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', sizingMethod='crop', src='" + imgURL.substring(5, imgURLLength - 2) + "')"
						});
					};
					
					if ((el.getTag() == 'img') && (el.getProperty('src').substring(el.getProperty('src').length - 3) == 'png')) {
						var imgReplacer = new Element('input', {
							'styles': {
								'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', sizingMethod='crop', src='" + el.getProperty('src') + "')",
								'position': 'relative',
								'background': 'transparent'
							},
							'title': el.getProperty('alt')
						});
						
						imgReplacer.setStyles(el.getStyles('padding', 'margin', 'border', 'height', 'width'));
						imgReplacer.setProperties(el.getProperties('id', 'class'));
						imgReplacer.disabled = true;
						el.replaceWith(imgReplacer);
					}
				}
			});
		}
	},
	
	/**
	 * Adds the CSS class 'safari2' to the <html> tag for the Safari 2 browser. Allows CSS specific to Safari 2 to be written.
	 * 
	 * CSS Example:
	 * .safari2 p {color:green;}
	 * => All paragraph tags in Safari 2 browser only will have a text colour of green
	 * 
	 * @method
	 * @alias Document.addSafariCSSClass
	 */
	addSafariCSSClass: function() {
		if (window.webkit419) {
			document.getElementsByTagName('html')[0].className += ' ' + 'safari2';
		}
	}() // initialises itself
});

Date.implement({
	/**
	 * Compares two dates
	 * 
	 * Example:
	 * new Date().matches(new Date())
	 * ==> true
	 * 
	 * @alias Date.matches
	 * @method
	 * @param {Date} dateToCompare
	 * @return (Bool) Returns true if dateToCompare matches this date, otherwise false
	 */
	matches: function(dateToCompare) {
		return ((this.getDate() == dateToCompare.getDate()) && (this.getMonth() == dateToCompare.getMonth()) && (this.getFullYear() == dateToCompare.getFullYear()));
	},
	
	/**
	 * Duplicates a date object without keeping reference to the original object
	 * 
	 * Example:
	 * var date1 = new Date();
	 * var date2 = date1.duplicate();
	 * ==> date1 and date2 are completely separate objects (notice the difference from 'var date2 = date1;')
	 * 
	 * @alias Date.duplicate
	 * @method
	 * @return (Date) Duplicate of date object passed in
	 */
	duplicate: function() {
		var returnDate = new Date();
		returnDate.setTime(this.valueOf());
		
		return returnDate;
	},
	
	/**
	 * Increments a date object by a specified number of months
	 * 
	 * Example:
	 * var newDate = new Date().incrementMonth(1);
	 * ==> newDate is now the 1st of next month
	 * 
	 * @alias Date.incrementMonth
	 * @method
	 * @param {Int} incrementBy
	 * @return (Date) Duplicate of passed in date with month incremented by one. Note the date is always the first of the month
	 */
	incrementMonth: function(incrementBy) {
		
		// If no argument is passed in we force function to increment by one month
		if(!incrementBy){
			incrementBy = 1;
		}
				
		var returnDate = this.duplicate();
		returnDate.setDate(1);
		incrementBy = returnDate.getMonth() + incrementBy;
		if (incrementBy < 0) {
			incrementBy += 12;
			returnDate.setFullYear(returnDate.getFullYear() - 1);
		} else if (incrementBy > 11) {
			incrementBy -= 12;
			returnDate.setFullYear(returnDate.getFullYear() + 1);
		}		
		returnDate.setMonth(incrementBy);
				
		return returnDate;
	},
	
	getMonthSquareStartDate: function() {
		var startDate = this.duplicate();
		startDate.setDate(1);
		// get day of first of month as an integer. then subtract from 1st of month to get sunday's date
		startDate.setDate(1 - startDate.getDay());
		
		return startDate;
	},
	
	getMonthSquareEndDate: function() {
		
		var endDate = this.duplicate();
		endDate.setDate(1);
		
		endDate = endDate.incrementMonth(1);
		
		// end date of passed in month
		endDate.setDate(endDate.getDate() - 1);
		
		// look forward to last day of month square
		var numberOfDaysToEndOfWeek = 6 - endDate.getDay();
		
		// Add the days to the endate
		endDate.setDate(endDate.getDate() + numberOfDaysToEndOfWeek);

		return endDate;
	},
	
	getNumberOfWeeksUntil: function(endDate) {

		// CONSTANTS: Millisecond values for day, week and minute 
		var MILLISECONDSINADAY = 86400000;
		var MILLISECONDSINAWEEK = 604800000;
		var MILLISECONDSINANMINUTE = 60000;
		
		// Duplicate dates to prevent unwanted side effects
		var startOfRange = this.duplicate();
		var endOfRange = endDate.duplicate();
		
		/* Create offset values to take into fact the potential for differing timezones/seasonal differences.
		 * As getTimezoneOffset returns a minute value, we are converting it into Milliseconds
		 */
		var startOfRangeOffsetInMilliseconds = startOfRange.getTimezoneOffset() * MILLISECONDSINANMINUTE;
		var endOfRangeOffsetInMilliseconds = endOfRange.getTimezoneOffset() * MILLISECONDSINANMINUTE;
		
		// Calculate number of weeks by subtracting start of range in milliseconds from end of range minus offests and divide by milliseconds in a week 
		var numberOfWeeksInRange = (((endOfRange.getTime() - endOfRangeOffsetInMilliseconds) - (startOfRange.getTime() - startOfRangeOffsetInMilliseconds)) / MILLISECONDSINAWEEK);
				
		return numberOfWeeksInRange;

	}
})

window.addEvent('load', function() {
	Document.supportTransparentPNGs();
})


