﻿
Type.registerNamespace('DTG.Dollar.Web.Consumer.Common.Ajax.LocationSearch');

/// <summary>
/// LocationSearch
///    Extender that populates DOM element with locations based on the values entered on the target text box.
///      A web service call is made to get locations based on text box value, if no locations are found
///      the message element is displayed else the list element is displayed with locations.
///      Once a user selects a location, the list is hidden and the target text box is populated with 
///      the selected location name.  the location code is populated in the pickup location code id
///      element.
///      This extender uses the Sys.Timer() to check textbox values.  The location images are formated
///      using the sitecore image library to set image source. 
/// </summary>
/// <remarks>
///    properties: 
///      {name: 'TargetControlID', type: String} : Default value for extenders identifing the TextBox control
///      {name: 'MinimumPrefixLength', type: Number} : value in which to start calling webservice for results
///      {name: 'PickupLocationCodeId', type: String} : id of element that is populated with location code when a location is selected
///      {name: 'PickupLocationNameId', type: String} : id of element that is populated with location name when a location is selected
///      {name: 'NoLocationFoundMessage', type: String} : message to display when no locations are found
///      {name: 'LocalRatesBehaviorId', type: String} : id of behavior associated with the LRA extender control container
///      {name: 'HighlightItemBgColor', type: String} : background color for list item highlight
///      {name: 'DefaultItemBgColor', type: String} : default background color for list item
///      {name: 'WebServiceErrorText', type: String} : ID to the Sitecore error.  Call the Validator to retrieve the error
///                 and call the Validator to render the error message. The render includes html tags 
///      {name: 'NoLocationMessage', type: String} : Text to display for no pickup location selected
///      {name: 'LocationSelectedMethod', type: String} : Method to call on selection of location from list
///      {name: 'IncludeAddress', type: bool : Whether or not to include location address information 
///      {name: 'IncludeMetroAreas', type: bool : Whether or not to include metro areas in the list
///      {name: 'IncludeStates', type: bool : Whether or not to include states in the list 
///      {name: 'IncludeCountries', type: bool : Whether or not to include countries in the list 
///      {name: 'FilterCountries', type: string : Filter locations by the provided comma delimited list of countries 
///      {name: 'FilterB2B', type: bool : Whether to filter locations for B2B
///      {name: 'NameExtText', type: bool : Text used for Metro, State, and Country names as extended text
///                 within the () after the name.  If empty, no text is displayed
///      {name: 'WatermarkBehaviorId', type: String} : id of behavior extender that identifies the
///                 AjaxControlToolkit watermark extender
/// </remarks>
/// <history>
///     <change date="01/15/2007 12:00:00" ticket="">
///         <author>Steven Berenbrock</author>
///         <description>Initial version.</description>
///     </change>
///     <change date="09/05/2007" ticket="CR 1167">
///         <author>Steven Berenbrock</author>
///         <description>Change to Vehicle Availability Check in Res Panel
///             Removed _setCarType function.....processing of cartype coded in LocationSelectedMethod
///         </description>
///     </change>
///     <change date="12/12/2007">
///         <author>Jscott1 - SiteDynamics</author>
///         <description>Added new property: FilterB2B.  This will filter the locations for use in B2B</description>
///     </change>
/// </history>

DTG.Dollar.Web.Consumer.Common.Ajax.LocationSearch.LocationSearchBehavior = function(element) {
    DTG.Dollar.Web.Consumer.Common.Ajax.LocationSearch.LocationSearchBehavior.initializeBase(this, [element]);
    ///<summary>LocationSearchBehavior Extender</summary>
    ///<param name="element">Associated element</param>

    //Properties
    this._minimumPrefixLength = 3;
    this._pickupLocationCodeId = null;
    this._pickupLocationNameId = null;
    this._noLocationFoundMessage = null;
    this._localRatesBehaviorId = null;
    this._highlightItemBgColor = null;
    this._defaultItemBgColor = "#ffffff";
    this._webServiceErrorText = null;
    this._noLocationMessage = null;
    this._locationSelectedMethod = null;
    this._includeAddress = false;
    this._includeMetroAreas = false;
    this._includeStates = false;
    this._includeCountries = false;
    this._filterCountries = null;
    this._nameExtText = null;
    this._watermarkBehaviorId = null;
    this._filterB2B = false;
    
    // Member variables
    this._listElement = null;
    this._messageElement = null;
    this._listPopupBehavior = null;
    this._messagePopupBehavior = null;
    this._timer = null;
    this._completionInterval = 1000;
    this._selectIndex = null;
    this._cache = null;
    this._currentPrefix = null;
    this._pauseMsg = false;
    this._itemSelected = false;
    this._textBoxHasFocus = false;
    
    // event delegates
    this._tickHandler = null;
    this._element$delegates = {
        blur : Function.createDelegate(this, this._onLostFocus),
        focus : Function.createDelegate(this, this._onGotFocus),
        keydown : Function.createDelegate(this, this._onKeyDown),
        keypress : Function.createDelegate(this, this._onKeyPress)
    };
    this._list$delegates = { 
        mousedown : Function.createDelegate(this, this._onListMouseDown),
        mouseover : Function.createDelegate(this, this._onListMouseOver)
    };
    this._msg$delegates = { 
        mousedown : Function.createDelegate(this, this._onMsgClick)
    };
    
    // Constants
    this._itemCssName = 'Item';
    this._ieItemCssName = 'IeItem';
    this._descriptionCssName = 'Description';
    this._highlightCssName = 'Highlight';
    this._messageCssName = 'Message';
    
    //used to identify the list element, used in id
    this._listElementIdSufix = "_LocationSearch_list";
    //used to identify the message element, used in id
    this._msgElementIdSufix = "_LocationSearch_msg";
    //used to identify items in list, used in item element id
    this._itemIdentifier = '_LocationSearch_item_';
    
    this._metroName = "Metro";
    this._countryName = "Country";
    this._stateName = "State";
}

