// Straightforward/simple Observer pattern implementation
// Example useage:
// var publisher = new Observer
// publisher.subscribe(function(msg){
//	alert(msg);
// });
// publisher.fire("Event fired!");
function Observer() {
    this.fns = [];
}

Observer.prototype = {
    subscribe : function(fn) {
        this.fns.push(fn);
    },
    unsubscribe : function(fn) {
        this.fns = this.fns.filter(
            function(el) {
                if (el !== fn) {
                    return el;
                }
            }
        );
    },
    fire : function(o, thisObj) {
        var scope = thisObj || window;
        this.fns.forEach(
            function(el) {
                el.call(scope, o);
            }
        );
    }
};

// Add some sugar to the Array prototype
Array.prototype.forEach = function(fn, thisObj) {
    var scope = thisObj || window;
    for ( var i=0, j=this.length; i < j; ++i ) {
        fn.call(scope, this[i], i, this);
    }
};

Array.prototype.filter = function(fn, thisObj) {
    var scope = thisObj || window;
    var a = [];
    for ( var i=0, j=this.length; i < j; ++i ) {
        if ( !fn.call(scope, this[i], i, this) ) {
            continue;
        }
        a.push(this[i]);
    }
    return a;
};

// create asset loader function
if (typeof Asset != "undefined") {
    var assets = [];
    /**
     * A method for loading JS dependencies at runtime.<br/>
     * A given script will only be loaded once.
     * 
     * @param {String} jsPath : static path to the script, e.g. leading slash
     * @return {Boolean} indicates whether script was loaded
     */
    var $import = function(jsPath) {
        if (assets.indexOf(jsPath) == -1) {
            assets.push(jsPath);
            new Asset.javascript(jsPath, {});
            return true;
        }
        return false;
    }
} else {
    /**
     * A method for loading JS dependencies at runtime.
     * Empty due to missing mootools.js dependency
     */
    $import = function(){return false};
}

/**
 * HomeAway namespace
 */
var ha = {
    /**
     * Page specific fields and methods
     */
    pages: {},
    
    /**
     * Utility methods
     */
    util: {
        /**
         * Method for performance timing <br/><br/>
         * <b>Usage:<b> <br/><br/>
         * ha.util.timer("mytimer"); <br/>
         * (...do things...) <br/>
         * ha.util.timer("mytimer");
         * 
         * @param {String} name
         * @depends firebug
         */        
        timer: function(name) {
            if (typeof ha.util.timers[name] == "undefined") {
                // create timer
                ha.util.timers[name] = (new Date()).getTime();
            } else {
                // output elapsed time
                console.log("@@" + name + ": " + (ha.util.timers[name] - (new Date()).getTime()) + "ms");
            }
        },
        timers: {}
        
    },
    
    /**
     * Methods and fields to support UI widgets
     */
    widget: {},
    
    /**
     * An object that contains data passed in from jsp
     */
    settings: {},
    
    strings: {},
    
    /**
     * Tests that 
     */
    tests: {
        
        /**
         * Test that browser handles setMonth with (argument < 0) properly
         */
        shiftMonth: function() {
            var date1 = new Date(Date.UTC(2005,0,5));
            var date2 = new Date(Date.UTC(2004,9,5));
            var shift = -3;
            date1.setUTCMonth(parseInt(date1.getUTCMonth()) + shift);
            return (date1.toString() !== date2.toString()) ? false : true;
        }
        
    }
    
};

$import("/resources/10071/js/product.js")

// load dependencies
$import("/resources/10071/js/datePicker.js");
// Extend native data types where needed

/**
 * Convert number to string with leading zeroes
 * @param {Int} num : digits desired
 * @return {String}
 */
Number.prototype.toLeadZero = function(num){
    var arr = String(this).split(".");
    var neg = (arr[0].indexOf("-") == -1) ? "" : "-";
    var str = arr[0].replace("-", "");
    var dec = (arr.length > 1 && arr[1] != "") ? "."+arr[1] : "";
    for (i = num - str.length; i > 0; i--) {
        str = "0" + str;
    }
    //console.log(this + ", " + num + ": ", neg + str + dec);
    return (neg + str + dec);
};

/**
 * Returns a copy of the current date object
 * @return {Date}
 */
