// Shortcuts
var Dom = YAHOO.util.Dom,
    Event = YAHOO.util.Event,
    Element = YAHOO.util.Element,
    Selector = YAHOO.util.Selector,
    Get = YAHOO.util.Get,
    Connect = YAHOO.util.Connect,
    Anim = YAHOO.util.Anim,
    JSON = YAHOO.lang.JSON,
    Panel = YAHOO.widget.Panel,
    Dialog = YAHOO.widget.Dialog;

/***** Number Methods *****/
/*
 * Copyright (C) 2006 Baron Schwartz <baron at sequent dot org>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation, version 2.1.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
 * details.
 *
 * $Revision: 1.1 $
 */

// Abbreviations: LODP = Left Of Decimal Point, RODP = Right Of Decimal Point
Number.formatFunctions = {count:0};

Number.prototype.numberFormat = function(format, context) {
    if (isNaN(this) || this == +Infinity || this == -Infinity) {
        return this.toString();
    }
    if (Number.formatFunctions[format] == null) {
        Number.createNewFormat(format);
    }
    return this[Number.formatFunctions[format]](context);
}

Number.createNewFormat = function(format) {
    var funcName = "format" + Number.formatFunctions.count++;
    Number.formatFunctions[format] = funcName;
    var code = "Number.prototype." + funcName + " = function(context){\n";

    // Decide whether the function is a terminal or a pos/neg/zero function
    var formats = format.split(";");
    switch (formats.length) {
        case 1:
            code += Number.createTerminalFormat(format);
            break;
        case 2:
            code += "return (this < 0) ? this.numberFormat(\""
                + String.escape(formats[1])
                + "\", 1) : this.numberFormat(\""
                + String.escape(formats[0])
                + "\", 2);";
            break;
        case 3:
            code += "return (this < 0) ? this.numberFormat(\""
                + String.escape(formats[1])
                + "\", 1) : ((this == 0) ? this.numberFormat(\""
                + String.escape(formats[2])
                + "\", 2) : this.numberFormat(\""
                + String.escape(formats[0])
                + "\", 3));";
            break;
        default:
            code += "throw 'Too many semicolons in format string';";
            break;
    }
    eval(code + "}");
}

