﻿/****************************************** Begin DynamicInclude ***************************************/
function DynamicInclude(fullUrl) {
    this.fullUrl = fullUrl;
    //this.noCacheIE = '&noCacheIE=' + (new Date()).getTime(); //HUY: removed for better performance
    this.noCacheIE = "";
    this.headLoc = GetHead();
    this.tagId = 'IncTagId' + DynamicInclude.tagCounter++;

    function GetHead() {
        var el = null;
        try {
            el = document.getElementsByTagName("head").item(0);
        }
        catch (e) {
            if (!DynamicInclude.headWarn) {
                DynamicInclude.headWarn = true;
                alert("Please add the <head></head> tag to your html document:\n" + e);
            }
        }
        return el;
    }
}
DynamicInclude.headWarn = false;
DynamicInclude.tagCounter = 1;
DynamicInclude.prototype.buildScriptTag = function() {
    this.scriptObj = document.createElement("script");
    this.scriptObj.setAttribute("type", "text/javascript");
    this.scriptObj.setAttribute("charset", "utf-8");
    this.scriptObj.setAttribute("src", this.fullUrl + this.noCacheIE);
    this.scriptObj.setAttribute("id", this.tagId);
}
DynamicInclude.prototype.buildCssTag = function() {
    this.scriptObj = document.createElement("link");
    this.scriptObj.setAttribute("type", "text/css");
    this.scriptObj.setAttribute("rel", "stylesheet");
    this.scriptObj.setAttribute("href", this.fullUrl + this.noCacheIE);
    this.scriptObj.setAttribute("id", this.tagId);
}
DynamicInclude.prototype.removeTag = function() {
    this.headLoc.removeChild(this.scriptObj);
}
DynamicInclude.prototype.addTag = function() {
    this.headLoc.appendChild(this.scriptObj);
}