Date.prototype.copy = function(){
    return (new Date(this.getUTCFullYear(), this.getUTCMonth(), this.getUTCDate()));
};

/**
 * A method to shift date objects by month
 * date.setMonth fails in Safari when passed arguments out of range
 * detect this issue and define setUTCMonth method once, at runtime
 * @param {Int} num
 * @return null
 */
Date.prototype.shiftUTCMonth = function(num){};
	if (ha.tests.shiftMonth() === true) {
		Date.prototype.shiftUTCMonth = Date.prototype.setUTCMonth;
	} else {
		Date.prototype.shiftUTCMonth = function(num){
			if (!num) {return false;}
			var mo = this.getUTCMonth();
			// target outside of current year?
			if (num < 0) {
				this.setUTCMonth(num + 12);
            	this.setUTCFullYear(this.getUTCFullYear() + Math.floor(num / 12));
			} else if (n > 11) {
				this.setUTCMonth(num - 12);
				this.setUTCFullYear(this.getUTCFullYear() + Math.floor(num / 12));
			} else {
				this.setUTCMonth(num);
		}
		return null;
    };
}

/* business requirement to have markup up high but display down low */
function showSeoText() {
	// check if the elements exist before calling them - the no search results page and some decorates
	// do not for instance
	if (document.getElementById('searchText') && document.getElementById('searchTextPosition')) {
		var content = document.getElementById('searchText').innerHTML;
		document.getElementById('searchTextPosition').innerHTML = content;
	}
}

/**
 * Cookie plugin
 *
 * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Create a cookie with the given name and value and other optional parameters.
 *
 * @example $.cookie('the_cookie', 'the_value');
 * @desc Set the value of a cookie.
 * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
 * @desc Create a cookie with all available options.
 * @example $.cookie('the_cookie', 'the_value');
 * @desc Create a session cookie.
 * @example $.cookie('the_cookie', null);
 * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
 *       used when the cookie was set.
 *
 * @param String name The name of the cookie.
 * @param String value The value of the cookie.
 * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
 * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
 *                             If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
 *                             If set to null or omitted, the cookie will be a session cookie and will not be retained
 *                             when the the browser exits.
 * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
 * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
 * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
 *                        require a secure protocol (like HTTPS).
 * @type undefined
 *
 * @name $.cookie
 * @cat Plugins/Cookie
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */

/**
 * Get the value of a cookie with the given name.
 *
 * @example $.cookie('the_cookie');
 * @desc Get the value of a cookie.
 *
 * @param String name The name of the cookie.
 * @return The value of the cookie.
 * @type String
 *
 * @name $.cookie
 * @cat Plugins/Cookie
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */
jQuery.cookie = function(name, value, options) {
    if (typeof value != 'undefined') { // name and value given, set cookie
        options = options || {};
        if (value === null) {
            value = '';
            options.expires = -1;
        }
        var expires = '';
        if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
            var date;
            if (typeof options.expires == 'number') {
                date = new Date();
                date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
            } else {
                date = options.expires;
            }
            expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
        }
        // CAUTION: Needed to parenthesize options.path and options.domain
        // in the following expressions, otherwise they evaluate to undefined
        // in the packed version for some reason...
        var path = options.path ? '; path=' + (options.path) : '';
        var domain = options.domain ? '; domain=' + (options.domain) : '';
        var secure = options.secure ? '; secure' : '';
        var cookie_string = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
        document.cookie = cookie_string
    } else { // only name given, get cookie
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
};

/**         
* Creates an iframe "mask" behind an element in IE.  Non-IE returns the node argument unchanged.         
* This solves a problem with menus in IE showing or clicking through div layers.        
* Parent of the node must be positioned absolute or relative.        
*/       
function rollover(node) { 
	if (window.ie6) {		
		node.className='hover';
 		ieMask(node.getElementsByTagName('ul')[0]);
	}
}

function rolloff(node) { 
	if (window.ie6) {		
		node.className='';
		var iframe = $j("iframe.maskFrame", node);
		if (iframe) {
			$j("body").append(iframe);
		}
	}
}