Number.createTerminalFormat = function(format) {
    // If there is no work to do, just return the literal value
    if (format.length > 0 && format.search(/[0#?]/) == -1) {
        return "return '" + String.escape(format) + "';\n";
    }
    // Negative values are always displayed without a minus sign when section separators are used.
    var code = "var val = (context == null) ? new Number(this) : Math.abs(this);\n";
    var thousands = false;
    var lodp = format;
    var rodp = "";
    var ldigits = 0;
    var rdigits = 0;
    var scidigits = 0;
    var scishowsign = false;
    var sciletter = "";
    // Look for (and remove) scientific notation instructions, which can be anywhere
    m = format.match(/\..*(e)([+-]?)(0+)/i);
    if (m) {
        sciletter = m[1];
        scishowsign = (m[2] == "+");
        scidigits = m[3].length;
        format = format.replace(/(e)([+-]?)(0+)/i, "");
    }
    // Split around the decimal point
    var m = format.match(/^([^.]*)\.(.*)$/);
    if (m) {
        lodp = m[1].replace(/\./g, "");
        rodp = m[2].replace(/\./g, "");
    }
    // Look for %
    if (format.indexOf('%') >= 0) {
        code += "val *= 100;\n";
    }
    // Look for comma-scaling to the left of the decimal point
    m = lodp.match(/(,+)(?:$|[^0#?,])/);
    if (m) {
        code += "val /= " + Math.pow(1000, m[1].length) + "\n;";
    }
    // Look for comma-separators
    if (lodp.search(/[0#?],[0#?]/) >= 0) {
        thousands = true;
    }
    // Nuke any extraneous commas
    if ((m) || thousands) {
        lodp = lodp.replace(/,/g, "");
    }
    // Figure out how many digits to the l/r of the decimal place
    m = lodp.match(/0[0#?]*/);
    if (m) {
        ldigits = m[0].length;
    }
    m = rodp.match(/[0#?]*/);
    if (m) {
        rdigits = m[0].length;
    }
    // Scientific notation takes precedence over rounding etc
    if (scidigits > 0) {
        code += "var sci = Number.toScientific(val,"
            + ldigits + ", " + rdigits + ", " + scidigits + ", " + scishowsign + ");\n"
            + "var arr = [sci.l, sci.r];\n";
    }
    else {
        // If there is no decimal point, round to nearest integer, AWAY from zero
        if (format.indexOf('.') < 0) {
            code += "val = (val > 0) ? Math.ceil(val) : Math.floor(val);\n";
        }
        // Numbers are rounded to the correct number of digits to the right of the decimal
        code += "var arr = val.round(" + rdigits + ").toFixed(" + rdigits + ").split('.');\n";
        // There are at least "ldigits" digits to the left of the decimal, so add zeros if needed.
        code += "arr[0] = (val < 0 ? '-' : '') + String.leftPad((val < 0 ? arr[0].substring(1) : arr[0]), "
            + ldigits + ", '0');\n";
    }
    // Add thousands separators
    if (thousands) {
        code += "arr[0] = Number.addSeparators(arr[0]);\n";
    }
    // Insert the digits into the formatting string.  On the LHS, extra digits are copied
    // into the result.  On the RHS, rounding has chopped them off.
    code += "arr[0] = Number.injectIntoFormat(arr[0].reverse(), '"
        + String.escape(lodp.reverse()) + "', true).reverse();\n";
    if (rdigits > 0) {
        code += "arr[1] = Number.injectIntoFormat(arr[1], '" + String.escape(rodp) + "', false);\n";
    }
    if (scidigits > 0) {
        code += "arr[1] = arr[1].replace(/(\\d{" + rdigits + "})/, '$1" + sciletter + "' + sci.s);\n";
    }
    return code + "return arr.join('.');\n";
}

Number.toScientific = function(val, ldigits, rdigits, scidigits, showsign) {
    var result = {l:"", r:"", s:""};
    var ex = "";
    // Make ldigits + rdigits significant figures
    var before = Math.abs(val).toFixed(ldigits + rdigits + 1).trim('0');
    // Move the decimal point to the right of all digits we want to keep,
    // and round the resulting value off
    var after = Math.round(new Number(before.replace(".", "").replace(
        new RegExp("(\\d{" + (ldigits + rdigits) + "})(.*)"), "$1.$2"))).toFixed(0);
    // Place the decimal point in the new string
    if (after.length >= ldigits) {
        after = after.substring(0, ldigits) + "." + after.substring(ldigits);
    }
    else {
        after += '.';
    }
    // Find how much the decimal point moved.  This is #places to LODP in the original
    // number, minus the #places in the new number.  There are no left-padded zeroes in
    // the new number, so the calculation for it is simpler than for the old number.
    result.s = (before.indexOf(".") - before.search(/[1-9]/)) - after.indexOf(".");
    // The exponent is off by 1 when it gets moved to the left.
    if (result.s < 0) {
        result.s++;
    }
    // Split the value around the decimal point and pad the parts appropriately.
    result.l = (val < 0 ? '-' : '') + String.leftPad(after.substring(0, after.indexOf(".")), ldigits, "0");
    result.r = after.substring(after.indexOf(".") + 1);
    if (result.s < 0) {
        ex = "-";
    }
    else if (showsign) {
        ex = "+";
    }
    result.s = ex + String.leftPad(Math.abs(result.s).toFixed(0), scidigits, "0");
    return result;
}

Number.prototype.round = function(decimals) {
    if (decimals > 0) {
        var m = this.toFixed(decimals + 1).match(
            new RegExp("(-?\\d*)\.(\\d{" + decimals + "})(\\d)\\d*$"));
        if (m && m.length) {
            return new Number(m[1] + "." + String.leftPad(Math.round(m[2] + "." + m[3]), decimals, "0"));
        }
    }
    return this;
}

Number.injectIntoFormat = function(val, format, stuffExtras) {
    var i = 0;
    var j = 0;
    var result = "";
    var revneg = val.charAt(val.length - 1) == '-';
    if ( revneg ) {
       val = val.substring(0, val.length - 1);
    }
    while (i < format.length && j < val.length && format.substring(i).search(/[0#?]/) >= 0) {
        if (format.charAt(i).match(/[0#?]/)) {
            // It's a formatting character; copy the corresponding character
            // in the value to the result
            if (val.charAt(j) != '-') {
                result += val.charAt(j);
            }
            else {
                result += "0";
            }
            j++;
        }
        else {
            result += format.charAt(i);
        }
        ++i;
    }
    if ( revneg && j == val.length ) {
        result += '-';
    }
    if (j < val.length) {
        if (stuffExtras) {
            result += val.substring(j);
        }
        if ( revneg ) {
             result += '-';
        }
    }
    if (i < format.length) {
        result += format.substring(i);
    }
    return result.replace(/#/g, "").replace(/\?/g, " ");
}

Number.addSeparators = function(val) {
    return val.reverse().replace(/(\d{3})/g, "$1,").reverse().replace(/^(-)?,/, "$1");
}

/* String methods */
String.prototype.contains = function(t) {
    return this.indexOf(t) >= 0 ? true : false
};

String.prototype.reverse = function() {
    var res = "";
    for (var i = this.length; i > 0; --i) {
        res += this.charAt(i - 1);
    }
    return res;
};

String.prototype.trim = function(ch) {
    if (!ch) ch = ' ';
    return this.replace(new RegExp("^" + ch + "+|" + ch + "+$", "g"), "");
};

String.leftPad = function (val, size, ch) {
    var result = new String(val);
    if (ch == null) {
        ch = " ";
    }
    while (result.length < size) {
        result = ch + result;
    }
    return result;
};

String.escape = function(str) {
    return str.replace(/('|\\)/g, "\\$1");
};

String.prototype.camelCase = function() {
    return this.replace(/\-(.)/g, function(m, l){return l.toUpperCase()});
};
/***** Array Methods *****/

/*
    -- indexof (added for older browsers --

    usage:
        var myArray = [1,'two',3,'four',5,'six',7,'eight',9,'ten'];
        document.writeln(myArray.indexOf('six'));      // outputs: 5
        document.writeln(myArray.indexOf('not here')); // outputs: -1
    
*/
//This prototype is provided by the Mozilla foundation and
//is distributed under the MIT license.
//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license

if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function(elt /*, from*/) {
        var len = this.length;

        var from = Number(arguments[1]) || 0;
        from = (from < 0) ? Math.ceil(from) : Math.floor(from);
        if (from < 0)
            from += len;

        for (; from < len; from++) {
            if (from in this && this[from] === elt)
            return from;
        }
        return -1;
    };
};

/*
    -- Find method --

    usage:
        var tmp = [5,9,12,18,56,1,10,42,'blue',30, 7,97,53,33,30,35,27,30,'35','Ball', 'bubble'];
        //         0/1/2 /3 /4/5 /6 /7     /8  /9/10/11/12/13/14/15/16/17/  18/    19/      20
        var thirty=tmp.find(30);             // Returns 9, 14, 17
        var thirtyfive=tmp.find('35');       // Returns 18
        var thirtyfive=tmp.find(35);         // Returns 15
        var haveBlue=tmp.find('blue');       // Returns 8
        var notFound=tmp.find('not there!'); // Returns false
        var regexp1=tmp.find(/^b/);          // returns 8,20    (first letter starts with b)
        var regexp1=tmp.find(/^b/i);         // returns 8,19,20 (same as above but ignore case)
*/
Array.prototype.find = function(searchStr) {
    var returnArray = false;
    for (i=0; i<this.length; i++) {
        if (typeof(searchStr) == 'function') {
            if (searchStr.test(this[i])) {
                if (!returnArray) { returnArray = [] }
                returnArray.push(i);
            }
        } else {
            if (this[i]===searchStr) {
                if (!returnArray) { returnArray = [] }
                returnArray.push(i);
            }
        }
    }
    return returnArray;
};

/*
	* The LOOT object is the global (namespace) object used by the LOOT
	* JavaScript Library.  All LOOT objects reside within this object scope.
*/
if ((typeof LOOT == "undefined") || (null == LOOT)) {
	var LOOT = {};
}

LOOT.namespace = function(s) {
	var a, o, i, j, d;
	// Determine if s is string or array and force it to an array
	if (typeof s === 'string') {
		a = [s];
	}
	else if (s.length !== undefined) {
		a = s;
	}
	else {
		// Neither a string or an array was passed in, so exit
		return {};
	}
	for (i = 0; i < a.length; i++) {
		d = a[i].split(".");
		o = LOOT;
		// LOOT is implied, so it is ignored if it is included
		for (j = (d[0] == "LOOT") ? 1 : 0; j < d.length; j++) {
			o[d[j]] = o[d[j]] || {};
			o = o[d[j]];
		}
	}
	return o;
};


/*
    Default properties to be used globally, assigned to LOOT.constant namespace.
*/
LOOT.namespace(["constant","category"]);
LOOT.constant = {
    path: {
        banner_view: 'http://www.loot.com/banners',
        img_media: '/content/images',
        ad_placement: '/place-an-ad.aspx',
        webservice: 'http://' + window.location.host + '/services'
    },
    webservice: {
        geolocation: '/GeoLocationService.asmx',
        advert: '/LootAdvertService.asmx',
        ratecard: '/ratecardservice.asmx',
        category: {
            property: '/categorypropertyservice.asmx'
        }
    },
    customer_services_number: '0800 123456',
    skyscraper_screen_size: '1090',
    timeout: 5000,
    timeout_message: 'Still working',
    error: {
        codes: {
            generic_exception: '-9999',
            JSON_exception: '-5001',
            connection_exception: '-1001',
            xhr_exception: '-1002'
        },
        messages: {
            postcode: 'Invalid Postcode:'
        }
    },
    regex: {
        postcode: /^((([BEGLMNS][1-9]\d?)|(W[2-9])|((A[BL]|B[ABDHLNRST]|C[ABFHMORTVW]|D[ADEGHLNTY]|E[HNX]|F[KY]|G[LUY]|H[ADGPRSUX]|I[GMPV]|JE|K[ATWY]|L[ADELNSU]|M[EKL]|N[EGNPRW]|O[LX]|P[AEHLOR]|R[GHM]|S[AEGKL-PRSTWY]|T[ADFNQRSW]|UB|W[ADFNRSV]|YO|ZE)\d\d?)|(W1[A-HJKSTUW0-9])|(E1W)|(((WC[1-2])|(EC[1-4])|(SW1))[ABEHMNPRVWXY]))(\s*)?([0-9][ABD-HJLNP-UW-Z]{2})?)$|^(GIR\s?0AA)$/i,
        email: '^\\s*[\\w\\-\\+_]+(\\.[\\w\\-\\+_]+)*\\@[\\w\\-\\+_]+\\.[\\w\\-\\+_]+(\\.[\\w\\-\\+_]+)*\\s*$',
        phone: '(\\(?\\+44\\)?\\s?(1|2|3|7|8)\\d{3}|\\(?(01|02|03|07|08)\\d{3}\\)?)\\s?\\d{3}\\s?\\d{3}|(\\(?\\+44\\)?\\s?(1|2|3|5|7|8)\\d{2}|\\(?(01|02|03|05|07|08)\\d{2}\\)?)\\s?\\d{3}\\s?\\d{4}|(\\(?\\+44\\)?\\s?(5|9)\\d{2}|\\(?(05|09)\\d{2}\\)?)\\s?\\d{3}\\s?\\d{3}'
    }
};

// Create LOOT utility (util) namespace
LOOT.namespace(["util"]);
/*
    Loot guid util
*/
LOOT.util.guid = function() {
    this.S4 = function() {
       return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
    };
};
LOOT.util.guid.prototype.generate = function() {
    return (this.S4()+this.S4()+"-"+this.S4()+"-"+this.S4()+"-"+this.S4()+"-"+this.S4()+this.S4()+this.S4());
}
/*
    clear the content of a given DOM element
    @private
*/
LOOT.util.empty = function(el){
	while(el.firstChild){
		el.removeChild(el.firstChild);
	}
};

/*
    Count the length of an associative array 
*/
LOOT.util.countAsc = function(a){
	var counter = 0;
	for(var i in a){
		counter++;
	}
	return counter;
};
/*
    Loot Querystring Utility
    -
*/
LOOT.util.queryString = function() { // optionally pass a querystring to parse
	this.params = {};

    if (arguments.length == 0) { return; };

    var _key = arguments[0];
        _qs = arguments[1];

    if (_qs == null) { _qs = location.search.substring(1, location.search.length); };
    if (_qs.length == 0) { return false; };

    // Turn <plus> back to <space>
    // See: http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4.1
    var _qs = _qs.replace(/\+/g, ' '),
        _args = _qs.split('&'); // parse out name/value pairs separated via &
	
    // split out each name=value pair
    for (var i = 0; i < _args.length; i++) {
	    var _pair = _args[i].split('='),
	        _name = decodeURIComponent(_pair[0]),
	        _value = (_pair.length==2) ? decodeURIComponent(_pair[1]) : _name;

	    this.params[_name] = _value;
    };
    return this.params[_key] == null ? false : true;
};
LOOT.util.queryString.prototype.get = function(key, default_) {
	var value = this.params[key];
	return (value != null) ? value : default_;
};


LOOT.util.log = function() {
    var _fbliteId = 'fblite',
        _fbliteSrc = 'http://localhost:8090/content/script/lib/firebug-lite/firebug-lite-compressed.js';
        _fbliteSrc = 'http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'; // Remote url

    try {
        var _fblite = document.getElementById(_fbliteId),
            _debug = false,//true, // TODO: set this using a cookie
            _args = [];

        // Only log if debug is set too true
        if (_debug) {
            // Check to see if console is available
            if (typeof console != 'object') {
                try {
                    // Load firebug lite
                    if (!_fblite) {
                        var firebug = document.createElement('script');
                            firebug.id = _fbliteId;
                            firebug.setAttribute('src',_fbliteSrc);
                            document.body.appendChild(firebug);
                            firebug.onload = function() {
                                try {
                                    alert('loading...');
                                    if (window.firebug.version) {
                                        alert('version: ' + window.firebug.version);
                                        firebug.init();
                                    } else {
                                        setTimeout(arguments.callee);
                                    };
                                    //void(firebug);
                                    alert('loaded');
                                } catch (ex) {
                                    alert(ex.message);
                                };
                            };
                    };
                } catch (ex) {
                    alert(ex.message);
                };
            };
            // Print messages to the console - TODO: don't think we need 
            for (i = 0; i < arguments.length; i++) {
                _args.push(arguments[i]);
            };
            console.log(_args);
        };
    } catch (ex) { /* Do Nothing */ };
};

// Create LOOT widget namespace
LOOT.namespace(["widget"]);
/*
    LOOT error message widget
*/
LOOT.widget.showInfoMessage = function() {
    var _widget, _widget_inner;
    var _CONTAINER_ID = 'lui_info_panel';

    Event.onAvailable(_CONTAINER_ID, function() {
        _widget = Dom.get(_CONTAINER_ID);
        _widget_inner = _widget.getElementsByTagName('em')[0];
    });

    return {
        hidden: true,
        show: function(m) {
            this.hidden = false;
            // first set the innerHTML to get the element to be the correct size
            _widget_inner.innerHTML = m;
            // then see how wide the element is
            Dom.setStyle(Dom.get(_widget), 'margin-left', '-' + (_widget.offsetWidth / 2) + 'px');
            // then show it
            Dom.setStyle(Dom.get(_widget), 'visibility', 'visible');
        },
        hide: function() {
            var _that = this;
            var _hideAnim = new YAHOO.widget.Effects.Fade(_widget, { seconds: .5, delay: true });
             _hideAnim.onEffectComplete.subscribe(function() { 
                _that.hidden = true;
                _widget_inner.innerHTML = '';
                Dom.setStyle(Dom.get(_widget), 'display', 'inline-block');
                Dom.setStyle(Dom.get(_widget), 'opacity', '1');
            });
            _hideAnim.animate();
        },
        update: function(m) {
            _widget_inner.innerHTML = m;
            Dom.setStyle(Dom.get(_widget), 'margin-left', '-' + (_widget.offsetWidth / 2) + 'px');
        }
    };
}();
/*
    LootUI Password Strength Meter
*/
LOOT.widget.passwordMeter = function(id, obj) {

    var _container_className = 'lui-validator lui-password-meter';
    this.meter_className = 'lui-meter';
    this.info_panel_className = 'lui-password-info';
	this.meter_container = Dom.get(id);
	this.check_match = obj.check || [];
	this.color = obj.color||'dark';
	this.orientation = obj.orientation||'left';
	this.tooltip = obj.tooltip||null;
	this.use_dictionary = false;  // TODO: add dictionary lookup over ajax to determine if password would be easy top crack.

    // set possible error messages
    this._ERROR_MESSAGES = {
        generic_exception: 'An error has occured, please try again',
        connection_failure: '<p>We were unable to connect to the category service,</p><p>please refresh your page and try again</p>',
        timeout: ''
    };

    // Set css class of container element
    var _container_current_class = this.meter_container.className == '' ? null : this.meter_container.className; // remember any class names assigned to element
    _container_current_class = _container_current_class == _container_className ? null : _container_current_class; // if classname is same as the lui classname, set to null so it wont be added back twice
    if(_container_current_class) {Dom.removeClass(this.meter_container, _container_current_class);}; // remove classname
    Dom.addClass(this.meter_container, _container_current_class ? _container_current_class + ' ' + _container_className : _container_className); // add the classname 'lui-category-browse' plus any old classname
    // Create Meter
    this.headerEl = document.createElement('h5');
    this.headerEl.appendChild(document.createTextNode('Password strength'));
    this.meter_container.appendChild(this.headerEl);
    this.meter = document.createElement('div');
    Dom.addClass(this.meter, this.meter_className);
    for (var i = 1; i < 5; i++) {
        var _tmpEl = document.createElement('div');
        _tmpEl.id = 'meter' + i;
        this.meter.appendChild(_tmpEl);
    };
    this.meter_container.appendChild(this.meter);
    // Create info Panel
    if(this.tooltip) {
        this.infoEl = new LOOT.widget.toolTip(
            this.meter_container, {
            color: this.color,
            orientation: this.orientation,
            tooltipClassName: this.info_panel_className
        });
        this.infoEl.setHeader(this.tooltip.heading);
        for (var i = 0; i < this.tooltip.message.length; i++) {
            this.infoEl.setBody(this.tooltip.message[i]);
        };
    };
};
LOOT.widget.passwordMeter.prototype.show = function() {
    this.meter_container.style.display = 'block';
};
LOOT.widget.passwordMeter.prototype.checkStrength = function(pwd) {
    var _base = 0, _combos = 0;

    // COUNT   
    var _length = pwd.length;
    if(_length > 10) {
        _base = 4;
    } else if (_length > 0) {
        _base = 2;
    } else {
        _base = 0;
    };
    // LETTERS
    if(pwd.match(/[a-z]/)) { // [verified] at least one lower case letter
        _base = (_base+1)
    };
    if(pwd.match(/[A-Z]/)) { // [verified] at least one upper case letter
        _base = (_base+5)
    };
    // NUMBERS
    if(pwd.match(/\d+/)) { // [verified] at least one number
        _base = (_base+5)
    };
    if(pwd.match(/(\d.*\d.*\d)/)) { // [verified] at least three numbers
        _base = (_base+5)
    };
    // SPECIAL CHAR
    if(pwd.match(/[!,@#$%^&*?_~]/)) { // [verified] at least one special character
        _base = (_base+5)
    };
    if(pwd.match(/([!,@#$%^&*?_~].*[!,@#$%^&*?_~])/)) { // [verified] at least two special characters
        _base = (_base+5)
    };
    // COMBOS
    if(pwd.match(/[a-z]/) && pwd.match(/[A-Z]/)) { // [verified] both upper and lower case
        _base = (_base+2)
    };
    if(pwd.match(/\d/) && pwd.match(/\D/)) { // [verified] both letters and numbers
        _base = (_base+2)
    };
    // [Verified] Upper Letters, Lower Letters, numbers and special characters
    if(pwd.match(/[a-z]/) && pwd.match(/[A-Z]/) && pwd.match(/\d/) && pwd.match(/[!,@#$%^&*?_~]/)) {
        _base = (_base+2)
    };
    // CHECK OTHER INPUTS
    if(pwd.length >= 1) {
        for (var i = 0; i < this.check_match.length; i++) {
            var _el = this.check_match[i];
            if(_el.value.toLowerCase() == pwd.toLowerCase()) { _base = 2; }; // needs converting into a regex
        };
    };

    _combos = Math.pow(_base,pwd.length);
    if(_combos <= 1){
        this.meter.className = this.meter_className;
    } else if(_combos > 1 && _combos < 1000000) {
        this.meter.className = this.meter_className + ' weak';
    } else if (_combos >= 1000000 && _combos < 10000000000) {
        this.meter.className = this.meter_className + ' medium';
    } else if (_combos >= 10000000000 && _combos < 1000000000000000000) {
        this.meter.className = this.meter_className + ' strong';
    } else {
        this.meter.className = this.meter_className + ' strongest';
    };
};
LOOT.widget.passwordMeter.prototype.showHelp = function() {
    if (this.tooltip) {
        this.infoEl.show();
    };
};
LOOT.widget.passwordMeter.prototype.hideHelp = function() {
    if (this.tooltip) {
        this.infoEl.hide();
    };
};
/*
    LootUI Input validation
*/
LOOT.widget.inputValidator = function(id, obj) {

    obj = typeof obj == 'undefined' ? {} : obj; // check to see if obj has been passed, if not create an empty object.

    var _container_className = 'lui-validator lui-input-validator';
    this.info_panel_className = '';
	this.widget_container = Dom.get(id);
	this.name = obj.name||'loot input validator';
	this.type = obj.type||'default';
	this.color = obj.color||'dark';
	this.orientation = obj.orientation||'left';
	this.regex = obj.regex||null;
	this.valid = null;

	// Set css class of container element
    var _container_current_class = this.widget_container.className == '' ? null : this.widget_container.className; // remember any class names assigned to element
    _container_current_class = _container_current_class == _container_className ? null : _container_current_class; // if classname is same as the lui classname, set to null so it wont be added back twice
    if(_container_current_class) {Dom.removeClass(this.widget_container, _container_current_class);}; // remove classname
    Dom.addClass(this.widget_container, _container_current_class ? _container_current_class + ' ' + _container_className : _container_className); // add the classname 'lui-category-browse' plus any old classname
    // Create widget
    this.imgEl = document.createElement('img');
    this.imgEl.src = '../../Content/Images/icon/waiting.grey.white.gif';
    this.widget_container.appendChild(this.imgEl);
    // Create info Panel
    this.infoEl = new LOOT.widget.toolTip(
        this.widget_container, {
        color: this.color,
        orientation: this.orientation,
        tooltipClassName: this.info_panel_className
    });
};
LOOT.widget.inputValidator.prototype.show = function() {
    this.widget_container.style.display = 'block';
};
LOOT.widget.inputValidator.prototype.validate = function(val) {
    this.imgEl.style.visibility = val.length > 0 ? 'visible' : 'hidden';
    // Javascript regex strings must have double backslashes!
    switch(this.type) {
        case 'email':
            this.regex = this.regex == null ? LOOT.constant.regex.email : this.regex;
            break
        case 'phone':
            this.regex = this.regex == null ? LOOT.constant.regex.phone : this.regex;
            break; //(\(?\+44\)?\s?(1|2|3|7|8)\d{3}|\(?(01|02|03|07|08)\d{3}\)?)\s?\d{3}\s?\d{3}|(\(?\+44\)?\s?(1|2|3|5|7|8)\d{2}|\(?(01|02|03|05|07|08)\d{2}\)?)\s?\d{3}\s?\d{4}|(\(?\+44\)?\s?(5|9)\d{2}|\(?(05|09)\d{2}\)?)\s?\d{3}\s?\d{3}
        default:
            this.regex = this.regex == null ? "\\S" : this.regex;
            break;
    };

    try {
        var _re = new RegExp(this.regex);
        this.valid = _re.test(val);
        this.imgEl.src = this.valid ? '../../Content/Images/icon/validate.input.tick.gif' : '../../Content/Images/icon/waiting.grey.white.gif';
    } catch(ex) {
        // Do nothing
    };
};
LOOT.widget.inputValidator.prototype.showHelp = function(obj) {
    try {
        this.infoEl.setHeader(obj.heading);
        for (var i = 0; i < obj.message.length; i++) {
            this.infoEl.setBody(obj.message[i]);
        };
        this.infoEl.show();
    } catch(ex) {
        alert(ex + ' :: ' + ex.message);
    }
};
LOOT.widget.inputValidator.prototype.hideHelp = function() {
    this.infoEl.reset();
    if(this.valid === false) {
        this.imgEl.src = '../../Content/Images/icon/validate.input.exclamation.gif';
    };
};
/*
    LootUI ToolTip
*/
LOOT.widget.toolTip = function(el, obj) {

    obj = typeof obj == 'undefined' ? {} : obj; // check to see if obj has been passed, if not create an empty object.
    try {
        var _color = obj.color||'dark',
            _orientation = obj.orientation||'left',
            _tool_tip_className = obj.tooltipClassName||'';

        this.tipEl = document.createElement('div');
        this.tipEl.className = 'lui-tooltip lui-tooltip-'+ _color + ' lui-tooltip-' + _orientation + ' ' + _tool_tip_className;
        this.tipEl.style.display = 'none';
        this.tipContent = document.createElement('div');
        this.tipHeader = document.createElement('h6');
        this.tipBody = document.createElement('div');
        this.tipContent.appendChild(this.tipHeader);
        this.tipContent.appendChild(this.tipBody);
        this.tipEl.appendChild(this.tipContent);
        el.appendChild(this.tipEl);
    } catch(ex) { alert('tooltip init ' + ex.message) };
    
    this.clearInnerHTML = function(obj) {
	    // perform a shallow clone on obj
	    nObj = obj.cloneNode(false);
	    // insert the cloned object into the DOM before the original one
	    obj.parentNode.insertBefore(nObj,obj);
	    // remove the original object
	    obj.parentNode.removeChild(obj);
	    // return new cloned node
	    return nObj;
    }
};
LOOT.widget.toolTip.prototype.setHeader = function(msg) {
    if (msg == null) {
        this.tipHeader = this.clearInnerHTML(this.tipHeader);
    } else {
        try {
            this.tipHeader.appendChild(document.createTextNode(msg));
        } catch(ex) { alert('setheader ' + ex.message) };
    };
};
LOOT.widget.toolTip.prototype.setBody = function(msg) {//console.log('tooltip body set');
    if (msg == null) {
        this.tipBody = this.clearInnerHTML(this.tipBody);
    } else {
        try {
            var _emEl = document.createElement('em');
                _emEl.appendChild(document.createTextNode(msg))
            this.tipBody.appendChild(_emEl);
        } catch(ex) { alert('setheader ' + ex.message) };
    };
};
LOOT.widget.toolTip.prototype.show = function() {
    try { this.tipEl.style.display = 'block'; } catch(ex) { alert(ex.message) };
};
LOOT.widget.toolTip.prototype.hide = function() {
    try { this.tipEl.style.display = 'none'; } catch(ex) { alert(ex.message) };
};
LOOT.widget.toolTip.prototype.reset = function() {
    try {
        this.setHeader();
        this.setBody();
        this.hide();
    } catch(ex) { alert(ex.message) };
};
/*
    LootUI dynamic skyscraper
*/
LOOT.widget.banner = function(el, obj) {
    obj = typeof obj == 'undefined' ? {} : obj;

    var _id = obj.id||'page_skyscraper',
        _className = obj._elClassName||'banner',
        _size = obj.size||'120x600',
        _iFrameClassName = obj.className||'sky';

    this.el = el;
    this.banner = document.createElement('div');
    this.banner.id = _id;
    this.banner.className = _className;

    var _iframe = document.createElement('iframe');
    _iframe.className = _iFrameClassName;
    _iframe.setAttribute('frameborder', '0');
    _iframe.setAttribute('scrolling', 'no');
    _iframe.setAttribute('src', LOOT.constant.path.banner_view + '/' + _size);

    this.banner.appendChild(_iframe);
};
LOOT.widget.banner.prototype.show = function() {
    try {
        Dom.addClass(Selector.query("body", document, true), "show-ad");
        this.el.appendChild(this.banner);
    } catch (ex) {
        LOOT.util.log(ex);
    };
};


(function() {
    /*
        LOOT Overlay Manager.
        Register all overlays to this manager, so that multiple overlays can be put on the page.
    */
    LOOT.widget.OverlayManager = YAHOO.widget.OverlayManager ? new YAHOO.widget.OverlayManager() : null;
    /*
        Set up some global LOOT panels
    */
    // create LOOT.panel namespace
    LOOT.namespace(["panel"]);

    // Modal Panel with title.
    LOOT.panel.ModalRounded = function() {
        var _title = arguments[0];
        var _oConfig = arguments[1] || [];

        LOOT.panel.ModalRounded.superclass.constructor.call(
            this,
            _oConfig.id || 'lui_panel_modal',
            {
                width: _oConfig.width||'600px',
                underlay: _oConfig.underlay||'none',
                fixedcenter: _oConfig.fixedcenter !== false,
                draggable: _oConfig.draggable !== false,
                close: _oConfig.close !== false,
                modal: _oConfig.modal !== false,
                constraintoviewport: false,
                visible: false,
                zIndex: _oConfig.zIndex||5
            }
        );

        this.setHeader('<div class="tl"></div><span>' + _title + '</span><div class="tr"></div>');
        this.setBody('<img class="panel-waiting" src="' + LOOT.constant.path.img_media + '/trans.gif" alt="waiting..." />');
        this.setFooter('<div class="bl"></div><span class="button-group"><a id="lui_panel_modal_cancel" href="javascript: void(0)">cancel</a> | <button id="lui_panel_modal_save">Save</button></span><div class="br"></div>');
        this.render(document.body);
    };
    if(Panel) {
        YAHOO.lang.extend(LOOT.panel.ModalRounded, Panel);
    };

    // Modal Dialog with title.
    LOOT.panel.ModalDialogRounded = function() {
        var _oConfig = arguments[1] || [],
            _title = arguments[0],
            _renderTo = _oConfig.render || document.body;

        LOOT.panel.ModalDialogRounded.superclass.constructor.call(
            this,
            _oConfig.id || 'lui_panel_modal',
            {
                width: _oConfig.width||'600px',
                underlay: _oConfig.underlay||'none',
                fixedcenter: _oConfig.fixedcenter !== false,
                draggable: _oConfig.draggable !== false,
                close: _oConfig.close !== false,
                modal: _oConfig.modal !== false,
                constraintoviewport: false,
                visible: false,
                zIndex: _oConfig.zIndex||5
            }
        );

        this.setHeader('<div class="tl"></div><span>' + _title + '</span><div class="tr"></div>');
        this.setBody('<img class="panel-waiting" src="' + LOOT.constant.path.img_media + '/trans.gif" alt="waiting..." />');
        this.setFooter('<div class="bl"></div><span id="footer_buttons" class="button-group"></span><div class="br"></div>');
        this.render(_renderTo);
    };
    if(Dialog) {
        YAHOO.lang.extend(LOOT.panel.ModalDialogRounded, Dialog);
    };

    var search_box = {
        config: {
            search_box_id: 'search_form',
            input_empty_classname: 'emp',
            default_kyd_txt: 'Keyword(s)',
            default_area_txt: 'Postcode'
        },
        init: function() {
            var _inputs = Dom.get(this.config.search_box_id).getElementsByTagName('input');
            this.inputs = new Array();
            for (var i = 0; i < _inputs.length; i++) {
                if (_inputs[i].type != 'hidden') {
                    this.inputs.push(_inputs[i]);
                    if (_inputs[i].value != this.config.default_kyd_txt && _inputs[i].value != this.config.default_area_txt) {
                        Dom.removeClass(_inputs[i], this.config.input_empty_classname);
                    };
                };
            };

            Event.addListener(this.inputs, "focus", search_box.sb_focus, search_box, true);
            Event.addListener(this.inputs, "blur", search_box.sb_blur, search_box, true);
        },
        sb_focus: function(ev) {
            var _tar = Event.getTarget(ev);
            if (_tar.value == this.config.default_kyd_txt || _tar.value == this.config.default_area_txt) {
                _tar.value = '';
            };
            this.set_class(_tar);
        },
        sb_blur: function(ev) {
            var _tar = Event.getTarget(ev);
            if (_tar.value == '') {
                var _tarInput = _tar.id.split('_');
                _tarInput = _tarInput[_tarInput.length - 1];
                if (_tarInput.toLowerCase() == 'gkyd' || _tarInput.toLowerCase() == 'hpkyd') {
                    _tar.value = this.config.default_kyd_txt;
                } else {
                    _tar.value = this.config.default_area_txt;
                };
            };
            this.set_class(_tar);
        },
        set_class: function(tar) {
            if (tar.value == '') {
                Dom.removeClass(tar, this.config.input_empty_classname);
            } else if (tar.value == this.config.default_kyd_txt || tar.value == this.config.default_area_txt) {
                Dom.addClass(tar, this.config.input_empty_classname);
            };
        }
    };
    Event.onAvailable(search_box.config.search_box_id, search_box.init, search_box, true);


    var user_actions = {
        config: {
            user_actions_id: 'user_actions',
            classnames: {
                menu_group: 'lui-menu lui-menu-button',
                menu_group_hover: 'lui-menu-hover',
                menu_group_arrow_hover: 'lui-menu-arrow-hover',
                menu_group_active: 'lui-menu-active',
                menu_group_link: 'lui-menu-link',
                menu_group_arrow: 'lui-menu-arrow'
            }
        },
        init: function() {
            try {
                var _self = this,
                    _navigation = Dom.get(this.config.user_actions_id), _navigationClone,
                    _user = Selector.query('strong', this.config.user_actions_id, true).firstChild.nodeValue,
                    _subMenuItems = Selector.query('#' + this.config.user_actions_id + ' a'),
                    _subMenuLinks = [], _subMenu, _menuGroup, _menuGroupLink, _menuGroupArrow;
                _self.clicked = false;

                // Create config array for building menu submenu links
                for (var i = 0; i < _subMenuItems.length; i++) {
                    var _menuItem = _subMenuItems[i],
                        _tmpObj = {};

                    _tmpObj.text = _menuItem.innerHTML ? _menuItem.innerHTML : _menuItem.firstChild.nodeValue;
                    _tmpObj.url = _menuItem.href;
                    _tmpObj.id = _menuItem.id;

                    _subMenuLinks.push(_tmpObj);
                };

                // Create The submenu group
                _menuGroup = document.createElement('span');
                _menuGroup.className = this.config.classnames.menu_group;
                _self.menuGroup = _menuGroup;
                // submenu link
                _menuGroupLink = document.createElement('a');
                _menuGroupLink.className = this.config.classnames.menu_group_link;
                _menuGroupLink.href = _subMenuItems[0].href;
                _menuGroupLink.appendChild(document.createTextNode(_user));
                _self.menuGroupLink = _menuGroupLink
                // submenu arrow
                _menuGroupArrow = document.createElement('img');
                _menuGroupArrow.className = this.config.classnames.menu_group_arrow;
                _menuGroupArrow.src = LOOT.constant.path.img_media + '/trans.gif';
                _menuGroupArrow.alt = _user + "'s Options";
                _self.menuGroupArrow = _menuGroupArrow;
                // append elements
                _menuGroup.appendChild(_menuGroupLink);
                _menuGroup.appendChild(_menuGroupArrow);

                // add elements to the nav
                // perform a shallow clone on _navigation element (dont clone the elements children)
	            _navigationClone = _navigation.cloneNode(false);
	            // insert the cloned object into the DOM before the original one
	            _navigation.parentNode.insertBefore(_navigationClone,_navigation);
	            // remove the original object
	            _navigation.parentNode.removeChild(_navigation);
                _navigationClone.appendChild(document.createTextNode('Logged in as '));
                _navigationClone.appendChild(_menuGroup);
                _self.add_menu_states();

                // instantiate the menu
                _subMenu = new YAHOO.widget.Menu('user_actions_menu', {
                    context: [ _menuGroup, "tl", "bl" ],
                    shadow: false,
                    zIndex: 30
                } );
                _subMenu.addItems(_subMenuLinks);
                _subMenu.render(this.config.user_actions_id);
                _subMenu.subscribe('hide', function () {
                    Dom.removeClass(_menuGroup, _self.config.classnames.menu_group_active);
                    _self.clicked = false;
                } );

                Event.addListener(_menuGroupArrow, 'click', _subMenu.show, null, _subMenu);

            } catch(ex) {
                // do nothing
            };
        },
        add_menu_states: function() {
            var _self = user_actions;

            Event.addListener(_self.menuGroup, 'mouseover', function(ev) {
                var _tar = Event.getTarget(ev),
                    _className = _tar.nodeName.toLowerCase() === 'img' ? _self.config.classnames.menu_group_arrow_hover : _self.config.classnames.menu_group_hover,
                    _removeClassName = _tar.nodeName.toLowerCase() === 'img' ? _self.config.classnames.menu_group_hover : _self.config.classnames.menu_group_arrow_hover;

                if(_self.clicked == true) {
                    return;
                };
                Dom.replaceClass(_self.menuGroup, _removeClassName, _className);
            }, null, _self);

            Event.addListener(_self.menuGroup, 'mouseout', function(ev) {
                var _tar = Event.getTarget(ev),
                    _className = _tar.nodeName.toLowerCase() === 'img' ? _self.config.classnames.menu_group_arrow_hover : _self.config.classnames.menu_group_hover;

                if(_self.clicked == true) {
                    return;
                };
                Dom.removeClass(_self.menuGroup, _className);
            }, null, _self);

            Event.addListener(_self.menuGroupArrow, 'click', function(ev) {
                Dom.replaceClass(_self.menuGroup, _self.config.classnames.menu_group_arrow_hover, _self.config.classnames.menu_group_active);
                _self.clicked = true;
            }, null, _self);
        }
    }
    Event.onAvailable(user_actions.config.user_actions_id, user_actions.init, user_actions, true);

})();

LOOT.namespace(["tracking"]);
LOOT.tracking.googleEventTracking = function() {
    var _self,
        _listings,
        _links,
        _li,
        _separator = ':';

    function handleClick(ev) {
        var _tar = Event.getTarget(ev),
            _parent = Dom.getAncestorByTagName(_tar, 'li'),
            _type = _tar.rel.split('-')[0],
            _position = _tar.className != '' ? _tar.className.split(' ').join('-') : _type == 'loot' ? _tar.className.split(' ')[0] : '',
            _client = _type == 'loot' ? _tar.className.split(' ')[1] : _parent.id.split(_separator)[0],
            _index = _parent.id.split(_separator)[1];

        pageTracker._trackEvent(_type, _position, _client);
    };

    function trackViews(_id, _type) {
        var _position = 'listingView',
            _client = _id.split(':')[0],
            _length = _li.length;

        pageTracker._trackEvent(_type, _position, _client, _length);    
    };

    function init() {
        _self = this;
        _listings = Selector.query('ul.sponsored-listings li'),
        _links = Selector.query('a[rel*=tracking]');
        _li = Selector.query('ul.sponsored-listings li');

        Event.on(_links, "click", handleClick, _self, true);

        for (var i = 0; i < _listings.length; i++) {
            var _parent = Dom.getAncestorByTagName(_links[i], 'ul'),
                _id = _listings[i].id,
                _type = _parent.className == 'sponsored-listings' ? 'sponsoredLinks' : _links[i].rel.split('-')[1];
            if (_type == 'sponsoredLinks') {
                trackViews(_id, _type);
            };
        };
    };

    return {
        init : init
    }
}();
Event.onDOMReady(LOOT.tracking.googleEventTracking.init, LOOT.tracking.googleEventTracking, true);