DTG.Dollar.Web.Consumer.Common.Ajax.LocationSearch.LocationSearchBehavior.prototype = {
    //*****************************************************************
    //Override methods
    //
    initialize : function() {
        DTG.Dollar.Web.Consumer.Common.Ajax.LocationSearch.LocationSearchBehavior.callBaseMethod(this, 'initialize');

        this._createTimer();
        
        var targetElement = this.get_element();
        targetElement.setAttribute("autocomplete", "off");
        $addHandlers(targetElement, this._element$delegates);
        
        //create message container element
        if (!this._messageElement) {
            this._messageElement = document.createElement('div');
            this._messageElement.id = targetElement.id + this._msgElementIdSufix;
            this._messageElement.className = "LocationSearchControlMessage";
       	    this._messageElement.style.visibility = "hidden";
            document.body.appendChild(this._messageElement);
            
            // add popup extender behavior to the message div
            this._messagePopupBehavior = $create(AjaxControlToolkit.PopupBehavior, { positioningMode : AjaxControlToolkit.PositioningMode.BottomLeft, parentElement : targetElement, y : -1 }, { }, null, this._messageElement);
            Sys.Debug.assert(this._messagePopupBehavior != null, "Couldn't create popup behavior for control '" + this._messageElement.id + "'");
            
            //add event handlers to the message element    
            $addHandlers(this._messageElement, this._msg$delegates);
        }
        
        // create list container element 
        if (!this._listElement) {
            this._listElement = document.createElement('div');
            this._listElement.id = targetElement.id + this._listElementIdSufix;
            this._listElement.className = "LocationSearchControlList";
       	    this._listElement.style.visibility = "hidden";
            document.body.appendChild(this._listElement);

            // add popup extender behavior to the list div
            this._listPopupBehavior = $create(AjaxControlToolkit.PopupBehavior, { positioningMode : AjaxControlToolkit.PositioningMode.BottomLeft, parentElement : targetElement, y : -1 }, { }, null, this._listElement);
            Sys.Debug.assert(this._listPopupBehavior != null, "Couldn't create popup behavior for control '" + this._listElement.id + "'");

            //add event handlers to the list element    
            $addHandlers(this._listElement, this._list$delegates);
        }
        this._initializeFields();
    },

    dispose : function() {
        var targetElement = this.get_element();
        
        this._destroyTimer();
        
        //dispose popup behaviors
        if (this._listPopupBehavior) {
            this._listPopupBehavior.dispose();
            this._listPopupBehavior = null;
        }

        if (this._messagePopupBehavior) {
            this._messagePopupBehavior.dispose();
            this._messagePopupBehavior = null;
        }

        // Detach this element events
        if (targetElement) {
            $common.removeHandlers(targetElement, this._element$delegates);
        }
               
        // Detach list element event handlers
        if (this._listElement != null) {
            $common.removeHandlers(this._listElement, this._list$delegates);
            this._listElement = null;
        }
        
        //Detach message element event handlers
        if (this._messageElement != null) {
            $common.removeHandlers(this._messageElement, this._msg$delegates);
            this._messageElement = null;
        }

        DTG.Dollar.Web.Consumer.Common.Ajax.LocationSearch.LocationSearchBehavior.callBaseMethod(this, 'dispose');
    },

    //*****************************************************************
    // Property get/set methods
    //
    get_MinimumPrefixLength : function() {
        return this._minimumPrefixLength;
    },
    
    set_MinimumPrefixLength : function(value) {
        this._minimumPrefixLength = value;
    },            

    get_NoLocationFoundMessage : function() {
        return this._noLocationFoundMessage;
    },
    
    set_NoLocationFoundMessage : function(value) {
        this._noLocationFoundMessage = value;
    },
    
    set_PickupLocationCodeId : function(value) {
        this._pickupLocationCodeId = value;
    },
    
    get_PickupLocationCodeId : function() {
        return this._pickupLocationCodeId;
    },
    
    set_PickupLocationNameId : function(value) {
        this._pickupLocationNameId = value;
    },
    
    get_PickupLocationNameId : function() {
        return this._pickupLocationNameId;
    },    
    
    set_LocalRatesBehaviorId : function(value) {
        this._localRatesBehaviorId = value;
    },
    
    get_LocalRatesBehaviorId : function() {
        return this._localRatesBehaviorId;
    },
    
    set_HighlightItemBgColor : function(value) {
        this._highlightItemBgColor = value;
    },
    
    get_HighlightItemBgColor : function() {
        return this._highlightItemBgColor;
    },
    
    set_DefaultItemBgColor : function(value) {
        this._defaultItemBgColor = value;
    },
    
    get_DefaultItemBgColor : function() {
        return this._defaultItemBgColor;
    },
    
    set_WebServiceErrorText : function(value) {
        this._webServiceErrorText = value;
    },
    
    get_WebServiceErrorText : function() {
        return this._webServiceErrorText;
    },
    
    get_NoLocationMessage : function() {
        return this._noLocationMessage;
    },
    
    set_NoLocationMessage : function(value) {
        this._noLocationMessage = value;
    },

    get_LocationSelectedMethod : function() {
        return this._locationSelectedMethod;
    },

    set_LocationSelectedMethod : function(value) {
        this._locationSelectedMethod = value;
    },
    
    get_IncludeAddress : function() {
        return this._includeAddress;
    },

    set_IncludeAddress : function(value) {
        this._includeAddress = value;
    },
    
    get_IncludeMetroAreas : function() {
        return this._includeMetroAreas;
    },

    set_IncludeMetroAreas : function(value) {
        this._includeMetroAreas = value;
    },
    
    get_IncludeStates : function() {
        return this._includeStates;
    },

    set_IncludeStates : function(value) {
        this._includeStates = value;
    },
    
    get_IncludeCountries : function() {
        return this._includeCountries;
    },

    set_IncludeCountries : function(value) {
        this._includeCountries = value;
    },
    
    get_FilterCountries : function() {
        return this._filterCountries;
    },

    set_FilterCountries : function(value) {
        this._filterCountries = value;
    },
    
    get_NameExtText : function() {
        return this._nameExtText;
    },

    set_NameExtText : function(value) {
        this._nameExtText = value;
    },
    
    set_WatermarkBehaviorId : function(value) {
        this._watermarkBehaviorId = value;
    },
    
    get_WatermarkBehaviorId : function() {
        return this._watermarkBehaviorId;
    },
    
    set_FilterB2B : function(value) {
        this._filterB2B = value;
    },
    
    get_FilterB2B : function() {  
        return this._filterB2B;
    },

    //*****************************************************************
    // Custom methods
    //
    _initializeFields : function() {
        ///<summary>Private method _initializeFields - set member variables with initialize values</summary>
        //if the pickup location name element value is present, set the current prefix to current location name
        var locationName = this._getPickupLocationName();
        if (locationName && locationName.length > 0) {
            this._currentPrefix = locationName;
        }
    },
    
    _createTimer : function() {
        if (!this._timer) {
            if (!this._tickHandler) {
                this._tickHandler = Function.createDelegate(this, this._onTimerTick);
            }
            this._timer = new Sys.Timer();
            this._timer.set_interval(this._completionInterval);
            this._timer.add_tick(this._tickHandler);
        }
    },

    _destroyTimer : function() {
        if (this._timer) {
            this._timer.remove_tick(this._tickHandler);
            this._timer.set_enabled(false);
            this._timer.dispose();
            this._timer = null;
        }
    },    
    
    _showList : function() {
        if (this._listPopupBehavior) {
            this._listPopupBehavior.show();
        }        
    },
    
    _hideList : function() {
        if (this._listPopupBehavior) {
            this._listPopupBehavior.hide();      
        }        
    },
    
    _showMessage : function() {
        if (this._messagePopupBehavior) {
            this._messagePopupBehavior.show();
        }        
    },
    
    _hideMessage : function() {
        if (this._messagePopupBehavior) {
            this._messagePopupBehavior.hide();
        }        
    },
        
    _resetList : function() {
        if (this._listElement) {
            this._listElement.innerHTML = '';
        }
    }, 
    
    _resetMessage : function() {
        if (this._messageElement) {
            this._messageElement.innerHTML = '';
        }
    },

    _getText : function() {
        ///<summary>Public method _getText - gets the textbox value.  if the watermark behavior exists
        /// the value is retreieved from the behavior else it is retrieve from the text box</summary>
        ///<remarks> watermark behavior is checked so that the water mark text does interfere with the
        ///     processing of the locations.  The watermark behavior extender checks if 
        ///     watermark is on returning empty string if true else returns value in text box</remarks>
        if (this._watermarkBehaviorId) {
            //find the extender behavior object
            var watermarkBehavior = $find(this._watermarkBehaviorId);
            if (watermarkBehavior) {
                return watermarkBehavior.get_Text();
            }
            else {
                return this.get_element().value;
            }
        }
        else {
            return this.get_element().value;
        }
    },
    
    _setText : function(text) {
        ///<summary>Private method setText - Sets the textbox value to parm text</summary>
        ///<param name="text">text string</param>
        this._currentPrefix = text;
        this.get_element().value = text;
    },
    
    _setPickupLocationCode : function(locationCode) {
        ///<summary>Private method setPickupLocationCode</summary>
        ///<param name="locationCode">location code string</param>
        ///<remarks>Sets the value attribute of element identified by the pickupLocationCodeId</remarks>
        if (this._pickupLocationCodeId) {
            var pickupLocationCodeElement = $get(this._pickupLocationCodeId);
            if (pickupLocationCodeElement) {
                pickupLocationCodeElement.value = locationCode;
            }
        }    
    },
    
    _setPickupLocationName : function(locationName) {
        ///<summary>Private method setPickupLocationName</summary>
        ///<param name="locationName">location name string</param>
        ///<remarks>Sets the value attribute of element identified by the pickupLocationNameId</remarks>
        if (this._pickupLocationNameId) {
            var pickupLocationNameElement = $get(this._pickupLocationNameId);
            if (pickupLocationNameElement) {
                pickupLocationNameElement.value = locationName;
            }
        }    
    },    
    
    _getPickupLocationName : function() {
        ///<summary>Private method _getPickupLocationName</summary>
        ///<remarks>get the element value from pickup location name element id</remarks>    
        if (this._pickupLocationNameId) {
            var pickupLocationNameElement = $get(this._pickupLocationNameId);
            if (pickupLocationNameElement) {
                return pickupLocationNameElement.value;
            }
        }    
        return null;
    },
    
    _update : function(prefixText, completionItems, cacheResults) {
        ///<summary>Private method update</summary>
        ///<param name="prefixText">text use type for search</param>
        ///<param name="completionItems">list of locations</param>
        ///<param name="cacheResults">bool to determine whether to cache results</param>
        ///<remarks>this method builds _listElement element with the results list.  each result
        ///     item generates a div element with the location data.  The location image is formatted with the sitecore
        ///     image library.  Once all results have been processed, the list is shown,  if no locations are found the
        ///     message element is display with the locations not found message</remarks>
        if (cacheResults){
            // add to the cache if it is not there
            if (!this._cache){
                this._cache = {};
            }
            this._cache[prefixText] = completionItems;
        }
        // reset the list
        this._resetList();
        this._selectIndex = -1;
        
        if (this._textBoxHasFocus) {
            if (completionItems && completionItems.length) {
                var targetElement = this.get_element();
                for (var i = 0; i < completionItems.length; i++){
                    var itemElement = document.createElement('div');
                    if ((Sys.Browser.agent === Sys.Browser.InternetExplorer) && (Sys.Browser.version < 7)) {
                        itemElement.className = this._ieItemCssName;
                    }
                    else {
                        itemElement.className = this._itemCssName;
                    }
                    //create item element id by target + constant itemIdentifier + location code
                    //  if you change how this id is formulated, you must change the selection method.
                    //  the code at the end of the id is used to retrieve the location data from the reuslt list(cache)
                    itemElement.id = targetElement.id + this._itemIdentifier + completionItems[i].Code;
                    // create container for information
                    if (completionItems[i].IsAirportLocation) {
                        var locationImage = document.createElement("img");
                        //format image path for sitecore using path :: ~/media/Images/Reservation/airport%20gif.ashx
                        //format image path for sitecore using guid :: ~/media/F139684850BC4A79BC24095339A42C26.ashx
                        //  had to remove curly brackets ({}) and dashes (-) from GUID in sitecore
                        //using guid method....deemed faster
                        locationImage.setAttribute("src", ("/Images/Dollar/Images/Common/F139684850BC4A79BC24095339A42C26.gif"));  
                        itemElement.appendChild(locationImage);
                    }
                    itemElement.appendChild(this._buildListName(prefixText, completionItems[i].Name, completionItems[i].Code, completionItems[i].MatchByText, completionItems[i].MatchCode, completionItems[i].IsAirportLocation));                    
                    this._listElement.appendChild(itemElement);
                }
                this._hideMessage();
                this._showList();
            }
            else if (prefixText.length >= this._minimumPrefixLength) {
                    this._callNoLocationFound();
            }
            else {
                this._hideMessage();
                this._hideList();
            }
        }
        else {
            this._hideMessage();
            this._hideList();
        }
    },
    
    _getListItemElement : function(element) {
        ///<summary>Private method getListItemElement</summary>
        ///<param name="element">Associated child DOM element to start search</param>
        ///<remarks>search for element with id having itemIdentifer as part of its string id
        /// this would be the list element in the location _listElement list</remarks>
        if (element) {
            var targetElement = this.get_element();
            if (element.id.indexOf(this._itemIdentifier) >= 0) {
                return element;
            }
            else {
                //search parents for item element...stop at list control.
                var locationSearchListId = targetElement.id + this._listElementIdSufix;
                while ((element.id != locationSearchListId) && (element.tagName != 'BODY')) {
                    element = element.parentNode;
                    if (element.id.indexOf(this._itemIdentifier) >= 0) {
                        return element;
                    }
                }
            }
        }
        return null;
    },   
    
    _listLocationSelected : function(itemElement) {
        ///<summary>Private method locationSelected</summary>
        ///<param name="itemElement">List element div element selected</param>
        ///<remarks>this method processes the selection of an item from the location
        ///  list.  the location data is retrieved from cache and found based on the 
        ///  location code at the end of the selected item id, location
        ///  found call to process location selected</remarks>
        if (itemElement) {
            var text = this._getText()
            if (this._cache && this._cache[text]) {
                var completeResults = this._cache[text];
                var subIdx = itemElement.id.indexOf(this._itemIdentifier);
                var code = (subIdx >= 0) ? itemElement.id.substring((subIdx + this._itemIdentifier.length)) : null;
                if (code) {
                    for (var idx = 0; idx < completeResults.length; idx++) {
                        if (code == completeResults[idx].Code) {
                            this._locationSelected(completeResults[idx]);
                            idx = completeResults.length;
                        }
                    }
                }
            }
        }
    },

    _callNoLocationFound : function() {
        ///<summary>Private method callNoLocationFound</summary>
        ///<remarks>sets up the message element for the Location not found message and
        ///     hides the element list and displays the message element</remarks>
        if (this._noLocationFoundMessage && this._noLocationFoundMessage.length > 0) {
            this._resetMessage();
            this._setHtmlMessageContent(this._noLocationFoundMessage, this._descriptionCssName);
            this._hideList();
            this._showMessage();
        }
    },

    _callNoLocationSelected : function() {
        ///<summary>Private method _callNoLocationSelected</summary>
        ///<remarks>sets up the message element for the Location not selected message and
        ///     displays the message element</remarks>
        if (this._noLocationMessage && this._noLocationMessage.length > 0) {
            this._resetMessage();
            this._setHtmlMessageContent(this._noLocationMessage, this._messageCssName);
            this._showMessage();
        }
    },
    
    _setHtmlMessageContent : function(msgText, msgClassName) {
        ///<summary>Private method _setHtmlMessageContent</summary>
        ///<param name="msgText">message string to display in message element</param>
        ///<remarks>set the inner html of the message element with the msg text.  text should be html formatted</remarks>
        if (this._messageElement) {
            var msgDescriptionElement = document.createElement("div");
            //msgDescriptionElement.className = this._messageCssName;
            msgDescriptionElement.className = msgClassName;
            msgDescriptionElement.innerHTML = msgText;
            this._messageElement.appendChild(msgDescriptionElement);
        }
    },    
    
    _setWebServiceError : function() {
        ///<summary>Private method _setWebServiceError</summary>
        ///<remarks>set the message container to display web service error message</remarks>
        this._resetMessage();
        this._setHtmlMessageContent(this._webServiceErrorText, this._messageCssName);
        this._hideList();
        this._showMessage();
    },
    
    _setLRA : function(hasLRA) {
        ///<summary>Private method setLRA</summary>
        ///<param name="hasLRA">bool for identifing if location has local rates (true/false)</param>
        ///<remarks>method that sets the local rates behavior (if exists).  Method calls behavior methods to
        ///     hide or show the local rates container.</remarks>
        if (this._localRatesBehaviorId) {
            //find the extender behavior object
            var localRatesBehavior = $find(this._localRatesBehaviorId);
            if (localRatesBehavior) {
                if (hasLRA) {
                    //show the local rates user entry for zip code
                    localRatesBehavior.show();
                }
                else {
                    //clear out any values in local rates and hide the local rates panel
                    localRatesBehavior.reset();
                    localRatesBehavior.hide();
                }
            }
        }
    },
    
    _buildListName : function(prefixText, locationName, locationCode, matchByText, matchCode, isAirport) {
        ///<summary>Private method buildListName</summary>
        ///<param name="prefixText">text use type for search</param>
        ///<param name="locationName">name of location from retrieved list</param>
        ///<param name="locationCode">code of location from retrieved list</param>
        ///<param name="matchByText">text match</param>
        ///<param name="matchCode">field code for match</param>
        ///<param name="isAirport">true if airport location, else false</param>
        ///<returns>DOM element of type div</returns>
        ///<remarks>this method builds the div tags for the location, metro, state, country name.
        ///  if the prefixText matchs the start of the location name, set to highlight class
        ///  else return as normal description class</remarks>
        var locationDescriptionElement = document.createElement("div");
        locationDescriptionElement.className = this._descriptionCssName;
        var name = locationName;
        switch (matchCode) {
            case "PostalCode":
                name = matchByText + " - " + name;
                break;
            case "City":
                name = matchByText + " - " + name;
                break;
            default:
                break;
        }
        
        if (name.toLowerCase().startsWith(prefixText.toLowerCase())) {
            var highlightElement = document.createElement("span");
            highlightElement.className = this._highlightCssName;
            highlightElement.appendChild(document.createTextNode(name.substr(0, prefixText.length)));
            locationDescriptionElement.appendChild(highlightElement);
            var nameFiller = name.substr(prefixText.length);
            locationDescriptionElement.appendChild(document.createTextNode(this._buildName(nameFiller, locationCode, isAirport)));
        }
        else {
            locationDescriptionElement.appendChild(document.createTextNode(this._buildName(name, locationCode, isAirport)));
        }
        return locationDescriptionElement;
    },

    _buildName : function(name, locationCode, isAirport) {
        ///<summary>Private method buildName</summary>
        ///<param name="name">name of location,metro,state,country from retrieved list</param>
        ///<param name="locationCode">code of location from retrieved list</param>
        ///<param name="isAirport">true if airport location, else false</param>
        ///<returns>string of name</returns>
        var listItemName = name;
        
        if (locationCode.startsWith(this._countryName) || locationCode.startsWith(this._stateName) ||
            locationCode.startsWith(this._metroName)) {
            if (this._nameExtText && this._nameExtText.length > 0) {
                listItemName = String.format("{0} - ({1})", name, this._nameExtText);
            }
        }
        else {
            if (isAirport) {
                listItemName = String.format("{0} ({1})", name, locationCode);
            }
            else {
                listItemName = name;            
            }
        }
        return listItemName;
    },

    _highlightItem : function(item) {
        ///<summary>Private method highlightItem</summary>
        ///<param name="item">DOM element to highlight</param>
        ///<remarks>this method highlights the item if highlightBgColor exists.</remarks>
        if (this._highlightItemBgColor) {
            var children = this._listElement.childNodes;
            
            for (var i = 0; i < children.length; i++) {
                var child = children[i];
                if (child != item){
                    child.style.backgroundColor = this._defaultItemBgColor;
                }
            }
            item.style.backgroundColor = this._highlightItemBgColor;
        }
    },
    
    _getItemIndex : function(itemElementId) {
        var index = -1;
        var children = this._listElement.childNodes;
        for (var i = 0; i < children.length; i++) {
            if (children[i].id == itemElementId){
                index = i;
                break;
            }
        }
        return index;
    },
    
    _callLocationSelectedMethod : function(locObj) {
        ///<summary>Private event method _callLocationSelectedMethod - if property value exists...call method defined by value
        ///     format the call to the location selected method passing the location data as a string list
        ///     separated by ':::'.  this allows custom code to run after selection</summary>
        ///<param name="locObj">location object</param>
        ///<remarks>location data: Code(string), Name(string), IsAirportLocation(bool), Address1(string), Address2(string),
        ///      City(string), State Code(string), PostalCode(string), Country Code(string)
        if (this._locationSelectedMethod && this._locationSelectedMethod != '') {
            var locArray = new Array(locObj.Code, locObj.Name, locObj.IsAirportLocation, locObj.IsLRALocation,
                locObj.Address.Address1, locObj.Address.Address2, locObj.Address.City, locObj.Address.StateCode,
                locObj.Address.PostalCode, locObj.Address.CountryCode);
            //sets up array as list divided by separator...
            var loc = locArray.join(':::');
            try {
                eval(String.format("{0}(\"{1}\")", this._locationSelectedMethod, loc));
            }
            catch(exception) {
                Sys.Debug.trace(exception);
            }
        }        
    },
    
    _processSelectionByText : function() {
        ///<summary>Private method _processSelectionByText</summary>
        ///<remarks>this method processes the text enter in target element
        ///     and calls web service for list of locations</remarks>
        var text = this._getText();
        if (text.length >= this._minimumPrefixLength) {
            //proxy for CustomerWebService.asmx GetLocations(parm, complete handler, error handler, user context);
            DTG.Dollar.Web.Consumer.Services.CustomerWebService.GetLocations(
                text, 
                this._includeAddress,
                this._includeMetroAreas,
                this._includeStates,
                this._includeCountries,
                this._filterCountries,
                this._filterB2B,
                this._onProcessSelectionByText, 
                this._onMethodError, 
                [this, text]);
        }        
    },
    
    _locationSelected : function(location) {
        ///<summary>Private method locationSelected</summary>
        ///<param name="location">location object selected</param>
        ///<remarks>this method processes the selection of a location
        ///  the hidden location data, lra</remarks>
        if (location) {
            this._setPickupLocationCode(location.Code);
            this._setPickupLocationName(location.Name);
            this._setText(location.Name);
            if (location.IsLRALocation) {
                this._setLRA(true);
            }
            else {
                this._setLRA(false);
            }
            this._callLocationSelectedMethod(location);
        }
    },
    
    //*****************************************************************
    // Event handler methods
    //
    _onProcessSelectionByText : function(result, userContext, methodName) {
        ///<summary>Private event method _onProcessSelectionByText</summary>
        ///<param name="result">Result of web service call</param>
        ///<param name="userContext">value passed to web service call for user context</param>
        ///<param name="methodName">name of method that called the web service</param>
        ///<remarks>this is the completed method call from a web service call.  it processes
        ///  the results of the selection by text</remarks>
        var acBehavior = userContext[0];
        var prefixText = userContext[1];
        if (!result || result.length <= 0) {
            acBehavior._callNoLocationFound();
        }
        else {
            acBehavior._locationSelected(result[0]); 
            this._itemSelected = true;
        }
    },    
    
    _onLocationSearchMethodComplete : function(result, userContext, methodName) {
        ///<summary>Private event method onLocationSearchMethodComplete</summary>
        ///<param name="result">Result of web service call</param>
        ///<param name="userContext">value passed to web service call for user context</param>
        ///<param name="methodName">name of method that called the web service</param>
        ///<remarks>this is the completed method call from a web service call.  it processes
        ///  the results of the Location Search web service call.</remarks>
        var acBehavior = userContext[0];
        var prefixText = userContext[1];
        acBehavior._update(prefixText, result, true);
        
        // trigger the no location found method
        if (!result || result.length <= 0) {
            acBehavior._callNoLocationFound();
        }
    },

    _onMsgClick : function(evnt) {
        ///<summary>Private event method _onMsgClick - check if user clicked on 
        /// link tag in message text....pause msgbox display so page can redirect
        /// to link</summary>
        ///<param name="evnt">event object</param>
        if (evnt) {
            if (evnt.target.tagName == "A" || evnt.target.nodeName == "A") {
                this._pauseMsg = true;
            }
        }
    },
    
    _onListMouseDown : function(evnt) {
        ///<summary>Private event method _onListMouseDown - called on mouse down on list
        /// select list item</summary>
        ///<param name="evnt">event object</param>
        if (evnt) {
            if (evnt.target.id != this._listElement.id) {
                var listItemElement =  this._getListItemElement(evnt.target);
                if (listItemElement) {
                    this._itemSelected = true;
                    this._timer.set_enabled(false);
                    this._listLocationSelected(listItemElement);
                    this._hideList();
                }
            }
        }
    },
    
    _onListMouseOver : function(evnt) {
        ///<summary>Private event method _onListMouseOver - called on mouse over of list
        /// highlight list item</summary>
        ///<param name="evnt">event object</param>
        if (evnt) {
            if (evnt.target.id.indexOf(this._itemIdentifier) >= 0) {
                this._highlightItem(evnt.target);
                this._selectIndex = this._getItemIndex(evnt.target.id);
            }
            else {
                // check if parent element mouse over
                var listItemElement =  this._getListItemElement(evnt.target);
                if (listItemElement) {
                    this._highlightItem(listItemElement);
                    this._selectIndex = this._getItemIndex(listItemElement.id);
                }
            }
        }
    },    
    
    _onTimerTick : function(sender, eventArgs) {
        ///<summary>Private event method _onTimerTick</summary>
        ///<param name="sender">sender object</param>
        ///<param name="eventArgs">event arguments</param>
        ///<remarks>event handler for timer tick</remarks>    
        var text = this._getText();
        if (text.length < this._minimumPrefixLength) {
            this._currentPrefix = ""
            this._update('', null, false);
        }
        else if (this._currentPrefix != text) {
            this._currentPrefix = text;
            if (this._cache && this._cache[text]) {
                this._update(text, this._cache[text], false);
            }
            else {
                //proxy for CustomerWebService.asmx GetLocations(parm, complete handler, error handler, user context);
                DTG.Dollar.Web.Consumer.Services.CustomerWebService.GetLocations(
                    text, 
                    this._includeAddress,
                    this._includeMetroAreas,
                    this._includeStates,
                    this._includeCountries,
                    this._filterCountries,
                    this._filterB2B,
                    this._onLocationSearchMethodComplete, 
                    this._onMethodError, 
                    [this, text]);
            }
        }
    },    
    
    _onMethodError : function(error, userContext, methodName) {
        ///<summary>Private event method _onMethodError - called when error received from web service</summary>
        ///<param name="error">error object</param>
        ///<param name="userContext">user context object set in web service call</param>
        ///<param name="methodName">name of method from where the error occurred</param>
        Sys.Debug.trace(error.get_message());
        var acBehavior = userContext[0];
        acBehavior._setWebServiceError();
    },
    
    _onGotFocus : function(evnt) {
        ///<summary>Private event method _onGotFocus - called on focus of target handler</summary>
        ///<param name="evnt">event object</param>
        this._textBoxHasFocus = true;
        this._timer.set_enabled(true);
    },
    
    _onLostFocus : function(evnt) {
        ///<summary>Private event method _onLostFocus - called on blur(lost focus) of target handler</summary>
        ///<param name="evnt">event object</param>
        this._textBoxHasFocus = false;   
        if (!this._itemSelected) {
            this._timer.set_enabled(false);
            this._hideList();
            //check if user clicked on link in message box
            if (!this._pauseMsg) {
                this._hideMessage();            
                var selectedLocationName = this._getPickupLocationName();
                //only validate if value exists
                var targetValue = this._getText();
                if (selectedLocationName != targetValue) {
                    if (targetValue.length >= this._minimumPrefixLength) {
                        this._processSelectionByText();                
                    }
                    else {
                        //user has not selected a new value....show No location selected message
                        this._setPickupLocationCode("");
                        this._setPickupLocationName("");
                        this._setText("");
                        this._callNoLocationSelected();
                    }                    
                }
            }
        }
        else {
            this.get_element().focus();
            this._itemSelected = false;
        }
    },
    
    _onKeyPress : function(evnt) {
        ///<summary>Private event method _onKeyPress - called on key press of target handler</summary>
        ///<param name="evnt">event object</param>
        ///<remarks>event method used to capture enter key for all browsers</remarks>
        if (evnt) {
            var key = evnt.keyCode ? evnt.keyCode : evnt.rawEvent.keyCode;
            if (key === Sys.UI.Key.enter) {         //13
                if (this._selectIndex != -1) {
                    this._listLocationSelected(this._listElement.childNodes[this._selectIndex]);
                    this._hideList();
                    evnt.stopPropagation();     
                    evnt.preventDefault();
                }
                else {
                    this._timer.set_enabled(false);
                    this._hideMessage();
                    this._hideList();
                    evnt.stopPropagation();     
                    evnt.preventDefault();
                    this._processSelectionByText();                
                }
            }
        }
    },
        
    _onKeyDown : function(evnt) {
        ///<summary>Private event method _onKeyDown - called on key down of target handler</summary>
        ///<param name="evnt">event object</param>
        ///<remarks>event method used to capture enter key for all browsers.  note that Safari does not
        /// respond to the enter key(13) in this keydown event.  check keypress event.</remarks> 
        if (evnt) {
            var key = evnt.keyCode ? evnt.keyCode : evnt.rawEvent.keyCode;
            if (key === Sys.UI.Key.esc) {        //27
                this._hideList();
                this._hideMessage();
                evnt.preventDefault();
            }
            else if (key === Sys.UI.Key.up) {       //38
                if (this._selectIndex > 0) {
                    this._selectIndex--;
                    this._highlightItem(this._listElement.childNodes[this._selectIndex]);
                    evnt.stopPropagation();     
                    evnt.preventDefault();
                }
            }
            else if (key === Sys.UI.Key.down) {          //40
                if (this._selectIndex < (this._listElement.childNodes.length - 1)) {
                    this._selectIndex++;
                    this._highlightItem(this._listElement.childNodes[this._selectIndex]);
                    evnt.stopPropagation();     
                    evnt.preventDefault();
                }
            }
            else if (key === Sys.UI.Key.tab) {  //9
                if (this._selectIndex != -1) {
                    this._listLocationSelected(this._listElement.childNodes[this._selectIndex]);
                    this._hideList();
                }
            }
            else {
                this._timer.set_enabled(true);
            }
        }
    }
}

DTG.Dollar.Web.Consumer.Common.Ajax.LocationSearch.LocationSearchBehavior.registerClass('DTG.Dollar.Web.Consumer.Common.Ajax.LocationSearch.LocationSearchBehavior', AjaxControlToolkit.BehaviorBase);

if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();