function ieMask(node) {           
	 if (window.ie6) {
       node = $(node);
		if(!node) return;
       var parent = $(node.parentNode);
       var z = node.getStyle("z-index").toInt();
       var mask = parent.getElement(".maskFrame") || new Element("iframe", {
           "class": "maskFrame",
           "scrolling": "no",
           "border": 0,
           "src": "javascript:void(0)"
       });
       mask.injectAfter(node);
       mask.setStyles({
               "display": "",
               "left": node.offsetLeft,
               "top": node.offsetTop,
               "width": node.offsetWidth,
               "height": node.offsetHeight, 
              "z-index": ($type(z) == "number") ? z - 1 : 0,
               "filter": "progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)"
       });
   }
   return this;
}

 /**
  * An inline setInterval method calls this function after the element obj's are created.
  * This function sets datePickControl.linkDates when the obj is ready and clears the timer.
  * The dpCnt incremental safeguards against an infinite loop.
  */
var dpCnt = 0;
function setDatePicker(arriveDate,departDate){
	if (typeof ha.widget.datePickControl != 'undefined')
	{
		ha.widget.datePickControl.linkDates(arriveDate, departDate);
		dpInt = window.clearInterval(dpInt);
		dpCnt++;
	}
	else if (dpCnt == 10)
	{
		dpInt = window.clearInterval(dpInt);
	}
}

function isInt(c)  { return((c>="0")&&(c<="9")) }