/****************************************** Begin ADL library ******************************************/
function ADL() { } //shared methods, meant to be static...
ADL.DisableAllNotifications = false;
ADL.Error = function(e) {
    var s = '';
    var blank = /^\s*$/i;
    if (e != null && !ADL.DisableAllNotifications) {
        if (e.name != null)
            s += e.name + ': ';
        if (e.message != null)
            s += e.message + '\n';
        if (e.stack != null)
            s += 'Stack:\n' + e.stack;
    }
    if (s != null && !blank.test(s))
        alert(s);
    else
        alert('Genereic Widget Error');
}
ADL.Alert = function(msg) {
    if (msg != null && !ADL.DisableAllNotifications)
        alert(msg);
}
ADL.CreateElement = function(name, attmap) {
    var tag = document.createElement(name);
    if (attmap != null) {
        for (var k in attmap) {
            if (k != null && k.length > 0) {
                tag.setAttribute(k, attmap[k]);
            }
        }
    }
    return tag;
}
ADL.FormatCurrency = function(amt) {
    var amount = amt ? Math.round(parseFloat(amt)) : 0;
    if (amount >= 0 && amount < 1000) {
        return amt.toString();
    }
    else {
        var x = amount.toString().length;
        if ((x - 3) % 3 == 0)
            return amount.toString().substr(0, 3).concat(',', ADL.FormatCurrency(amount.toString().substr(3)));
        else
            return amount.toString().substr(0, (x - 3)).concat(',', ADL.FormatCurrency(amount.toString().substr((x - 3))));
    }
};
ADL.JSEscape = function(s) {
    try {
        var re = /[\\'"]/gi; //'
        if (s != null && s.length > 0 && re.test(s)) {
            s = s.replace(re, function($0) { return '\\' + $0; });
        }
    }
    catch (e) { ADL.Error(e); }
    return s;
}
ADL.HTMLEscape = function(s) {
    try {
        if (s != null && s.length > 0) {
            s = s.replace(/\&/g, '&amp;');
            s = s.replace(/\</g, '&lt;');
            s = s.replace(/\>/g, '&gt;');
        }
    }
    catch (e) { ADL.Error(e); }
    return s;
}
ADL.HTMLEscape2 = function(s) {
    try {
        if (s != null && s.length > 0) {
            s = ADL.HTMLEscape(s);
            var re = /[\r\n]+$/i; s = s.replace(re, '');
            re = /\r\n/g; s = s.replace(re, '\n');
            re = /[\n]{3,}/g; s = s.replace(re, '\n\n');
            re = /\n/g; s = s.replace(re, '<br/>');
        }
    }
    catch (e) { ADL.Error(e); }
    return s;
}
ADL.ExtractDateAPI = function(str) {
    var r = null;
    try {
        var re = /[0-9]+/i;
        if (re.test(str)) {
            var ar = re.exec(str);
            if (ar != null && ar.length > 0) {
                var s = parseInt(ar[0]);
                r = new Date(s);
            }
        }
    }
    catch (e) { ADL.Error(e); }
    return r;
}
ADL.ExtractDateUS = function(str) {
    var r = null;
    try {
        var leading0s = /^0*/i;
        var usdate = /([0-9]{1,2})[^0-9]+([0-9]{1,2})[^0-9]+([0-9]{4})/i;
        if (str != null && str.length > 0 && usdate.test(str)) {
            var exp = usdate.exec(str);
            if (exp != null && exp.length > 3) {
                var MM = parseInt(exp[1].replace(leading0s, ''));
                var dd = parseInt(exp[2].replace(leading0s, ''));
                var yyyy = parseInt(exp[3]);
                if (MM >= 1 && MM <= 12 && dd >= 1 && dd <= 31 && yyyy >= 1900 && yyyy <= 2020) {
                    r = new Date();
                    r.setFullYear(yyyy, MM - 1, dd);
                }
            }
        }
    }
    catch (e) { ADL.Error(e); }
    return r;
}
ADL.ToServiceDate = function(date) {
    var r = null;
    try {
        if (date != null) {
            var MM = date.getMonth();
            var dd = date.getDate();
            var yyyy = date.getFullYear();
            if (MM >= 0 && MM <= 11 && dd >= 1 && dd <= 31 && yyyy >= 1900 && yyyy <= 2020) {
                r = yyyy + '-' + (MM + 1) + '-' + dd;
            }
        }
    }
    catch (e) { ADL.Error(e); }
    return r;
}
ADL.AlertNull = function(varname, delay, msg) {
    var blank = /^\s*$/i;
    if (varname != null && !blank.test(varname) && delay > 0) {
        var s = 'if(' + varname + '==null){';
        s += 'window.status = "';
        if (msg != null && !blank.test(msg))
            s += ADL.JSEscape(msg);
        else
            s += ADL.JSEscape(varname + ' is null!');
        s += '";';
        s += '}';
        setTimeout(s, delay);
    }
}
ADL.HasParentForm = function(element) {
    var b = false;
    if (element != null) {
        var re = /^form$/i;
        if (element.nodeName != null && re.test(element.nodeName))
            b = true;
        else
            b = ADL.HasParentForm(element.parentNode);
    }
    return b;
}
ADL.Void = function() {
    //do nothing
}
ADL.IsIE = function() {
    var b = false;
    try {
        var browser = window.navigator.appName;
        var re = /Microsoft/i;
        b = re.test(browser);
    }
    catch (e) { ADL.Error(e); }
    return b;
}
ADL.IsIEver = function(from, to) {
    var b = false;
    try {
        if (ADL.IsIE()) {
            var ua = navigator.userAgent;
            var re = /MSIE ([0-9]+[\.0-9]+)/i;
            if (re.exec(ua) != null) {
                var rv = parseFloat(RegExp.$1);
                if (rv && rv >= from && rv < to)
                    b = true;
            }
        }
    }
    catch (e) { ADL.Error(e); }
    return b;
}
ADL.IsIE6 = function() {
    return ADL.IsIEver(0, 7.0);
}
ADL.IsIE7 = function() {
    return ADL.IsIEver(7.0, 8.0);
}
ADL.IsIE8 = function() {
    return ADL.IsIEver(8.0, 9.0);
}
ADL.IsScriptNotLoaded = function(typeofCheck) {
    var b = (typeofCheck == 'undefined' || typeofCheck == null);
    return b;
}
ADL.YahooGlobalObj = null;
ADL.YahooGetUtil = null;
ADL.InitOnce = false;
ADL.AbsolutePath = null;
ADL.SecureAbsolutePath = null;
ADL.PollingRates = 10; //in ms
ADL.TempLocationID = 101000000;

/****************************************** Begin Module ******************************************/
function Module(jsArray, cssArray) {
    this.JS = jsArray;
    this.CSS = cssArray;
    this.onSuccess = null;
    this.onFailure = null;
    this.onProgress = null;
    this.onTimeout = null;
    this.timeout = 30000;
    this.Responded = false;
    var self = this;
    this.Load = function() {
        this.CSS = Prepend(this.CSS, ADL.ContentPath);
        if (this.CSS != null && this.CSS.length > 0) {
            YAHOO.util.Get.css(this.CSS);
        }
        this.JS = Prepend(this.JS, ADL.ScriptPath);
        if (this.JS != null && this.JS.length > 0) {
            YAHOO.util.Get.script(this.JS, {
                onSuccess: Success,
                onFailure: Failure,
                onProgress: Progress,
                onTimeout: Timeout,
                timeout: this.timeout,
                autopurge: !ADL.IsIE()
            });
        }
    }
    //interceptors
    function Success() {
        if (!self.Responded) {
            self.Responded = true;
            if(self.onSuccess)
                self.onSuccess();
        }
    }
    function Failure() {
        if (!self.Responded) {
            self.Responded = true;
            if(self.onFailure)
                self.onFailure();
        }
    }
    function Progress() {
        if (!self.Responded) {
            self.Responded = true;
            if(self.onProgress)
                self.onProgress();
        }
    }
    function Timeout() {
        if (!self.Responded) {
            self.Responded = true;
            if(self.onTimeout)
                self.onTimeout();
        }
    }
    //helpers
    function Prepend(arr, str) {
        var ret = [];
        var isURL = /^http[s]?\:\/\/[^\/]+/i;
        if (arr != null && arr.length > 0 && str != null && str.length > 0) {
            for (var i = 0; i < arr.length; i++) {
                var s = arr[i];
                if (s != null && s.length > 0) {
                    ret[ret.length] = isURL.test(s) ? s : str + s;
                }
            }
        }
        else
            ret = arr;
        return ret;
    }
}

/********************************** Continue ADL: Begin Path & Module Config ****************************/
ADL.ContentPath = '/Content/Widgets/';
ADL.ScriptPath = '/Scripts/';
ADL.TripSearchEndPoint = '/API/TripSearch?mimeType=javascript&';
ADL.TripDetailsEndPointPath = '/API/TripDetail?mimeType=javascript&';
ADL.TripRatesEndPointPath = '/API/TripRates?mimeType=javascript&';
ADL.Modules = [
    null, //null module : 0
    new Module( //search result module : 1
        ['http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js', 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js', 'AdventureLink/TripSearch.js', 'ui.draggable.js'],
        ['SearchNav.css', 'SearchResult.css', ADL.IsIE6() ? 'SearchResult_ie6.css' : null, ADL.IsIE7() ? 'SearchResult_ie7.css' : null]
    ),
    new Module( //search form module : 2
        ['http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js', 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js',
            'JQuery/ui.datepicker.js', 'JQuery/ui.slider.js', 'AdventureLink/SearchForm.js'],
        ['jquery-ui-1.7.1.custom.css', 'SearchForm.css', ADL.IsIE() ? 'SearchForm_ie.css' : null]
    ),
    new Module( //details : 3
        ['http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js', 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js',
            'Other/photoslider.js', 'JQuery/jquery.tablesorter.min.js', 'JQuery/jquery.tablesorter.pager.js',
						'JQuery/jquery.galleryview-2.0.mod.js', 'JQuery/jquery.easing.1.3.js', 'JQuery/jquery.timers-1.1.2.js',
            'AdventureLink/TripDetails.js'], 
        ['http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/themes/ui-lightness/ui.theme.css', 'jquery-ui-1.7.1.custom.css',
            'StandardStyle.css', '../gui-button.css', 'imageviewer.css',
            'photoslider.css', 'TableSorter.css', 
						'TripDetails.css',
            'Promotions.css', 'Tabs.css', ADL.IsIE7() ? 'IE7Widget.css' : null]
    ),
    new Module( //promo result module : 4
        ['http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js', 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js', 'AdventureLink/TripPromotion.js'],
        ['DealsWidget.css','SaveCorner.css','gui-button.css','StandardStyle.css']
    )
];
ADL.DetectLocalURL = function() { //find local URL & auto config above conf
    try {
        if (ADL.AbsolutePath == null || ADL.AbsolutePath.length == 0) {
            ADL.AbsolutePath = ADL.GetAbsolutePath();
            var re = /^http:/i;
            var local = /^(https:\/\/|http:\/\/localhost|http:\/\/192\.168\.16\.80|http:\/\/10\.0\.1\.63|http:\/\/vweb1|)/i;
            if (local.test(ADL.AbsolutePath)) //exception case for debugging...
                ADL.SecureAbsolutePath = ADL.AbsolutePath;
            else {
                if (re.test(ADL.AbsolutePath))
                    ADL.SecureAbsolutePath = ADL.AbsolutePath.replace(re, "https:");
                else
                    ADL.SecureAbsolutePath = "https://" + ADL.AbsolutePath;
            }

            //add auto conf paths here...
            ADL.ContentPath = ADL.AbsolutePath + ADL.ContentPath;
            ADL.ScriptPath = ADL.AbsolutePath + ADL.ScriptPath;
            ADL.TripSearchEndPoint = ADL.AbsolutePath + ADL.TripSearchEndPoint;
            ADL.TripDetailsEndPointPath = ADL.AbsolutePath + ADL.TripDetailsEndPointPath;
            ADL.TripRatesEndPointPath = ADL.AbsolutePath + ADL.TripRatesEndPointPath;
        }
    }
    catch (e) { ADL.Error(e); }
}

/********************************** Continue Internal ADL Loader: End config ****************************/
ADL.GetAbsolutePath = function() {
    var res = null;
    try {
        var scriptTag = ADL.GetScriptTag();
        if (scriptTag == null || scriptTag.src == null)
            alert("ModuleLoader script is not setup properly. Loader script tag can't be detected!");
        else {
            var re = /^http[s]?\:\/\/[^\/#\?&]+/i;
            var url = scriptTag.src.toString();
            if (url != null && re.test(url)) {
                var ar = re.exec(url);
                if (ar != null && ar[0] != null) {
                    res = ar[0];
                }
            }
            else
                alert("ModuleLoader script is not setup properly. Please check your loader URL.");
        }
    }
    catch (e) { ADL.Error(e); }
    return res;
}

ADL.IsProductionURL = function() {
    var b = false;
    try {
        var re = /^http[s]?:\/\/[^\/#?]+\.(com|net|org)[\/#?]?/i;
        if (ADL.AbsolutePath == null || ADL.AbsolutePath.length == 0)
            ADL.AbsolutePath = ADL.GetAbsolutePath();
        b = (ADL.AbsolutePath != null && re.test(ADL.AbsolutePath));
    } catch (e) { ADL.Error(e); }
    return b;
}

ADL.MasterInit = function() { //recursive check loop
    ADL.DetectLocalURL(); //auto config url!
    
    if (ADL.YahooGlobalObj == null) {
        var url = 'http://ajax.googleapis.com/ajax/libs/yui/2.7.0/build/yahoo/yahoo-min.js';
        //var url = ADL.ScriptPath + 'Yahoo/yahoo-min.js';
        ADL.YahooGlobalObj = new DynamicInclude(url);
        ADL.YahooGlobalObj.buildScriptTag();
        ADL.YahooGlobalObj.addTag();
    }
    try {
        if (ADL.IsScriptNotLoaded(typeof (YAHOO)))
            setTimeout('ADL.MasterInit();', ADL.PollingRates);
        else
            ADL.MasterInit2();
    }
    catch (e) { setTimeout('ADL.MasterInit();', ADL.PollingRates * 2); }
}
ADL.MasterInit2 = function() { //recursive check loop
    if (ADL.YahooGetUtil == null) {
        var url = 'http://ajax.googleapis.com/ajax/libs/yui/2.7.0/build/get/get-min.js';
        //var url = ADL.ScriptPath + 'Yahoo/get-min.js';
        ADL.YahooGetUtil = new DynamicInclude(url);
        ADL.YahooGetUtil.buildScriptTag();
        ADL.YahooGetUtil.addTag();
    }
    try {
        if (ADL.IsScriptNotLoaded(typeof (YAHOO.util.Get)))
            setTimeout('ADL.MasterInit2();', ADL.PollingRates);
        else if (!ADL.InitOnce) {
            ADL.InitOnce = true;
            ADL.Init();
        }
    }
    catch (e) { setTimeout('ADL.MasterInit2();', ADL.PollingRates * 2); }
}
ADL.GetScriptTag = function() {
    var scriptTag = document.getElementById("ModuleLoader");
    if (scriptTag == null) {
        var re = /\/loader\.js[\#\?]Module[\s]*=[\s]*/i;
        var allTags = document.getElementsByTagName("script");
        if (allTags != null && allTags.length > 0) {
            for (var i = 0; i < allTags.length; i++) {
                var t = allTags[i];
                if (t != null && t.src != null && re.test(t.src)) { //found!
                    scriptTag = t;
                    break;
                }
            }
        }
    }
    return scriptTag;
}
ADL.GetModuleParams = function() {
    var arr = [];
    try {
        var scriptTag = ADL.GetScriptTag();
        if (scriptTag == null || scriptTag.src == null)
            alert("ModuleLoader script is not setup properly!");
        else {
            var re = /[\#\?\&]module[\s]*=[\s]*([^\&]*)/i;
            var exp = re.exec(scriptTag.src);
            if (exp != null && exp.length > 1 && exp[1] != null) {
                arr = exp[1].split(',');
                if (arr != null && arr.length > 0) { //convert to int array
                    var newarr = [];
                    for (var i = 0; i < arr.length; i++) {
                        if (arr[i] != null) {
                            newarr[newarr.length] = parseInt(arr[i]);
                        }
                    }
                    arr = newarr;
                }
            }
        }
    }
    catch (e) { ADL.Error(e); }
    return arr;
}
ADL.Init = function() {
    if (ADL.Modules != null && ADL.Modules.length > 0) {
        var params = ADL.GetModuleParams();
        for (var i = 0; i < params.length; i++) {
            try {
                var p = params[i];
                var mod = ADL.Modules[p];
                if (mod != null)
                    mod.Load();
            }
            catch (e) { ADL.Error(e); }
        }
    }
}

/***************************** INIT CODE *******************************/

ADL.MasterInit(); //INIT code

/***************************************** Begin EventCollection ***************************************/
function EventCollection() {
    this.Events = [];
    this.Contains = function(ev) {
        var b = false;
        if (this.Events != null) {
            for (var i = 0; i < this.Events.length; i++) {
                if (this.Events[i] == ev || this.Events[i].valueOf() == ev.valueOf()) {
                    b = true;
                    break;
                }
            }
        }
        return b;
    }
    this.Add = function(ev) {
        if (ev != null) {
            if (this.Events == null)
                this.Events = [];

            if (!this.Contains(ev))
                this.Events[this.Events.length] = ev;
        }
    }
    this.Remove = function(ev) {
        var b = false;
        if (this.Contains(ev)) {
            var newcol = [];
            for (var i = 0; i < this.Events.length; i++) {
                if (!(this.Events[i] == ev || this.Events[i].valueOf() == ev.valueOf())) {
                    newcol[newcol.length] = this.Events[i];
                }
            }
            this.Events = newcol;
        }
        return b;
    }
    this.ExecuteAll = function() {
        if (this.Events != null) {
            for (var i = 0; i < this.Events.length; i++) {
                try {
                    var ev = this.Events[i];
                    if (ev != null)
                        ev();
                }
                catch (e) { ADL.Error(e); }
            }
        }
    }
}

/******************************************* Begin TripCriteria ********************************************/
function TripCriteria() {
    this.Criteria = null;
    this.AcceptableKeys = "Key,TripIDs,AffiliateIDs,SortField,PageSize,PageNumber,IgnoreProdUnv," +
        "SupplierIDs,SupplierName,TripName,MinTripDuration,MaxTripDuration,IsPopularOnly," +
        "SiteCurrency,DoubleAdults,SingleAdults,Children,MinTotalAmount,MaxTotalAmount,MinDailyAmount,MaxDailyAmount,DepartureStart,DepartureEnd,RateIDs,SupplierCurrency,HasPromotion," +
        "ActivityIDs,LocationIDs,TagIDs,ConsortiaIDs,MinLocations,MinActivities," +
        "EventIDs,RadiusMeter,Latitude,Longitude," +
        "SearchPhrase,ReturnEvents,ReturnRates,AllowSuggestion,AllowMatchedLocations,AllowMatchedActivities,AllowMatchedTags,AllowMatchedSuppliers,HideSupplier,LocationOp,ActivityOp,TagOp";
    var acceptable = {}; //for caching, only need to do this once
    var self = this;
    this.ParseURL = function(searchURL) {
        try {
            if (searchURL == null || searchURL.toString().length == 0)
                searchURL = window.location.toString();

            var re = /(\?([^\?]+)|#([^#]+))$/i;
            var ar = re.exec(searchURL);
            if (ar && ar[1] != null) {
                var rawPairs = ar[1].split(/[\?\&\#]+/i);
                var filter = {};
                for (var i = 0; i < rawPairs.length; i++) {
                    if (rawPairs[i] != null && rawPairs[i].length > 0) {
                        var p = ExtractUrlKeyValue(rawPairs[i]);
                        if (p != null && this.IsKeyAcceptable(p.Key))
                            filter[p.Key] = unescape(p.Value);
                            
                            
                            
                    }
                }
                this.Criteria = filter;
            }
        }
        catch (e) { ADL.Error(e); }
    }
    this.MakeURL = function(baseURL, forceRefresh) {
        var url = baseURL;
        try {
            if (this.Criteria != null) {
                if (baseURL == null || baseURL.toString().length == 0)
                    baseURL = window.location.toString();

                var re = /[\#]+[^\#]*$/i;
                if (re.test(baseURL))
                    baseURL = baseURL.replace(re, "#");
                else
                    baseURL += "#";

                if (forceRefresh == true) {
                    var tre = /[\&\?\#]t=[0-9]+/i;
                    if (tre.test(baseURL))
                        baseURL = baseURL.replace(tre, "?t=" + (new Date()).getTime());
                    else
                        baseURL = baseURL.replace(re, "?t=" + (new Date()).getTime() + "#");
                }
                url = baseURL + this.MakeURLQueryOnly();
            }
        }
        catch (e) { ADL.Error(e); }
        return url;
    }
    this.IsKeyAcceptable = function(key) {
        var b = false;
        FillAcceptable();
        b = (acceptable != null && key != null && acceptable[key.toLowerCase()] != null);
        return b;
    }
    this.MakeURLQueryOnly = function() {
        var s = null;
        if (this.Criteria != null) {
            s = '';
            var blank = /^\s*$/i;
            for (var k in this.Criteria) {
                try {
                    var rek = /^key$/i;
                    if (!rek.test(k) && this.IsKeyAcceptable(k)) {
                        var val = this.Criteria[k];
                        if (val != null && !blank.test(val))
                            s += k + '=' + escape(val) + '&';
                    }
                }
                catch (e) { ADL.Error(e); }
            }
        }
        return s;
    }
    this.WriteCriteria = function() {
        var s = '';
        for (var k in this.Criteria) {
            s += "'" + ADL.JSEscape(k) + "':'" + ADL.JSEscape(this.Criteria[k]) + "',";
        }
        if (s.length > 1)
            s = '{' + s.slice(0, s.length - 2) + '}';
        else
            s = '{}';
        return s;
    }
    function FillAcceptable() {
        if (acceptable == null || IsEmpty(acceptable)) { //make it if it isn't there
            if (self.AcceptableKeys != null && self.AcceptableKeys.length > 0) {
                var names = self.AcceptableKeys.toLowerCase().split(/[,]+/i);
                if (names && names.length > 0) {
                    for (var i = 0; i < names.length; i++) {
                        acceptable[names[i]] = true;
                    }
                }
            }
        }
    }
    function IsEmpty(hashObject) {
        var b = true;
        if (hashObject) {
            for (k in hashObject) {
                if (k) {
                    b = false;
                    break;
                }
            }
        }
        return b;
    }
    function ExtractUrlKeyValue(pstr) {
        var r = { 'Key': null, 'Value': null };
        var re = /^[\s]*([^=\s\&]+)=([^=\&]*)$/i;
        var ar = re.exec(pstr);
        if (ar && ar[1] != null && ar[1].length > 0) {
            r.Key = ar[1];
            r.Value = ar[2];
        }
        return r;
    }
}
TripCriteria.SetTripDetailURL = function(existingURL, newTripID) {
    var url = '';
    if (existingURL != null && existingURL.length > 0 && newTripID > 0) {
        var re = /([\#\?\&]?tripID=)[^\&]*/i;
        var ar = re.exec(existingURL);
        if (ar && ar[1] && ar[1].length > 1) {
            url = existingURL.replace(re, function($0, $1) {
                return $1 + newTripID;
            });
        }
        else {
            var h = /\#/i;
            url = existingURL + (h.test(existingURL) ? "&" : "#") + "tripID=" + newTripID;
        }
    }
    return url;
}
TripCriteria.Clone = function(criteria) {
    var r = {};
    if (criteria != null) {
        for (var k in criteria) {
            if (k != null) {
                r[k] = criteria[k];
            }
        }
    }
    return r;
}
TripCriteria.Validate = function(filter, disableAlert) {
    var b = false;
    if (disableAlert == null)
        disableAlert = false;
    try {
        if (filter != null) {
            var SMALL_INT = /^\s*[0-9]{1,2}\s*$/i;
            var MED_INT = /^\s*[0-9]{1,3}\s*$/i;
            var BIG_INT = /^\s*[0-9]{1,6}\s*$/i;
            var MINCHAR_4 = /([^\s]{4,}|^\s*$)/i; //or empty
            var CSV_INT = /^([\-\,0-9]+|\s*)$/i;
            var BIT = /^\s*[01]?\s*$/i;
            var DATE = /^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}[^0-9]*/i;
            var BLANK = /^\s*$/i;
            var AFF_ONLY = /^AffiliateIDs=[0-9]+[&]?$/i;
            var tests = [
                new RegExpTest(filter.TripIDs, CSV_INT, 'TripIDs is not a valid integer CSV.'),
                new RegExpTest(filter.AffiliateIDs, CSV_INT, 'AffiliateIDs is not a valid integer CSV.'),
                new RegExpTest(filter.SortField, SMALL_INT, 'SortField needs to be a positive number.'),
                new RegExpTest(filter.PageSize, MED_INT, 'PageSize needs to be a positive number between 0 and 999'),
                new RegExpTest(filter.PageNumber, MED_INT, 'PageNumber needs to be a positive number between 0 and 999'),
                new RegExpTest(filter.SupplierIDs, CSV_INT, 'SupplierIDs is not a valid integer CSV.'),
                new RegExpTest(filter.SupplierName, MINCHAR_4, 'SupplierName needs to be longer than 3 characters.'),
                new RegExpTest(filter.TripName, MINCHAR_4, 'TripName needs to be longer than 3 characters.'),
                new RegExpTest(filter.MinTripDuration, SMALL_INT, 'MinTripDuration needs to be between 0 and 99.'),
                new RegExpTest(filter.MaxTripDuration, SMALL_INT, 'MaxTripDuration needs to be between 0 and 99.'),
                new RegExpTest(filter.IsPopularOnly, BIT, 'IsPopularOnly needs to be 0 or 1.'),
                new RegExpTest(filter.SiteCurrency, MED_INT, 'SiteCurrency needs to be an integer between 0 and 999.'),

                new RegExpTest(filter.MinTotalAmount, BIG_INT, 'MinTotalAmount needs to be between 0 and 999999.'),
                new RegExpTest(filter.MaxTotalAmount, BIG_INT, 'MaxTotalAmount needs to be between 0 and 999999.'),
                new RegExpTest(filter.MinDailyAmount, BIG_INT, 'MinDailyAmount needs to be between 0 and 999999.'),
                new RegExpTest(filter.MaxDailyAmount, BIG_INT, 'MaxDailyAmount needs to be between 0 and 999999.'),
                new RegExpTest(filter.DepartureStart, DATE, 'DepartureStart needs to be in yyyy-MM-dd format.'),
                new RegExpTest(filter.DepartureEnd, DATE, 'DepartureEnd needs to be in yyyy-MM-dd format.'),
                new RegExpTest(filter.RateIDs, CSV_INT, 'RateIDs is not a valid integer CSV.'),
                new RegExpTest(filter.SupplierCurrency, MED_INT, 'SupplierCurrency needs to be a medium integer.'),
                new RegExpTest(filter.HasPromotion, BIT, 'HasPromotion needs to be a medium integer.'),

                new RegExpTest(filter.ActivityIDs, CSV_INT, 'ActivityIDs is not a valid integer CSV.'),
                new RegExpTest(filter.LocationIDs, CSV_INT, 'LocationIDs is not a valid integer CSV.'),
                new RegExpTest(filter.TagIDs, CSV_INT, 'TagIDs is not a valid integer CSV.'),
                new RegExpTest(filter.ConsortiaIDs, CSV_INT, 'ConsortiaIDs is not a valid integer CSV.'),

                new RegExpTest(filter.SearchPhrase, /^\s*([^\s]{3,}|$)/i, 'SearchPhrase needs to contain more than 3 characters.'),
                new RegExpTest(filter.ReturnEvents, BIT, 'ReturnEvents needs to be 0 or 1.'),
                new RegExpTest(filter.ReturnRates, BIT, 'ReturnRates needs to be 0 or 1.'),
                
                new RegExpTest(filter.LocationOp, BIT, 'LocationOp needs to be 0 or 1.'),
                new RegExpTest(filter.ActivityOp, BIT, 'ActivityOp needs to be 0 or 1.'),
                new RegExpTest(filter.TagOp, BIT, 'TagOp needs to be 0 or 1.')
            ];
            var successes = 0;
            for (var i = 0; i < tests.length; i++) {
                var t = tests[i];
                if (t != null) {
                    if (!t.Test(disableAlert))
                        break;
                    else
                        successes++;
                }
            }
            if (successes >= tests.length) { //ok so far, additional tests
                var tc = new TripCriteria();
                tc.Criteria = filter;
                var query = tc.MakeURLQueryOnly();
                if (query != null && !BLANK.test(query) && !AFF_ONLY.test(query))
                    b = true;
                else
                    alert("No criteria to search on, please provide more parameters!");
            }
        }
    }
    catch (e) { ADL.Error(e); }
    return b;
}

/***************************************** Begin RangeTest ***************************************/

function RangeTest(obj, min, max, objname) {
    this.Object = obj;
    this.ObjectName = objname;
    this.Min = min;
    this.Max = max;
    this.Test = function(disableAlert) {
        var b = false;
        try {
            if (min > max) {
                if (!disableAlert)
                    alert("RangeTest for" + this.ObjectName + " min: " + this.Min + " can't be more than max: " + this.Max);
            }
            else if (this.Object != null) {
                b = this.Object >= this.Min && this.Object <= this.Max;
                if (b == false && !disableAlert && objname != null)
                    alert(this.ObjectName + " is expected to be between: " + this.Min + " and: " + this.Max);
            }
        }
        catch (e) { ADL.Error(e); }
        return b;
    }
}

/***************************************** Begin RegExpTest ***************************************/

function RegExpTest(obj, re, msg) {
    this.Object = obj;
    this.RegExp = re;
    this.Message = msg;
    this.Test = function(disableAlert) {
        var b = false;
        try {
            if (this.RegExp == null)
                alert("RegExpTest.RegExp can not be null!");
            else if (this.Object == null)
                b = true;
            else {
                b = this.RegExp.test(this.Object.toString());
                if (b == false && !disableAlert && msg != null)
                    alert(msg);
            }
        }
        catch (e) { ADL.Error(e); }
        return b;
    }
}

/***************************************** Begin LoadingStatus ***************************************/

function LoadingStatus() {
    this.LoadingImage = ADL.ContentPath + '2-1-loading.gif';
    this.Center = true;
    this.TopPadding = 10;
    var divheight = 21;
    var self = this;
    LoadingStatus.Instances++;
    this.GetElementID = function() {
        return 'LoadingStatus' + LoadingStatus.Instances;
    }
    this.CreateHTML = function() {
        var style = 'padding-top:' + this.TopPadding + 'px; line-height: ' + divheight + 'px; ';
        style += 'font-family:arial,verdana; font-weight:bold; font-size:14px; color:#6db33f; ';
        if (this.Center) {
            style += 'margin:0px auto ' + (-divheight - this.TopPadding) + 'px auto; ';
            style += 'width:100px; ';
        }
        var html = '<div id="' + this.GetElementID() + '" class="loadingstatus" style="' + style + '">';
        html += '<img style="vertical-align:middle" src="' + this.LoadingImage + '" border="0" alt="Loading...">';
        html += '&nbsp; Loading...</div>';
        return html;
    }
    this.PrependAsFirstChild = function(parentEl) {
        if (parentEl != null) {
            var html = this.CreateHTML();
            parentEl.innerHTML = html + parentEl.innerHTML;
        }
    }
}
LoadingStatus.Instances = 0;

/************************************** Detect Link ******************************************/

function DetectLink(parentElementID) {
    this.ParentElement = document.getElementById(parentElementID);
    this.LinkElement = null;
    this.Exists = function() {
        var b = false;
        try {
            if (this.LinkElement == null) {
                if (this.ParentElement != null) {
                    var links = this.ParentElement.getElementsByTagName("a");
                    if (links != null && links.length > 0) {
                        for (var i = 0; i < links.length; i++) {
                            if (TestLink(links[i])) {
                                this.LinkElement = links[i];
                                b = true;
                                break;
                            }
                        }
                    }
                }
            }
            else
                b = true;
        }
        catch (e) { ADL.Error(e); }
        return b;
    }
    this.GetKey = function() {
        var k = null;
        if (this.LinkElement != null || (this.LinkElement == null && this.Exists())) {
            var kval = this.LinkElement.getAttribute('key');
            var re = /^[a-z0-9+\/=]{16,}/i;
            if (kval != null && re.test(kval))
                k = kval;
        }
        return k;
    }
    var self = this;
    function TestLink(el) {
        var b = false; //nodeName
        var isatag = /^a$/i;
        var isgoodlink = /^http[s]?\:\/\/[^.]*[.]?adventurelink\.com(\/|#|\?|$)/i;
        b = (el != null && el.href != null && isgoodlink.test(el.href));
        return b;
    }
}