//handles: advancedSearchForm, homeSearchForm, keywordSearchForm, refineSearchForm (aka sidebar)
ha.util.searchForm = {
    init: function(){
    	$j('span.search-submit-lnk').show();
        $j('input.search-submit-btn').hide();
        
        $j('#searchKeywords').keyup(function(e){
        	if(e.which == 13) {
        		ha.util.searchForm.submit(e);
        	}
        });
        
    	$j('form[name=searchForm],form[name=refineSearchForm]').each(function(){
    		$j(this).submit(function(e){
    			e = new Event(e);
    			e.stop();
    		});
    		
    		$j('.search-submit-lnk', $j(this)).click(function(e){
    			ha.util.searchForm.submit(e);
    		});
    	});
    },
    
    submit: function(e){
    	var target = new Event(e).target;
    	var formObj = $j(target).parents('form');
    	//var formId = $j(e.target).parents('form').map(function(){ return this.id; }).get();

    	// determine what sort of search has been performed
    	var searchType = formObj.attr("id");
    	if(searchType == "homeSearchform")
    		searchType = "simple";
    	else if(searchType == "keywordSearchForm")
    		searchType = "keyword";
    	else if(searchType == "advancedSearchForm")
    		searchType = "advanced";
    	else if(searchType == "refineSearchform")
    		searchType = "availability";
    	else
    		searchType = "notknown";
    		
		$j.cookie('searchType', searchType, {expires: 1, path: '/'});	

    	formObj = formObj.map(function(){ return this; }).get();

    	if(ha.util.searchForm.validate($j('#startDateInput',formObj).val(), $j('#endDateInput',formObj).val())){ 
    		// get keywords
        	var keywords = ($j("input[@name=keywords]", formObj).val() != null && $j.trim($j("input[@name=keywords]", formObj).val()) != '') ? '/keywords:' + escape($j("input[@name=keywords]", formObj).val()) : '';

        	var refinements = "";
        	if ($j("#refinements",formObj).val() != null && $j.trim($j("#refinements",formObj).val()) != ''){
        		// get refineSearchForm refinements aka sidebar
        		refinements += $j("#refinements",formObj).val();
        	}
        	else{ // get advancedSearchForm refinements
        		var refinements = "";
        		$j('input, select',formObj).each(function(i,el){
        			if ((el.type == "select-one" && el.value != '') || (el.type == "checkbox" && el.checked)){
        				refinements += '/' + el.value;
        			}
        		});
        	}
        	
        	var url = '/search';
	    	if (refinements != ''){ url += '/refined'; }
        		url += keywords;
    			url += refinements;
    			url += ha.util.searchForm.dateParam($j('#startDateInput', formObj),'arrival');
    			url += ha.util.searchForm.dateParam($j('#endDateInput', formObj),'departure');
    			
    		window.location = url;
    	}
    },
    
    validate: function(startDate, endDate){
    	var dateFormat = ha.settings.brandDateFormat;
    	var startMonth,startDay,startYear,endMonth,endDay,endYear,startDim,endDim;
    	var hasStartDate = (startDate!=undefined && startDate!="" && startDate!=dateFormat);
    	var hasEndDate = (endDate!=undefined && endDate!="" && endDate!=dateFormat);

    	var errorSearch = ha.strings.advancedSearchError;
    	var errorMissing = ha.strings.bothDatesRequiredMessage;
    	
    	if((hasStartDate && !hasEndDate) || (hasEndDate && !hasStartDate)){
    		alert(errorMissing);
    		return false;
    	} 
    	else if (hasStartDate && hasEndDate){
			startDate = ha.util.searchForm.delim(startDate).split("/");
			endDate = ha.util.searchForm.delim(endDate).split("/");
			
			if (startDate.length != 3 || endDate.length != 3){
				alert(errorSearch);		
				return false;
			} 
			else if (startDate.length == 3 && endDate.length == 3){
				var i,j;
				// validate if date objects are integers
				for (i = 0; i< 3; i++){
					for (j = 0; j<startDate[i].length; j++){
						if (!isInt(startDate[i].charAt(j))){
							alert(errorSearch);	
							return false; break;
						}
					}
					for (j = 0; j<endDate[i].length; j++){
						if (!isInt(endDate[i].charAt(j))){
							alert(errorSearch);	
							return false; break;
						}
					}
				}
				
				if (dateFormat == 'mm/dd/yyyy'){
					startMonth = startDate[0];
					startDay = startDate[1];
					endMonth = endDate[0];
					endDay = endDate[1];
				}
				else {
					startMonth = startDate[1];
					startDay = startDate[0];
					endMonth = endDate[1];
					endDay = endDate[0];
				}
			
				startYear = (startDate[2].length == 4) ? startDate[2] : parseInt('20'+startDate[2]);
				endYear = (endDate[2].length == 4) ? endDate[2] : parseInt('20'+endDate[2]);

				startDim = ha.util.searchForm.dim(startMonth,startYear);
				endDim = ha.util.searchForm.dim(endMonth,startYear);
				
				var start = new Date();
				var end = new Date();
				start.setFullYear(startYear, startMonth-1, startDay);
				end.setFullYear(endYear, endMonth-1, endDay);
				
				// validate date continuity, past dates, and
				// date day does not exceed number of days in the month
				var today = new Date(); 
				if(end<start || start<today || end<today || startDim < startDay || endDim < endDay){
					alert(errorSearch);
					return false;
				}
			}
    	}
    	return true;
    },
    
    // return a formatted url param for a given search date string
    dateParam: function(o,s){
    	if ((typeof $j(o).val() == "undefined") || (ha.util.searchForm.delim($j(o).val()) == "")){
    		return "";
    	}
    	else if ($j(o).val() != ha.settings.brandDateFormat){
    		if (ha.settings.brandDateFormat == 'mm/dd/yyyy'){
    			var parts = $j(o).val().split("/")
    			return '/' + s + ':' + parts[2] + '-' + parts[0] + '-' + parts[1];
    		}
    		return '/' + s + ':' + $j(o).val().split("/").reverse().join("-");
    	}
    	return "";
    },

    // set the date string delimiters
    delim: function(s){
		if(s.indexOf("/") == -1){
			if(s.indexOf("-") > -1) s = s.replace(/-/g, "/");
			else if(s.indexOf(".") > -1) s = s.replace(/\./g, "/");
			else s = "";
		}
		return s;
    },
    
    // return the number of days in a given month
    dim: function(m,y){
    	var dim = new Array(12);
    	dim[0] = 31;
    	if((y % 4 == 0) && ((!(y % 100 == 0)) || (y % 400 == 0)))
    		dim[1] = 29;
    	else
    		dim[1] = 28;
    	dim[2] = 31;
    	dim[3] = 30;
    	dim[4] = 31;
    	dim[5] = 30;
    	dim[6] = 31;
    	dim[7] = 31;
    	dim[8] = 30;
    	dim[9] = 31;
    	dim[10] = 30;
    	dim[11] = 31;
    	return dim[m-1];
    }
};

//sitewide onDomReady event
$j(document).ready(function(){
	ha.util.searchForm.init();
	// load iframe ads
	$j("iframe[@rel]").each(function(){
		$j(this).attr("src", $j(this).attr("rel"));
	});
});

//clear search type cookie
$j.cookie('searchType', null, {path: '/'});
