//Author:   rebecca.mccay
//Created:  9/25/2009 8:50:37 AM
var regions = "Select a Region,Auckland,Bay of Plenty,Canterbury,Gisborne,Hawkes Bay,Manawatu-Wanganui,Marlborough,Nelson,Northland,Otago,Southland,Taranaki,Tasman,Waikato,Wellington,West Coast";
var map;


var IsBackToResults = false;
var IsParamSearch = false;
var IsPagination = true;
var IsSearch = false;
var IsMapSearchActive = false;
var IsMapActive = false;
var isPopupVisible = false;
var route = false;
var drivingDirectionsCalled = false;

var paginating = false;
var qs = null;

function OnLoad() {
    var _SELF = this;

    Locator.initMap.apply(Locator);
}

var Locator = {

    InitialZoom: 4,
    InitialCentre: new MapDS.LatLng(-28, 135),
    NZCentre: new MapDS.LatLng(-41, 175),
    NZZoom: 5,
    items_per_page: 10,
    num_display_entries: 10,
    listview_items_per_page: 10,
    listview_num_display_entries: 10,
    search_results: new Array(),
    category_filters: new Array(),
    excluded_categories: new Array(),
    useCategoryExclusions: false,
    _lastSelectedResult: null,
    _lastSearchedLocation: null, // private
    retailergrouptop_low: "0px",
    retailergrouptop_high: "0px",
    _resulthint: '',
    _param_retailer: '',

    Strings: {
        InvalidSearch: 'Please enter a Town/Suburb or Postcode',
        InvalidSuburb: 'The value of Suburb is not valid',
        InvalidPostcode: 'The value of Postcode is not valid',
        MultipleAddressDialogTitle: 'Multiple Address Matches Found',
        MultipleAddressPrompt: 'Choose an address',
        InvalidFiltersCategory: 'Please select one or more categories',
        InvalidFiltersRetailer: 'Please select one or more retailers',
        InvalidSearchType: 'Please select either category or retailer',
        Searching: 'Searching...',
        ItemsFound: '{0} nearest location{1} to ',
        DefaultTxtRetailer: 'eg. Retravision, Freedom'
    },

    Images: {
        Loading: './images/loading-circle-black.gif'
    },

    ElementIDs: {
        POIResults: 'poi',
        CheckAll: 'catAll',
        RetailerLabel: 'retailer-label',
        MultipleAddressDialog: 'multipleAddressDialog',
        Sidebar: 'sidebar',
        Map: 'map',
        MultipleAddresses: 'ddlMultipleAddresses',
        ItemsFound: 'itemsfound',
        Search: 'search',
        Results: 'results',
        SearchStreet: 'txtStreet',
        SearchSuburb: 'txtSuburb',
        SearchSuburbNZ: 'txtSuburbNZ',
        SearchState: 'ddlState',
        SearchPostcode: 'txtPostcode',
        AdvancedSearchTrigger: 'chkAdvancedSearch',
        AdvancedSearch: 'search-advanced',
        AdvancedSearchLink: 'advancedSearchLink',
        SearchButton: 'btnFindAddress',
        NewSearchButton: 'btnNewSearch',
        BackToResultsButton: 'btnbackToResults',
        ExceptionDialog: 'exception-dialog',
        DrivingDirections: 'drivingDirections',
        CategorySearchTrigger: 'radioCategorySearch',
        RetailerSearchTrigger: 'radioRetailerSearch',
        CategorySearch: 'search-advanced-category',
        RetailerSearch: 'search-advanced-retailer',
        SearchRetailer: 'ulRetailer',
        SearchCategory: 'ulCategory',
        storeID: 'storeID',
        prodID: 'prodID',
        countryID: 'countryID',
        SearchTxtRetailer: 'txtRetailer',
        streetHidden: 'streetHidden',
        suburbHidden: 'suburbHidden',
        postcodeHidden: 'postcodeHidden',
        stateHidden: 'stateHidden',
        latitudeHidden: 'latitudeHidden',
        longitudeHidden: 'longitudeHidden',
        EndDetail: 'enddetail',
        EndDetailPrint: 'enddetailprint',
        StartTitle: 'startTitle',
        EndTitle: 'endTitle',
        DrivingDirectionsList: 'drivingDirectionsList',
        TxtRetailer: 'txtRetailer',
        stepOne: 'location',
        stepTwo: 'searchtype',
        searchBtns: 'search-buttons',
        StepOneImg: 'stepOneImg',
        RetailerShow: 'retailerShow',
        CategoryShow: 'categoryShow',
        SideBarFooter: 'sidebarfooterDiv',
        ResultsPrevNext: 'resultPrevNext',
        SearchFieldSet: 'search-fieldset',
        SearchDiv: 'searchDiv',
        SearchFilters: 'searchFilters',
        CategoryFilterGroup: 'categoryfiltergroup',
        RetailerFilterGroup: 'retailerfiltergroup',
        CatHome: 'catHome',
        CatHealth: 'catHealth',
        CatOther: 'catOther',
        HomeUlDiv: 'home-ul-div',
        HealthUlDiv: 'health-ul-div',
        OtherUlDiv: 'other-ul-div',
        RetailerFilters: 'ulRetailer'
    },

    // Originally checked all the tickboxes when "All" was selected now Unchecks tickboxes.  
    // Will still perform a search on all filters as in the code further down
    checkAll: function() {
        $('input:checkbox[name=all]:checked').each(function(i) {
            $('input:checkbox[name=category]').attr('checked', '')
        });
    },

    // unchecks all when user selects a single category   
    unCheckAll: function() {
        $('input:checkbox[name=all]').attr('checked', '')
    },

    /// This method is used to validate the search fields. The following function has code
    /// to perform validation on the standard address fields. Use it as a guide for your
    /// custom search fields.
    validateSearchFields: function() {
        var _SELF = this;
        var haveValidSuburb = false;
        var haveValidPostcode = false;
        //var countryID = $(_SELF.getElementID(_SELF.ElementIDs.countryID));
        IsMapSearchActive = false;

        if (_SELF.countryID == "NZ") {
            txtSuburb = $(_SELF.getElementID(_SELF.ElementIDs.SearchSuburbNZ));
        } else {
            txtSuburb = $(_SELF.getElementID(_SELF.ElementIDs.SearchSuburb));
        }

        var val = $(txtSuburb).val().toLowerCase();
        var title = $(txtSuburb).attr("title").toLowerCase();

        if (val == title) {
            // an unchanged default value
            haveValidSuburb = false;
            haveValidPostcode = false;
        } else {
            // the value entered is either a suburb or postcode
            if (_SELF.isPostcode(txtSuburb)) {
                haveValidPostcode = true;
            } else {
                haveValidSuburb = true;
            }
        }

        if (!haveValidSuburb && !haveValidPostcode) {
            _SELF.displayException(this.Strings.InvalidSearch);
            return false;
        }

        var filterChecked = false;
        var category = "";
        var retailer = "";
        var haveValidRetailer = false;
        var txtRetailer = $(_SELF.getElementID(_SELF.ElementIDs.SearchTxtRetailer));

        // Check to see if Category radio is selected
        if ($(_SELF.getElementID(_SELF.ElementIDs.CategorySearchTrigger)).attr("checked")) {
            category = "Y";
            // Check to see if Retailer radio is selected
        } else if ($(_SELF.getElementID(_SELF.ElementIDs.RetailerSearchTrigger)).attr("checked")) {

            retailer = "Y";

            // Check to make sure at least one retailer is checked
            $('input:checkbox[name=retailer]:checked').each(function(i) {
                filterChecked = true;
            });
            if (txtRetailer.attr("value") != '' &&
                txtRetailer.attr("value").toLowerCase() != txtRetailer.attr("title").toLowerCase()) {
                haveValidRetailer = true;
            }
        };


        if (filterChecked != true && retailer == "Y" && haveValidRetailer != true) {
            _SELF.displayException(_SELF.Strings.InvalidFiltersRetailer);
            return false;
        }
        return true;
    },

    isPostcode: function(postcode) {
        var alpha = new RegExp('[a-z,A-Z]');
        if (alpha.test(postcode)) {
            // found alpha characters so fail
            return false;
        }

        // postcode is 4 digits
        var pc = new RegExp('[0-9]{4}');
        if (!pc.test(postcode)) {
            return false;
        }
        return true;
    },

    /// Builds a JSON representation of the address to be geocoded. This method is 
    /// automatically called, it should return an object that contains the following
    /// properties:
    ///     sb = suburb
    ///     st = state
    ///     pc = postcode
    /// if the values are all required by the Geocode handler.
    buildAddressSearch: function() {
        var _SELF = this;

        // load suburb information
        var street = '';
        //var countryID = $(this.getElementID(this.ElementIDs.countryID)).val();

        if (_SELF.countryID == "NZ") {
            txtSuburb = $(_SELF.getElementID(_SELF.ElementIDs.SearchSuburbNZ));
        } else {
            txtSuburb = $(_SELF.getElementID(_SELF.ElementIDs.SearchSuburb));
        }

        var suburb_postcode = txtSuburb.attr("value");
        if (txtSuburb.attr("value").toLowerCase() == txtSuburb.attr("title").toLowerCase()) {
            suburb_postcode = '';
        }

        // load selected state value
        var state = '';
        var ddlState = $(this.getElementID(this.ElementIDs.SearchState));
        if (ddlState.attr("selectedIndex") != 0) {
            state = ddlState.attr("value");
        }

        //var country = document.getElementById('countryID').value;

        var postcode = "";
        var suburb = "";

        (_SELF.isPostcode(suburb_postcode)) ? postcode = suburb_postcode : suburb = suburb_postcode;


        //console.debug('street={0}, suburb={1}, postcode={2}, state={3}, country={4}'.format(street, suburb, postcode, state, _SELF.countryID));

        var address = new MapDS.Address(street, suburb, postcode, null, state, _SELF.countryID);
        //var address = new MapDS.Address(street, suburb, postcode, null, state, 'new zealand');
        return address;
    },

    /// Builds a JSON representation of the search filters available.
    /// MUST return either an object or null. Last line should always be "return null;"
    /// instead of removing, return your object before this line. A return is immediate
    /// and the rest of the code within the method will not execute.

    getSearchFiltersJSON: function() {
        var myFilters = new Array();
        var x = 0;
        var filterChecked = false;

        var _SELF = this;

        // Check to see if Category radio is selected
        if ($(this.getElementID(this.ElementIDs.CategorySearchTrigger)).attr("checked")) {
            type = "category";

            // Find which category checkboxes are selected and add them to an array
            $('input:checkbox[name=category]:checked').each(function(i) {
                filterChecked = true;
                myFilters[i] = this.id;
            });

            // If no filters are selected adds all filters to array
            if (filterChecked == false) {
                var next_index = 0;
                $('input:checkbox[name=category]').each(function(i) {
                    //  check exclusions
                    var shouldBeExcluded = false;
                    if (_SELF.useCategoryExclusions) {
                        for (var j = 0; j < _SELF.excluded_categories.length; j++) {
                            if (_SELF.excluded_categories[j] == this.id) {
                                shouldBeExcluded = true;
                                break;
                            }
                        }
                    }
                    if (!shouldBeExcluded) {
                        myFilters[next_index] = this.id;
                        next_index++;
                    }
                });
            }

            // Check if Reatiler is selected
        } else if ($(this.getElementID(this.ElementIDs.RetailerSearchTrigger)).attr("checked")) {
            type = "retailer";

            // Find which retailer checkboxes are selected and add them to an array
            $('input:checkbox[name=retailer]:checked').each(function(i) {
                filterChecked = true;
                myFilters[i] = this.id;
            });

            if (filterChecked != true) {
                // on a param search this is coming up with the default value
                var txtRetailer = $(this.getElementID(this.ElementIDs.SearchTxtRetailer));
                if (txtRetailer.attr("value") != _SELF.Strings.DefaultTxtRetailer) {
                    myFilters[0] = txtRetailer.attr("value");
                }
            }
        };

        // Add array  of filters selected to query string
        return myFilters.join(" ");
    },

    minimise: function(exclude) {
        var _SELF = this;
        $(_SELF.getElementID(_SELF.ElementIDs.POIResults)).children().each(function() {
            var item = this; // li
            var detail = $(item).children().get(1);
            var header = $(item).children().get(0);
            var plus = $(header).children().get(0);
            var minus = $(header).children().get(1);

            // when we want to minimise everything we use ... minimise(null)
            if (exclude == null || $(item).attr("id") != $(exclude).attr("id")) {
                if ($(detail).css("display") == "block") {
                    $(detail).css("display", "none");
                    $(plus).css("display", "block");
                    $(minus).css("display", "none");

                    $(header).css("border-bottom", "1px solid #E1E1DF");
                }
            }
        });
    },

    // MS - under construction
    setResultPagination: function(address, data, msg) {

        var _SELF = this;
        var showPagingControls = false;
        var lastPoiListPage = -1;

        IsPagination = false;

        // this is where the nav UI is
        var listViewPoiPaging = $(_SELF.getElementID(_SELF.ElementIDs.ResultsPrevNext)).html('');

        if (data.length > 0) {
            $('<div/>').addClass('pagination').appendTo(listViewPoiPaging).pagination(
                data.length, {
                    callback: (
                function(page_index, jq) {
                    var max_elem = Math.min((page_index + 1) * this.items_per_page, data.length);
                    var poiCounter = 0;

                    $(_SELF.getElementID(_SELF.ElementIDs.POIResults)).html('')

                    //if (!IsSearch && !IsBackToResults) {
                        //_SELF._pois = new Array();
                    //}

                    if (_SELF.map && _SELF.map != null) {
                        _SELF.map.clearOverlays();
                    }

                    for (var i = page_index * this.items_per_page; i < max_elem; i++) {
                        try {
                            poiCounter++;
                            var poi = data[i];
                            poi.Marker = _SELF.processPOI(i + 1, poi)
                            _SELF._pois.push(poi);
                        } catch (ex) {
                            //console.debug(ex);
                        }
                    }

                    //if (IsSearch) {
                    if (!_SELF.isUndefined(_SELF._lastSearchedLocation) &&
                        _SELF._lastSearchedLocation != null) {
                        _SELF.processLocationPOI(_SELF._lastSearchedLocation);
                    }
                    //}

                    $('.header').click(function() {

                        var header = this;
                        var parent = $(header).parent();
                        var detail = $(parent).children().get(1);
                        var plus = $(header).children().get(0);
                        var minus = $(header).children().get(1);

                        if ($(detail).css("display") == "none") {
                            $(detail).slideDown();
                            $(plus).css("display", "none");
                            $(minus).css("display", "block");

                            $(header).css("border-bottom", "none");
                            $(detail).css("border-bottom", "1px solid #E1E1DF");
                        } else {
                            //$(detail).slideUp();
                            $(detail).css("display", "none");

                            $(plus).css("display", "block");
                            $(minus).css("display", "none");

                            $(header).css("border-bottom", "1px solid #E1E1DF");
                            $(detail).css("border-bottom", "none");
                        }

                        // minimise all excluding this parent
                        _SELF.minimise(parent);
                    });

                    lastPoiListPage = page_index;

                    //Add results heading eg: 11 to 20 of 36 Locations
                    var total_page_item_count = _SELF._pois.length;
                    var ending_page_item_number = (page_index + 1) * this.items_per_page;
                    var starting_page_item_number = (ending_page_item_number - this.items_per_page) + 1;

                    //Account for final results page end number
                    if (poiCounter != this.items_per_page) { ending_page_item_number = _SELF._pois.length; }

                    $(_SELF.getElementID(_SELF.ElementIDs.ItemsFound)).html(msg);

                    paginating = true;

                    if (IsSearch || IsPagination) {
                        _SELF.map.loadBestView(null, true);
                    }

                    IsPagination = true;
                    return false;
                }),
                    next_text: 'Next 10 results',
                    prev_text: 'Previous 10 results',
                    next_show_always: true,
                    prev_show_always: true,
                    items_per_page: _SELF.listview_items_per_page,
                    num_display_entries: _SELF.listview_num_display_entries
                });
        }

        // ensure all the UI is visible 
        $(_SELF.getElementID(_SELF.ElementIDs.ResultsPrevNext)).css("display", "block");

        // expand the first li in the results list
        if (IsSearch) {
            var first_result = $('#poi').children().get(0);
            $(first_result).trigger('click');

            var header = $(first_result).children().get(0);
            $(header).css("border-bottom", "none");

            var plus = $(header).children().get(0);
            var minus = $(header).children().get(1);

            $(plus).css("display", "none");
            $(minus).css("display", "block");

            var detail = $(first_result).children().get(1);
            $(detail).slideDown();
            $(detail).css("border-bottom", "1px solid #E1E1DF");
        }
    },

    /// This method is called from within findNearest. The purpose of this function is to allow
    /// for control of how the marker is created and how the extra POI information is displayed.
    processPOI: function(id, poi) {
        var _SELF = this;
        var size = new MapDS.Size(22, 36);
        var offset = new MapDS.Pixel(-11, -35);
        var storeID = '';

        // Find current Store Type Selected
        storeID = document.getElementById('storeID').value;

        // Select the appropriate marker to use
        var icn = new MapDS.Maps.Icon('./images/markers/' + storeID + '/{0}.png'.format(id), size, offset);

        // find if the URL parameter has http:// added
        var str = poi.URL;
        var http = "http://";

        if ((str.search(/http/i)) == 0) {
            http = "";
        }

        var mkr = new MapDS.Maps.Marker(new MapDS.LatLng(poi.Position.Latitude, poi.Position.Longitude), { icon: icn });
        mkr.setPopupContent('<div class="popup-content"><div style="padding-bottom:3px;">{0}</div><h6 style="padding-bottom:6px;">{1}</h6 ><p>{2}{3}{5}{6}{7}</p><p>{8}</p><p style="padding-bottom: 15px;">{9}</p><p style="font-weight:bold;"> <a class="wwwlink" href="#" onclick="Locator.getDirections({10})">Get Directions</a> {11}</p></div>'.format(
        //            ((poi.RETAILERID != '' && !_SELF.isUndefined(poi.RETAILERID) && !_SELF.isUndefined(poi.Logo) && poi.Logo == 'Y') ? '<img src="http://www.gemoney.com.au/common/locator/' + poi.RETAILERID + '.gif" class="popup-logo"  alt="Logo" />' : ''),
            ((poi.RETAILERID != '' && !_SELF.isUndefined(poi.RETAILERID)) ? '<img src="http://www.gemoney.com.au/common/locator/' + poi.RETAILERID + '.gif" class="popup-logo"  alt=" " />' : ''),
            '<div class="popupheader">' + poi.Description + '</div>',
            ((poi.StreetPrefix != '' && !_SELF.isUndefined(poi.StreetPrefix)) ? '<p>' + poi.StreetPrefix.toProperCase() + '</p> ' : ''),
            ((poi.Street != '' && !_SELF.isUndefined(poi.Street)) ? poi.Street.toProperCase() + ' ' : ''),

        // Taken out or locator as there is no provision for it in latest mock-ups as of 15th Oct 2009, Left here will most probably be requested in future. 
            ((poi.StreetSuffix != '' && !_SELF.isUndefined(poi.StreetSuffix)) ? poi.StreetSuffix.toProperCase() + ' ' : ''),
            ((poi.Suburb != '' && !_SELF.isUndefined(poi.Suburb)) ? poi.Suburb.toProperCase() + ', ' : ''),
            poi.State + ', ',
            ((poi.Postcode != '' && !_SELF.isUndefined(poi.Postcode)) ? poi.Postcode + '<br/> ' : ''),
            ((poi.Phone != '' && !_SELF.isUndefined(poi.Phone)) ? 'Ph: ' + poi.Phone + '<br/> ' : ''),
            ((poi.URL != '' && !_SELF.isUndefined(poi.URL)) ? '<a class="wwwlink" href="' + http + poi.URL + ' " target="_blank">' + poi.URL + '</a> ' : ''),
            id,
            '<a class="wwwlink" href="javascript:Locator.setMapCentre(' + poi.Position.Latitude + ',' + poi.Position.Longitude + ');"> Zoom in</a>'
        ));

        var header = $('<div class="header">{0}. {1}</div>'.format(id.toString(), poi.Description));
        var max = $('<div class="results-plus" style="display:block;" ></div>');
        var min = $('<div class="results-minus" style="display:none;" ></div>');
        header.append(max);
        header.append(min);

        var detailhtml = '<div class="detail">';
        detailhtml += '<div class="detail-address">';

        var suburbstatepostcode = (!_SELF.isUndefined(poi.Suburb) && poi.Suburb != '') ? poi.Suburb.toProperCase() : '';

        if (suburbstatepostcode.length > 0) {
            suburbstatepostcode += ', ';
        }
        suburbstatepostcode += (!_SELF.isUndefined(poi.State) && poi.State != '') ? ' ' + poi.State.toProperCase() : '';

        if (suburbstatepostcode.length > 0) {
            suburbstatepostcode += ', ';
        }
        suburbstatepostcode += (!_SELF.isUndefined(poi.Postcode) && poi.Postcode != '') ? ' ' + poi.Postcode.toProperCase() : '';

        detailhtml += '<table><tr><td>';

        // street prefix, street, street suffix, suburb/state/postcode 
        detailhtml += '<p>{0}{1}{2}<br>{3}</p>'.format(
            (!_SELF.isUndefined(poi.StreetPrefix) && poi.StreetPrefix != '') ? poi.StreetPrefix.toProperCase() + '</br>' : '',
            (!_SELF.isUndefined(poi.Street) && poi.Street != '') ? poi.Street.toProperCase() : '',
            (!_SELF.isUndefined(poi.StreetSuffix) && poi.StreetSuffix != '') ? ' ' + poi.StreetSuffix.toProperCase() : '',
            suburbstatepostcode);

        // phone, URL
        detailhtml += '<p>{0}<br>{1}</p>'.format(
            (!_SELF.isUndefined(poi.Phone) && poi.Phone != '') ? 'Ph: ' + poi.Phone : '',
            (!_SELF.isUndefined(poi.URL) && poi.URL != '') ? '<a  class="wwwlink" href="' + http + poi.URL + ' " target="_blank">' + poi.URL + '</a> ' : '');

        detailhtml += '</div>'; // address div
        detailhtml += '</td><td>';

        // logo
        detailhtml += '<div class="detail-logo">{0}</div>'.format(
            //(poi.RETAILERID != '' && !_SELF.isUndefined(poi.RETAILERID) && !_SELF.isUndefined(poi.Logo) && poi.Logo == 'Y') ? '<img src="http://www.gemoney.com.au/common/locator/' + poi.RETAILERID + '.gif" alt="Logo" style="float:right;" />' : '');
            (poi.RETAILERID != '' && !_SELF.isUndefined(poi.RETAILERID)) ? '<img src="http://www.gemoney.com.au/common/locator/' + poi.RETAILERID + '.gif" alt=" " style="float:right;" />' : '');

        detailhtml += '</td></tr></table>';

        detailhtml += '</div>'; // detail div

        var detail = $(detailhtml);

        $('<div class="directions-div">' +
          '<img src="./images/' + storeID + '/car.png" height="16px" width="16px" alt="Driving Directions" title="Driving Directions" />' +
          '<a href="#" class="wwwlink driving-wwwlink" style="padding-left:5px;">Driving directions</a>').click(function() {
              _SELF.getDirections(id); return false;
          }).appendTo(detail);

        var item = $('<li style="width:390px;" id="' + id.toString() + '"></li>');
        item.append(header);
        item.append(detail);
        item.click(function() {
            // omniture 
            typeof storeLocatorDetails == "function" && storeLocatorDetails(poi.Description, poi.Suburb);

            _SELF._lastSelectedResult = this;

            mkr.showPopup();
            IsMapSearchActive = false;

            _SELF.map.setCentre(mkr.getPoint(),
            _SELF.map.getZoom());
        })

        // TODO this will open the result however since there is no even when closing the popup this can wait ...
        //        MapDS.Events.addListener(mkr, "popup_displayed", function () {
        //            // expand the result
        //            var detail = $(item).children().get(1);
        //            var header = $(item).children().get(0);
        //            var plus = $(header).children().get(0);
        //            var minus = $(header).children().get(1);
        //            $(header).css("border-bottom", "none");
        //            $(plus).css("display", "none");
        //            $(minus).css("display", "block");
        //            $(detail).show();
        //            _SELF.minimise(item);
        //        });

        item.appendTo(_SELF.getElementID(_SELF.ElementIDs.POIResults));
        _SELF.map.addOverlay(mkr);

        return mkr;
    },

    /// This method is called from within findNearest. The purpose of this function is to allow
    /// for control of how the searched location marker is created and how the extra information is displayed.
    processLocationPOI: function(poi) {
        var size = new MapDS.Size(29, 36);
        var offset = new MapDS.Pixel(-3, -35);

        // Find current Store Type Selected
        storeID = document.getElementById('storeID').value;

        // Select the appropriate marker to use
        icn = new MapDS.Maps.Icon('./images/' + storeID + '/home_location.png', size, offset);
        var _SELF = this;
        var mkr = '';
        var latitudeValue = '';
        var longitudeValue = '';

        if (!IsMapSearchActive) {
            latitudeValue = poi.Position.Latitude;
            longitudeValue = poi.Position.Longitude;

            mkr = new MapDS.Maps.Marker(new MapDS.LatLng(latitudeValue, longitudeValue), { icon: icn });
            mkr.setPopupContent('<div class="popup-content"><h5>Your searched location</h5><p>{0}{1}{2}{3}</p></div>'.format(
                ((poi.Street != '' && !_SELF.isUndefined(poi.Street)) ? poi.Street + '' : ''),
                ((poi.Locality != '' && !_SELF.isUndefined(poi.Locality)) ? poi.Locality + ', ' : ''),
                poi.Region + ', ',
                ((poi.PostalCode != '' && !_SELF.isUndefined(poi.PostalCode)) ? poi.PostalCode : '')
            ));
            $(_SELF.getElementID(_SELF.ElementIDs.suburbHidden)).val(poi.Locality != '' ? poi.Locality + ', ' : '');
            $(_SELF.getElementID(_SELF.ElementIDs.streetHidden)).val(poi.Street != '' ? poi.Street + ', ' : '');
            $(_SELF.getElementID(_SELF.ElementIDs.postcodeHidden)).val(poi.PostalCode != '' ? poi.PostalCcode + ', ' : '');
            $(_SELF.getElementID(_SELF.ElementIDs.stateHidden)).val(poi.Region);
            $(_SELF.getElementID(_SELF.ElementIDs.latitudeHidden)).val(latitudeValue);
            $(_SELF.getElementID(_SELF.ElementIDs.longitudeHidden)).val(longitudeValue);

        } else {

            var latitude = $(_SELF.getElementID(_SELF.ElementIDs.latitudeHidden));
            var longitude = $(_SELF.getElementID(_SELF.ElementIDs.longitudeHidden));

            latitudeValue = (Number(latitude.attr("value")));
            longitudeValue = (Number(longitude.attr("value")));

            mkr = new Mapds.Maps.Marker(new MapDS.LatLng(latitudeValue, longitudeValue), { icon: icn });
            mkr.setPopupContent('<div class="popup-content"><h5>Your searched location</h5><p>{0}{1}{2}{3}</p></div>'.format(
                $(_SELF.getElementID(_SELF.ElementIDs.streetHidden)).val(),
                $(_SELF.getElementID(_SELF.ElementIDs.suburbHidden)).val(),
                $(_SELF.getElementID(_SELF.ElementIDs.postcodeHidden)).val(),
                $(_SELF.getElementID(_SELF.ElementIDs.stateHidden)).val()

            ));
        }

        mkr.IsCentreMarker = true;
        this.map.addOverlay(mkr);

        // DO NOT REMOVE THE FOLLOWING LINE - It is needed for routing purposes.
        this.locationMarker = mkr;
    },

    /// This method is called from within createRouteCallback. It is the helper method for generating the caption that will appear on
    /// the driving directions listing for the point.
    buildRouteCaption: function(poi) {
        var _SELF = this;
        return [poi.Description,
            ((poi.Street != '' && !_SELF.isUndefined(poi.Street)) ? poi.Street + '' : ''),
            ((poi.Locality != '' && !_SELF.isUndefined(poi.Locality)) ? poi.Locality + ', ' : ''),
            ((poi.PostalCode != '' && !_SELF.isUndefined(poi.PostalCode)) ? poi.PostalCode : '')
        ];
    },

    /// Start of core Locator code
    map: null, // object that contains the QuickMap instance
    geocoder: new MapDS.Maps.Geocoder(),
    directionsHelper: null,
    RouteMode: 1, // eventually this will be a setting that can change therefore it will move to the top of the script file.
    locationMarker: null,
    _foundLocations: null, // private
    _pois: Array(), // private
    _retailers: Array(),
    _CategoryName: '',
    _lastFieldFocussed: null, // private, the last search field to have focus

    /**
    * Returns true if position is a valid sidebar position
    */
    //isValidSidebarPosition: function (position) { if (position == this.SidebarPositions.Left || position == this.SidebarPositions.Bottom || position == this.SidebarPositions.Right || position == this.SidebarPositions.Top) { return true; } return false; },

    /**
    * Returns true if object is undefined
    */
    isUndefined: function(object) { return typeof object === "undefined"; },

    /**
    * Private method
    * Returns true if object is an Image
    * IE doesn't support "instanceof Image" so instead we test that the object is in the DOM then test the tagName is 'IMG'
    */
    isImage: function(object) { return this.isHTMLElement(object, 'IMG'); },

    /**
    * Private method
    * Returns true if object is an HTML Element
    * {type} is a string that represents the type of HTML element that the object should be.
    *      for example. if [type] is "div" then the element should be a div.
    */
    isHTMLElement: function(object, type) { if (!type || !(typeof type === "string")) { return false; } if (object && object.nodeType) { return (object.tagName === type.toUpperCase() ? true : false); } return false; },

    /**
    * Private method
    * Returns true if input is a number
    */
    isNumeric: function(input) { return (input - 0) == input && input.length > 0; },

    /**
    * Private method
    * Returns true if object is a function
    */
    isFunction: function(object) { return typeof object === "function"; },

    /**
    * Returns the id string asked for, will prepend # unless the second parameter is false.
    */
    getElementID: function(id, withHash) {
        if (this.isUndefined(withHash)) {
            withHash = true;
        }
        return (withHash ? "#" : "") + id;
    },

    /**
    * Will fire a call to load up the exception dialog, the HTML will be set using the message parameter.
    */
    displayException: function(errorMessage) { $(this.getElementID(this.ElementIDs.ExceptionDialog)).html(errorMessage).dialog('open'); },

    /**
    * Will save a POI as the last location.
    */
    saveLocationPOI: function(poi) { this._lastSearchedLocation = poi; },
    saveRouteStartPOI: function(poi) { this._routeStart = poi; },

    /**
    * Private method
    * Assumption is made that at least the first parameter exists and that it is a number. 
    * The same number assumption is made for precision if it is given.
    * Default for precision is 1, therefore no change.
    */
    round: function(val, precision) { precision = (arguments.length > 1) ? Math.pow(10, arguments[1]) : 1; return Math.round(val * precision) / precision; },

    /**
    * Will return the full bearing from the shortened string.
    */
    expandBearing: function(bearing) { switch (bearing) { case 'N': return 'North'; break; case 'S': return 'South'; break; case 'E': return 'East'; break; case 'W': return 'West'; break; case 'NE': return 'North East'; break; case 'NW': return 'North West'; break; case 'SE': return 'South East'; break; case 'SW': return 'South West'; break; default: return ''; } },

    /**
    * Will convert seconds to a formatted time string
    */
    convertToTime: function(seconds) { var hrs = Math.floor(seconds / 3600); var mins = Math.floor(seconds / 60) - (hrs * 60); var secs = seconds - ((hrs * 3600) + (mins * 60)); var msg = 'about '; if (hrs > 0) { msg = hrs + 'hrs '; } if (mins > 0) { msg += mins + 'mins '; } if (hrs == 0 && mins == 0) { msg = 'less than 1 minute'; } return msg; },

    /**
    * Resets everything! 
    */

    //        CatHome: 'catHome',
    //        CatHealth: 'catHealth',
    //        CatOther: 'catOther',
    //        HomeUlDiv: 'home-ul-div',
    //        HealthUlDiv: 'health-ul-div',
    //        OtherUlDiv: 'other-ul-div'

    /// Reset the search fields back to default values.
    /// Here we set the textfields to the value in the title attribute and then call the blur method to
    /// trigger jQuery hint code.
    resetSearchCheckboxes: function() {
        var _SELF = this;
        $(_SELF.getElementID(_SELF.ElementIDs.Search) + ' input[title!=""]').attr("value", "").blur();
        $(_SELF.getElementID(_SELF.ElementIDs.Search) + ' input[type="checkbox"]').attr("checked", "");
        $('input:checkbox[name=all]').attr('checked', 'checked');
        $(_SELF.getElementID(_SELF.ElementIDs.SearchState)).attr("selectedIndex", 0);
        $(_SELF.getElementID(_SELF.ElementIDs.CategorySearchTrigger)).attr("checked", "checked");
        $(_SELF.getElementID(_SELF.ElementIDs.RetailerSearchTrigger)).attr("checked", "");
    },

    resetSearchElements: function() {
        var _SELF = this;

        _SELF.resetSearchCheckboxes();

        $(_SELF.getElementID(_SELF.ElementIDs.CategorySearch)).show()
        $(_SELF.getElementID(_SELF.ElementIDs.RetailerSearch)).hide()

        $(_SELF.getElementID(_SELF.ElementIDs.RetailerFilterGroup)).css("top", _SELF.retailergrouptop_low);

        // maximize
        var homeul = $(_SELF.getElementID(_SELF.ElementIDs.HomeUlDiv)).show();
        var homeplus = $($($($($(_SELF.getElementID(_SELF.ElementIDs.CatHome)).children().get(0)).children().get(0)).children().get(0))[0].cells[1]).children().get(0);
        var homeminus = $($($($($(_SELF.getElementID(_SELF.ElementIDs.CatHome)).children().get(0)).children().get(0)).children().get(0))[0].cells[2]).children().get(0);

        // cathome icon to minimise
        $(homeplus).css("display", "none");
        $(homeminus).css("display", "block");

        // close the rest
        if (!_SELF.useCategoryExclusions) {
            //$(_SELF.getElementID(_SELF.ElementIDs.HealthUlDiv)).slideUp();
            $(_SELF.getElementID(_SELF.ElementIDs.HealthUlDiv)).css("display", "none");

            var healthplus = $($($($($(_SELF.getElementID(_SELF.ElementIDs.CatHealth)).children().get(0)).children().get(0)).children().get(0))[0].cells[1]).children().get(0);
            var healthminus = $($($($($(_SELF.getElementID(_SELF.ElementIDs.CatHealth)).children().get(0)).children().get(0)).children().get(0))[0].cells[2]).children().get(0);

            // cathome icon to minimise
            $(healthplus).css("display", "block");
            $(healthminus).css("display", "none");
        }

        //$(_SELF.getElementID(_SELF.ElementIDs.OtherUlDiv)).slideUp();
        $(_SELF.getElementID(_SELF.ElementIDs.OtherUlDiv)).css("display", "none");

        var otherplus = $($($($($(_SELF.getElementID(_SELF.ElementIDs.CatOther)).children().get(0)).children().get(0)).children().get(0))[0].cells[1]).children().get(0);
        var otherminus = $($($($($(_SELF.getElementID(_SELF.ElementIDs.CatOther)).children().get(0)).children().get(0)).children().get(0))[0].cells[2]).children().get(0);

        // cathome icon to minimise
        $(otherplus).css("display", "block");
        $(otherminus).css("display", "none");
    },

    reset: function() {
        var _SELF = this;

        _SELF._foundLocations = null;
        _SELF._lastSearchedLocation = null;
        _SELF.locationMarker = null;
        _SELF._pois = new Array();
        IsMapSearchActive = false;
        IsMapActive = false;
        _SELF.searchClear = true;

        _SELF.resetSearchElements();

        $(_SELF.getElementID(_SELF.ElementIDs.Results)).hide();
        $(_SELF.getElementID(_SELF.ElementIDs.DrivingDirections)).hide();
        $(_SELF.getElementID(_SELF.ElementIDs.SideBarFooter)).hide();
        $(_SELF.getElementID(_SELF.ElementIDs.Search)).show();

        // buttons could be aligned as for driving directions panel ...


        // and ensure the new search button has the correct image
        //Logger.log('reset: newsearchbutton');
        $(_SELF.getElementID(_SELF.ElementIDs.NewSearchButton)).removeClass('alternate-newsearchbutton');
        $(_SELF.getElementID(_SELF.ElementIDs.NewSearchButton)).addClass('newsearchbutton');

        if ($(_SELF.getElementID(_SELF.ElementIDs.NewSearchButton)).hasClass('alternate-newsearchbutton')) {
            alert('reset: hasClass: alternate-newsearchbutton');
        }

        // ensure the backtoresults button is hidden

        //Logger.log('reset: back-to-results');
        //$(_SELF.getElementID(_SELF.ElementIDs.BackToResultsButton)).hide();
        $(_SELF.getElementID(_SELF.ElementIDs.BackToResultsButton)).removeClass('back-to-results-show');
        $(_SELF.getElementID(_SELF.ElementIDs.BackToResultsButton)).addClass('back-to-results');

        if (!_SELF.isUndefined(_SELF.map) && _SELF.map != null) {
            _SELF.map.clearOverlays();
            if (_SELF.countryID == 'NZ') {
                _SELF.map.setCentre(_SELF.NZCentre, _SELF.NZZoom);
            } else {
                _SELF.map.setCentre(_SELF.InitialCentre, _SELF.InitialZoom);
            }
        }

        // NOTE that the search page will be as it was left 
        // ... if the advanced search was open it will be open etc.
    },

    /**
    * Performs a call to geocode in order to geocode an address. 
    */
    findAddress: function() {
        var _SELF = this;

        //console.debug('findAddress: countryID=' + _SELF.countryID);


        IsMapSearchActive = false;
        IsMapActive = false;
        var areSearchFieldsValid = _SELF.validateSearchFields();

        if (!areSearchFieldsValid) {
            return;
        }

        // lock down the find button
        $(_SELF.getElementID(_SELF.ElementIDs.SearchButton)).attr('disabled', 'true');
        var target = _SELF.buildAddressSearch();

        _SELF.geocode(target, function(address) {
            _SELF.saveLocationPOI.apply(_SELF, [address]);
            IsSearch = true;
            _SELF.findNearest(address, IsMapSearchActive);
        });
    },

    getResultSummary: function(productsearch) {
        var _SELF = this;

        // HACK
        if (productsearch || (!productsearch && document.getElementById('storeID').value == 'CC')) {
            if ($(_SELF.getElementID(_SELF.ElementIDs.CheckAll)).attr("checked")) {
                return "All";
            }
        }

        var items = "";

        var maxfilters = _SELF.category_filters.length;
        var filters = _SELF.getSearchFiltersJSON().split(" ");

        if (productsearch) {
            for (var i = 0; i < filters.length; i++) {
                if (items.length > 0) {
                    items += ", ";
                }

                var index = parseInt(filters[i]);
                if (isNaN(index)) {
                    // if the number did not parse discard it and continue
                    continue;
                }
                items += _SELF.category_filters[index - 1];
            }
        } else {
            for (var i = 0; i < filters.length; i++) {
                if (items.length > 0) {
                    items += ", ";
                }

                var retailerID = parseInt(filters[i]);
                if (isNaN(retailerID)) {
                    // if the number did not parse discard it and continue
                    continue;
                }

                var found = false;
                // where index is the retailer ID
                for (var n = 0; n < _SELF._retailers.length; n++) {
                    var r = _SELF._retailers[n];
                    if (r.RETAILERID == retailerID) {
                        found = true;
                        items += r.RETAILERNAME;
                    }
                }

                //if (!found) { Logger.log('retailer ID:{0} was not found'.format(retailerID.toString())); }
            }
        }

        return items;
    },


    /**
    * Calls findnearest.ashx passing X/Y and search filters. Results are displayed.
    */
    findNearest: function(address, IsMapSearchActive) {
        var _SELF = this;
        var Lat = '';
        var Long = '';
        var storeType = '';
        var LocTxt = '';
        var prodID = document.getElementById('prodID').value;

        if ($(this.getElementID(this.ElementIDs.CategorySearchTrigger)).attr("checked")) {
            storeType = "category";
        } else if ($(this.getElementID(this.ElementIDs.RetailerSearchTrigger)).attr("checked")) {
            storeType = "retailer";
        };

        // this causes the sidebar to subtly widen or move right
        $(_SELF.getElementID(_SELF.ElementIDs.Search)).hide();
        $(_SELF.getElementID(_SELF.ElementIDs.Results)).show();

        Lat = address.Position.Latitude;
        Long = address.Position.Longitude;

        var json_filters = _SELF.getSearchFiltersJSON();

        //console.debug("findnearest.ashx?x={0}&y={1}&storeType={3} &filter={2} &prodID={4}".format(Long, Lat, json_filters, storeType, prodID));
        $.getJSON("findnearest.ashx?x={0}&y={1}&storeType={2}&filter={3}&prodID={4}".format(Long, Lat, storeType, json_filters, prodID),
            function(data) {

                // unlock down the find button
                $(_SELF.getElementID(_SELF.ElementIDs.SearchButton)).attr('disabled', '');
                var searchedAddress = null;

                if (data.Code > 0) {
                    IsSearch = false;
                    _SELF.displayException.apply(_SELF, [data.Message]);
                    _SELF.reset();
                    return;
                } else {

                _SELF._pois = new Array();
                _SELF.map.clearOverlays();

                    $(_SELF.getElementID(_SELF.ElementIDs.DrivingDirections)).hide("slow");
                    $(_SELF.getElementID(_SELF.ElementIDs.POIResults)).show("slow");
                    $(_SELF.getElementID(_SELF.ElementIDs.ItemsFound)).show("slow");
                    $(_SELF.getElementID(_SELF.ElementIDs.ItemsFound)).html(_SELF.Strings.Searching);
                    $(_SELF.getElementID(_SELF.ElementIDs.POIResults)).html("");

                    if (!IsMapActive && _SELF.searchActive) {
                        searchedAddress = new String(
                            (!_SELF.isUndefined(address.Locality) && address.Locality != '' ? address.Locality.toProperCase() + ' ' : '') +
                            (!_SELF.isUndefined(address.Region) && address.Region != '' ? address.Region + ' ' : '') +
                            (!_SELF.isUndefined(address.PostalCode) && address.PostalCode != '' ? address.PostalCode : '')
                        );

                        if (!$(_SELF.getElementID(_SELF.ElementIDs.stepTwo)).is(":visible") && storeType == "category") {
                            $(_SELF.getElementID(_SELF.ElementIDs.CategoryShow)).click(function() {
                                $(_SELF.getElementID(_SELF.ElementIDs.searchBtns)).toggle();
                                $(_SELF.getElementID(_SELF.ElementIDs.stepOne)).toggle();
                            });
                        } else if (!$(_SELF.getElementID(_SELF.ElementIDs.stepTwo)).is(":visible")) {
                            $(_SELF.getElementID(_SELF.ElementIDs.RetailerShow)).click(function() {
                                $(_SELF.getElementID(_SELF.ElementIDs.searchBtns)).toggle();
                                $(_SELF.getElementID(_SELF.ElementIDs.stepOne)).toggle();
                            });
                        }
                    }

                    // Defined arrays to sort Rank number
                    var poiRank = new Array();
                    var poiRankSorted = new Array();
                    var poiRankUnique = new Array();
                    var id = '';
                    var poiID = '0';

                    // Take rank for each poi
                    $.each(data.items, function(i, poi) {
                        poiRank[i] = poi.Rank;
                    });

                    // function to order rank by number
                    function sortNumber(a, b) {
                        return a - b;
                    }

                    // call function to sort rank by number
                    poiRankSorted = (poiRank.sort(sortNumber));

                    // find unique values in array
                    for (i = 0; i < poiRankSorted.length; i++) {
                        if (id == '') {
                            id = poiRankSorted[i];
                            poiRankUnique[poiID] = poiRankSorted[i];
                            poiID++;
                        } else if (id != poiRankSorted[i]) {
                            poiRankUnique[poiID] = poiRankSorted[i];
                            poiID++;
                            id = poiRankSorted[i];
                        }
                    }
                    id = 0;

                    // data reorder by rank must be done here before pagination
                    var rankSortedData = [];

                    // MS - Bec did a version of this. The SQL query does not come back to here
                    // ordered by rank ... for some reason.

                    //Loop through each rank number and add them to the page
                    for (poiID = 0; poiID < poiRankUnique.length; poiID++) {
                        $.each(data.items, function(i, poi) {
                            if (poi.Rank == poiRankUnique[poiID]) {
                                rankSortedData.push(this);
                            }
                        });
                    }

                    //space delimited list of category_id ... render this into a message

                    var products_or_retailers = _SELF.getResultSummary((storeType == "category") ? true : false);
                    if (products_or_retailers == '' && _SELF._param_retailer != '') {
                        // is there a param retailer
                        products_or_retailers = _SELF._param_retailer;
                    }

                    //console.debug('products_or_retailers=' + products_or_retailers);
                    var locationSearched = (!_SELF.isUndefined(address.Locality) && address.Locality != '') ? address.Locality.toProperCase() : ''; ;
                    if (locationSearched.length != 0) {
                        locationSearched += ", ";
                    }

                    locationSearched += (!_SELF.isUndefined(address.PostalCode) && address.PostalCode != '') ? address.PostalCode : '';

                    // omniture tracking
                    typeof storeLocatorDetails == "function" && storeLocatorSearch(locationSearched,
                                                                    (storeType == "retailer") ? "Retailer" : "Product",
                                                                    products_or_retailers,
                                                                    data.items.length)

                    var subjects = (storeType == "retailer") ? "retailers" : "products";
                    if (document.getElementById('storeID').value == 'CC') {
                        subjects = 'practices';
                    }

                    var tmp = "{0} {1} found for '{2}', in {3} {4}.".format(data.items.length.toString(),
                    (data.items.length > 1) ? "Results" : "Result",
                    (searchedAddress == null) ? "" : searchedAddress,
                    (products_or_retailers) ? "'" + products_or_retailers + "'" : '',
                    subjects);

                    if (tmp.length > 112) {
                        _SELF._resulthint = tmp;
                        // truncate at 112
                        tmp = tmp.substring(0, 112);
                        // add ellipsis
                        tmp += '...';

                        $('#itemsfound').mouseenter(function() {
                            // show or fade inn hint text
                            $(this).attr('title', _SELF._resulthint);
                            //$(this).trigger('hover');

                            $(this).css('cursor', 'pointer');
                        });

                        $('#itemsfound').mouseleave(function() {
                            // Hide or fade out hinttext
                            $(this).attr('title', '');
                            $(this).css('cursor', 'default');
                        });

                    } else {
                        _SELF._resulthint = '';
                    }

                    var msg = "<table style='padding-left:3px;'><tr style='height:30px;'><td style='vertical-align:middle;width:388px;height:30px;'>" + tmp + "</td></tr></table>";

                    _SELF.setResultPagination(searchedAddress, rankSortedData, msg);

                    if ($(_SELF.getElementID(_SELF.ElementIDs.NewSearchButton)).hasClass('alternate-newsearchbutton')) {
                        alert('findNearest: hasClass: alternate-newsearchbutton');
                    }

                    $(_SELF.getElementID(_SELF.ElementIDs.Search)).hide();
                    $(_SELF.getElementID(_SELF.ElementIDs.SideBarFooter)).show();

                    if (!IsMapSearchActive) {
                        //_SELF.map.loadBestView(new MapDS.LatLng(address.Position.Latitude, address.Position.Longitude));
                        _SELF.saveRouteStartPOI.apply(_SELF, [address]);
                    }
                    //}
                }
            });
        //});
    },

    // find nearst POIs to a point
    findPOIs: function() {
    },

    /**
    * Performs a call to Geocode an address. If a single match is found then the method 
    * will automatically call findNearest. Multiple matches are displayed within a 
    * dialog for the user to select.
    */
    geocode: function(addressToGeocode, loadAddressCallBack) {

        // make jQuery Ajax call...
        var _SELF = this;
        _SELF.geocoder.getLocations(addressToGeocode, function(result) {
            if (result.Code === 1) {
                loadAddressCallBack(result.Locations[0]);
            } else if (result.Code === 100) {
                _SELF._foundLocations = result.Locations;
                $(_SELF.getElementID(_SELF.ElementIDs.MultipleAddressDialog)).find(
                    _SELF.getElementID(_SELF.ElementIDs.MultipleAddresses)).html('');
                $("<option/>").attr('value', '0').html(_SELF.Strings.MultipleAddressPrompt).appendTo(
                    $(_SELF.getElementID(_SELF.ElementIDs.MultipleAddressDialog)).find(
                        _SELF.getElementID(_SELF.ElementIDs.MultipleAddresses)));
                $.each(result.Locations, function(i, address) {
                    $("<option/>").html((address.AddressLine != '' ? address.AddressLine + ', ' : '') +
                        address.Locality + ', ' + address.Region + ', ' + address.PostalCode).appendTo(
                            $(_SELF.getElementID(_SELF.ElementIDs.MultipleAddressDialog)).find(
                        _SELF.getElementID(_SELF.ElementIDs.MultipleAddresses)));
                });
                $(_SELF.getElementID(_SELF.ElementIDs.MultipleAddressDialog)).dialog('open');
            } else if (result.Code === 110) {
                _SELF.displayException("<p class='errorheader'></p> We were unable to find the location specified. Please try new information");
                $(_SELF.getElementID(_SELF.ElementIDs.SearchButton)).attr('disabled', '');
            } else if (result.Code > 100) {
                _SELF.displayException(result.Message);
                $(_SELF.getElementID(_SELF.ElementIDs.SearchButton)).attr('disabled', '');
            }
        });
    },

    /// Executes a request for driving directions for the given POI id.
    getDirections: function(id) {
        var _SELF = this;
        _SELF.routeType = 'trip';
        _SELF.map.clearOverlays();
        if (_SELF.map.hasVisiblePopup()) { _SELF.map.removePopups(); }

        if (!_SELF.isUndefined(_SELF._pois) && _SELF._pois.length >= id) {
            id -= 1; // decrement to get array position
            _SELF.directionsHelper.clear();

            var stSuburb = '';
            var stPostcode = '';
            var st = (_SELF._lastSearchedLocation.Position instanceof MapDS.LatLng ? _SELF._lastSearchedLocation.Position : new MapDS.LatLng(_SELF._lastSearchedLocation.Position.Latitude, _SELF._lastSearchedLocation.Position.Longitude));
            var ed = (_SELF._pois[id].Position instanceof MapDS.LatLng ? _SELF._pois[id].Position : new MapDS.LatLng(_SELF._pois[id].Position.Latitude, _SELF._pois[id].Position.Longitude));
            _SELF.map.addOverlay(_SELF._pois[id].Marker);
            _SELF.processLocationPOI(_SELF._lastSearchedLocation);

            if (this.RouteMode === 1) {

                $(_SELF.getElementID(_SELF.ElementIDs.Results)).hide();
                var enddetailprint = $(_SELF.getElementID(_SELF.ElementIDs.EndDetailPrint));
                var enddetail = $(_SELF.getElementID(_SELF.ElementIDs.EndDetail));
                var stTitle = $(_SELF.getElementID(_SELF.ElementIDs.StartTitle));
                var stAddress = ((_SELF._lastSearchedLocation.AddressLine != '' && !_SELF.isUndefined(_SELF._lastSearchedLocation.AddressLine)) ? _SELF._lastSearchedLocation.AddressLine() + ', ' : '');
                var txtSuburb = $(this.getElementID(this.ElementIDs.SearchSuburb));

                // full detail .eg
                // 11. Freedom - Melbourne
                //     13 Upper Terrace, Melboune VIC 3000
                //     Ph: 03 8664 4300                             freedom logo here
                //     www link

                var http = "http://";
                var poi = _SELF._pois[id];

                var div = $('<div></div>');
                var header = $('<div class="header" style="border-bottom:none;">' + poi.Description + '</div>').appendTo(div); ;

                var suburbstatepostcode = (!_SELF.isUndefined(poi.Suburb) && poi.Suburb != '') ? poi.Suburb.toProperCase() : '';

                if (suburbstatepostcode.length > 0) {
                    suburbstatepostcode += ', ';
                }
                suburbstatepostcode += (!_SELF.isUndefined(poi.State) && poi.State != '') ? ' ' + poi.State.toProperCase() : '';

                if (suburbstatepostcode.length > 0) {
                    suburbstatepostcode += ', ';
                }
                suburbstatepostcode += (!_SELF.isUndefined(poi.Postcode) && poi.Postcode != '') ? ' ' + poi.Postcode.toProperCase() : '';

                var detailhtml = '<div class="detail" style="display:block;height:65px;">';
                detailhtml += '<div class="detail-address">';
                detailhtml += '<table><tr><td>';

                // street prefix, street, street suffix, suburb, postcode 
                detailhtml += '<p>{0}{1}{2}<br>{3}</p>'.format(
                    (!_SELF.isUndefined(poi.StreetPrefix) && poi.StreetPrefix != '') ? poi.StreetPrefix.toProperCase() + '</br>' : '',
                    (!_SELF.isUndefined(poi.Street) && poi.Street != '') ? poi.Street.toProperCase() : '',
                    (!_SELF.isUndefined(poi.StreetSuffix) && poi.StreetSuffix != '') ? ' ' + poi.StreetSuffix.toProperCase() : '',
                    suburbstatepostcode);

                // phone, URL
                detailhtml += '<p>{0}<br>{1}</p>'.format(
                    (!_SELF.isUndefined(poi.Phone) && poi.Phone != '') ? 'Ph: ' + poi.Phone : '',
                    (!_SELF.isUndefined(poi.URL) && poi.URL != '') ? '<a  class="wwwlink" href="' + http + poi.URL + ' " target="_blank">' + poi.URL + '</a> ' : '');

                detailhtml += '</div>'; // address div
                detailhtml += '</td><td>';

                // logo
                detailhtml += '<div class="detail-logo">{0}</div>'.format(
                    (poi.RETAILERID != '' && !_SELF.isUndefined(poi.RETAILERID) && !_SELF.isUndefined(poi.Logo) && poi.Logo == 'Y') ? '<img src="http://www.gemoney.com.au/common/locator/' + poi.RETAILERID + '.gif" alt="Logo" />' : '');

                detailhtml += '</td></tr></table>';
                detailhtml += '</div>'; // detail div
                var detail = $(detailhtml);
                detail.appendTo(div);
                enddetail.html(div.html());

                // print logo here
                $(enddetailprint).html('<div class="directions-print"><a class="wwwlink" href="javascript:window.print();"><img alt="Print" style="margin-top:3px;float:right;" title="Print" src="images/Print.png" style="margin-right:3px;float:right;"/></a></div>');

                // TODO this is wrong when the search is a param search ... WHY?

                var start = '';
                if (!_SELF.isUndefined(_SELF._lastSearchedLocation.Locality) &&
                    _SELF._lastSearchedLocation.Locality != '') {
                    start = _SELF._lastSearchedLocation.Locality.toProperCase();
                } else if (!_SELF.isUndefined(_SELF._lastSearchedLocation.PostalCode) &&
                    _SELF._lastSearchedLocation.PostalCode != '') {
                    start = _SELF._lastSearchedLocation.PostalCode;
                }

                $(stTitle).html($('<h5 />'.format(id)).html('<div style="font-size:11px;font-weight:bold;">From "{0}" to {1}</div>'.format(
                    start,
                    ((_SELF._pois[id].Description != '' && !_SELF.isUndefined(_SELF._pois[id].Description)) ? _SELF._pois[id].Description : '')
                )));



                //Logger.log('getDirections: alternate-newsearchbutton');

                $(_SELF.getElementID(_SELF.ElementIDs.ResultsPrevNext)).show();

                $(_SELF.getElementID(_SELF.ElementIDs.NewSearchButton)).removeClass('newsearchbutton');
                $(_SELF.getElementID(_SELF.ElementIDs.NewSearchButton)).addClass('alternate-newsearchbutton');

                // Logger.log('getDirections: back-to-results-show');
                $(_SELF.getElementID(_SELF.ElementIDs.BackToResultsButton)).removeClass('back-to-results');
                $(_SELF.getElementID(_SELF.ElementIDs.BackToResultsButton)).addClass('back-to-results-show');
                //$(_SELF.getElementID(_SELF.ElementIDs.BackToResultsButton)).show();

                var edTitle = $(_SELF.getElementID(_SELF.ElementIDs.EndTitle));
                edTitle.html($('<h5 />'.format(id)).html('<div style="font-size:11px;font-weight:bold;">End: {0}{1}{2}{3}{4}</div>'.format(
                    ((_SELF._pois[id].Description != '' && !_SELF.isUndefined(_SELF._pois[id].Description)) ? _SELF._pois[id].Description + ', ' : ''),
                    ((_SELF._pois[id].Street != '' && !_SELF.isUndefined(_SELF._pois[id].Street)) ? _SELF._pois[id].Street + ', ' : ''),
                    ((_SELF._pois[id].Suburb != '' && !_SELF.isUndefined(_SELF._pois[id].Suburb)) ? _SELF._pois[id].Suburb + ', ' : ''),
                    ((_SELF._pois[id].Postcode != '' && !_SELF.isUndefined(_SELF._pois[id].Postcode)) ? _SELF._pois[id].Postcode + ', ' : ''),
                    ((_SELF._pois[id].State != '' && !_SELF.isUndefined(_SELF._pois[id].State)) ? _SELF._pois[id].State : '')
                )));

                $(_SELF.getElementID(_SELF.ElementIDs.Results)).hide("slow");
                $(_SELF.getElementID(_SELF.ElementIDs.ItemsFound)).hide();
                $(_SELF.getElementID(_SELF.ElementIDs.ResultsPrevNext)).hide();

                var dd = $(_SELF.getElementID(_SELF.ElementIDs.DrivingDirections));
                var ddList = $(_SELF.getElementID(_SELF.ElementIDs.DrivingDirectionsList));
                ddList.html('<p><img src="./images/loading-circle-black.gif" alt="Loading" height="16px" width="16px" /> Loading</p>');
                _SELF.directionsHelper.buildFromWaypoints([st, ed]);
                if (dd.is(":hidden")) { $(_SELF.getElementID(_SELF.ElementIDs.DrivingDirections)).show("slow"); }

            }
        }
    },

    /**
    * Creates a callback function that each marker will have in order to fire a route build request.
    */
    createRouteCallback: function(poi, startMarker) {
        var _SELF = this;
        if (this.RouteMode == 1 && !route) {
            return (function() {
                route = true;
                var listCaption = new String(
                ($(_SELF.getElementID(_SELF.ElementIDs.streetHidden)).val() != '' ? $(_SELF.getElementID(_SELF.ElementIDs.streetHidden)).val() + ' ' : '') +
                ($(_SELF.getElementID(_SELF.ElementIDs.suburbHidden)).val() != '' ? $(_SELF.getElementID(_SELF.ElementIDs.suburbHidden)).val() + ' ' : '') +
                ($(_SELF.getElementID(_SELF.ElementIDs.postcodeHidden)).val() != '' ? $(_SELF.getElementID(_SELF.ElementIDs.postcodeHidden)).val() + ' ' : '') +
                ($(_SELF.getElementID(_SELF.ElementIDs.stateHidden)).val() != '' ? $(_SELF.getElementID(_SELF.ElementIDs.stateHidden)).val() + ' ' : '')
            ); listCaption = listCaption.substr(0, listCaption.lastIndexOf(', '));

                _SELF.buildRoute({
                    from: { caption: listCaption, position: _SELF._routeStart.Position },
                    to: { caption: _SELF.buildRouteCaption(poi), position: poi.Position }
                }, startMarker, poi.Marker, this);
                return false;
            });
        } else {
            // TODO: slot in code here for allowing custom starting address.
        }
    },

    /**
    * This method calls for a route to be built. The result is handled and a lot of processing occurs here in order to reformat the returned 
    * route information into a nice list.
    */
    buildRoute: function(routeRequest, startMarker, endMarker, srcImageLink) {
        var _SELF = this;
        if (typeof routeRequest != "object") {
            throw "Invalid route request.";
        }
        if (!(startMarker instanceof MapDS.Maps.Marker)) {
            if (!(_SELF.locationMarker instanceof MapDS.Maps.Marker)) {
                throw "Invalid start marker.";
            }
            startMarker = _SELF.locationMarker;
        }
        if (!(endMarker instanceof MapDS.Maps.Marker)) {
            throw "Invalid end marker.";
        }
        if (srcImageLink && _SELF.isImage(srcImageLink)) {
            // change icon image to loading image
            srcImageLink.src = _SELF.Images.Loading;
        }
        // possibly need to look at generic approach here - use wp instead of s/e
        $.getJSON("routebuilder.ashx?s={0},{1}&e={2},{3}&co={4}".format(
            routeRequest.from.position.Latitude,
            routeRequest.from.position.Longitude,
            routeRequest.to.position.Latitude,
            routeRequest.to.position.Longitude,
            _SELF.countryID
        ),
        function(data) {
            $(_SELF.getElementID(_SELF.ElementIDs.POIResults)).hide("slow");
            $(_SELF.getElementID(_SELF.ElementIDs.ItemsFound)).hide("slow");

            var dd = $('<div></div>');

            $('<h5/>').html("Start: <strong>{0}</strong>".format(routeRequest.from.caption)).appendTo(dd);

            $.each(data.Segments, function(i, segment) {
                var segmentTable = $('<table></table>');
                $.each(segment.Directions, function(i) {
                    // scope of this method is the direction itself.
                    var instruction;
                    var distance = _SELF.round(this.Distance, 2) + 'km';
                    if (i == 0) { // start
                        instruction = 'Head <strong>{0}</strong> on <strong>{1}</strong>'.format(
                            (_SELF.expandBearing(this.Bearing)).toLowerCase(),
                            this.Address.Street
                        );
                    } else if (this.Instruction.toLowerCase() == 'continues as') {
                        instruction = 'Continue along <strong>{0}</strong>'.format(this.Address.Street);
                    } else if (this.Instruction.toLowerCase() == 'finish on') {
                        instruction = this.Instruction + ' <strong>{0}</strong>'.format(this.Address.Street);
                        distance = '';
                    } else {
                        instruction = '{0} at <strong>{1}</strong>'.format(
                            this.Instruction.replace(/left/i, '<strong>left</strong>').replace(/right/i, '<strong>right</strong>'),
                            this.Address.Street
                        );
                    }

                    // NOTE: something here to be done for distances under 100 metres...
                    $('<tr><td>{0}.</td><td>{1}</td><td>{2}</td></tr>'.format((i + 1), instruction, distance)).appendTo(segmentTable);
                });

                $('<tr class="segmentTotal"><td colspan="3">{0}km - {1}</td></tr>'.format(
                        _SELF.round(segment.Distance, 2),
                        _SELF.convertToTime.apply(_SELF, [segment.DrivingTime])
                    )).appendTo(segmentTable);
                segmentTable.appendTo(dd);
            });

            $('<h5/>').html("End: <strong>{0}</strong>".format(routeRequest.to.caption)).appendTo(dd);

            // build the final DD HTML
            $('<h3>Driving Directions</h3>').appendTo(_SELF.getElementID(_SELF.ElementIDs.DrivingDirections));

            // build the route object
            var myRoute = new MapDS.Route(null, data.MapFileName, new MapDS.Bounds(data.Bounds.Left, data.Bounds.Bottom, data.Bounds.Right, data.Bounds.Top));

            // append back link to top of DD
            $('<a class="back"/>').html('Back to results').click(backToSearch).appendTo(_SELF.getElementID(_SELF.ElementIDs.DrivingDirections));

            // append the DDs
            dd.appendTo(_SELF.getElementID(_SELF.ElementIDs.DrivingDirections))

            // append back link to bottom of DD
            $('<a class="back"/>').html('Back to results').click(backToSearch).appendTo(_SELF.getElementID(_SELF.ElementIDs.DrivingDirections));

            $(_SELF.getElementID(_SELF.ElementIDs.DrivingDirections)).show("slow");

            _SELF.map.clearOverlays();

            _SELF.map.addOverlay(startMarker);
            _SELF.map.addOverlay(endMarker);

            // add route to map
            _SELF.map.addRoute(myRoute);
            _SELF.map.loadBestView(null, true);
        });
    },

    // this used to return the user from the directions view to the results list
    // ... now using MoveBackToResult ... and it's incomplete
    backToSearch: function() {
        var _SELF = this;
        _SELF.routeType = 'search';
        _SELF.map.clearOverlays();
        $(_SELF.getElementID(_SELF.ElementIDs.POIResults)).html('');
        $.each(_SELF._pois, function(i, poi) {
            var id = i + 1;
            _SELF.processPOI(id, poi);
            _SELF.map.addOverlay(poi.Marker);
        });

        $(_SELF.getElementID(_SELF.ElementIDs.DrivingDirections)).hide("slow");
        $(_SELF.getElementID(_SELF.ElementIDs.POIResults)).show("slow");
        $(_SELF.getElementID(_SELF.ElementIDs.ItemsFound)).show("slow");

        _SELF.processLocationPOI(_SELF._lastSearchedLocation);
        _SELF.map.loadBestView(null, true);
    },

    MoveBackToResults: function() {
        var _SELF = this;

        // adding the route will have cleared the result page markers
        if (_SELF._lastSelectedResult != null) {
            _SELF.map.clearOverlays();

            _SELF.routeType = 'search';
            try {

                var index = parseInt($(_SELF._lastSelectedResult).attr("id"))
                var pageindex = 0;
                pageindex = Math.ceil(index / _SELF.listview_items_per_page);

                // page 1 includes 1 .. 9
                // page 4 includes 31 .. 40, .etc

                var startindex = (pageindex * _SELF.listview_items_per_page) - (_SELF.listview_items_per_page - 1);
                var endindex = (pageindex * _SELF.listview_items_per_page) // except where the las page does not have the set number of items on 

                if (!_SELF.isUndefined(_SELF._pois)) {
                    for (var i = startindex; i < endindex; i++) {
                        _SELF.map.addOverlay(_SELF._pois[i].Marker);
                    }

                    // last position
                    if (!_SELF.isUndefined(_SELF._lastSearchedLocation) &&
                        _SELF._lastSearchedLocation != null) {
                        _SELF.processLocationPOI(_SELF._lastSearchedLocation);
                    }
                }

            } catch (e) {
                //Logger.log(e);
            }
        }

        // ... manage UI elements
        $(_SELF.getElementID(_SELF.ElementIDs.DrivingDirections)).hide("slow");
        $(_SELF.getElementID(_SELF.ElementIDs.Results)).show("slow");
        $(_SELF.getElementID(_SELF.ElementIDs.ItemsFound)).show("slow");

        $(_SELF.getElementID(_SELF.ElementIDs.ResultsPrevNext)).show("slow");


        //Logger.log('MoveBackToResults: newsearchbutton');

        //$(_SELF.getElementID(_SELF.ElementIDs.NewSearchButton)).toggleClass('newsearchbutton');
        $(_SELF.getElementID(_SELF.ElementIDs.NewSearchButton)).removeClass('alternate-newsearchbutton');
        $(_SELF.getElementID(_SELF.ElementIDs.NewSearchButton)).addClass('newsearchbutton');

        //console.debug('MoveBackToResults: hide');
        //$(_SELF.getElementID(_SELF.ElementIDs.BackToResultsButton)).hide();
        $(_SELF.getElementID(_SELF.ElementIDs.BackToResultsButton)).removeClass('back-to-results-show');
        $(_SELF.getElementID(_SELF.ElementIDs.BackToResultsButton)).addClass('back-to-results');

        // ... reset the map
        IsBackToResults = true;
        //_SELF.map.loadBestView(null, true);
    },


    /*
    * This method is hooked into the window.onload automatically.
    */
    initMap: function(/*lat, lng, zoom*/) {
        var _SELF = this;
        var _sID = $(_SELF.getElementID(_SELF.ElementIDs.storeID)).val();
        //var countryID = $(_SELF.getElementID(_SELF.ElementIDs.countryID)).val();

        _SELF.geocoder.setCountryCode(_SELF.countryID);

        // If the store ID is GECLNZ show Newzealand regions
        if (_SELF.countryID == 'NZ') {
            this.map = new MapDS.Maps.Map(this.getElementID(this.ElementIDs.Map, false));
            this.map.setCentre(this.NZCentre, this.NZZoom);
            List = regions.split(",");

            $('#ddlState >option').remove();
            var myCombo = $(this.getElementID(this.ElementIDs.SearchState));

            for (i = 0; i < List.length; i++) {
                $("<option/>").html(List[i]).appendTo(myCombo);
            }
        } else {
            this.map = new MapDS.Maps.Map(this.getElementID(this.ElementIDs.Map, false));
            this.map.setCentre(this.InitialCentre, this.InitialZoom);
        }

        _SELF._lastCentre = _SELF.map.getCentre();
        _SELF._lastZoom = _SELF.map.getZoom();

        MapDS.Events.addListener(_SELF.map, 'moveend', function(e) {
            var newCentre = _SELF.map.getCentre();
            var mapZoom = this.getZoom();
            var zoomChanged = mapZoom !== _SELF._lastZoom ? true : false;
            var hasMoved = (
                Math.abs(_SELF._lastCentre.Longitude() - newCentre.Longitude()) > 0.005 ||
                Math.abs(_SELF._lastCentre.Latitude() - newCentre.Latitude()) > 0.005
            ) ? true : false;

            var latitude = newCentre.Latitude();
            var longitude = newCentre.Longitude();
            var address = new Object();
            var Position = new Object();

            address = {
                Position: { Latitude: latitude, Longitude: longitude }
            }

            if ((hasMoved || zoomChanged)) {

                // search centre point may no longer be valid because of a pan/zoom

                _SELF._lastCentre = newCentre;
                _SELF._lastZoom = mapZoom;
                if (_SELF.routeType == 'search' && !_SELF.map.hasVisiblePopup() && !_SELF.searchClear && !_SELF.searchActive) {
                    var IsMapSearchActive = true;
                    if (paginating) {
                        paginating = false;
                    } else {
                        // may need to find the centre marker and remove it
                        //_SELF._lastSearchedLocation = null;


                        IsSearch = false;
                        IsBackToResults = false;
                        _SELF.findNearest(address, IsMapSearchActive);
                    }
                }
                _SELF.searchClear = false;
                _SELF.searchActive = false;
            }
        });
        _SELF.directionsHelper = new MapDS.Maps.Directions(_SELF.map, (_SELF.ElementIDs.DrivingDirectionsList ? document.getElementById(_SELF.ElementIDs.DrivingDirectionsList) : null));
    },

    // Set the center of the map and zoom level
    setMapCentre: function(lat, lng) {
        this.map.setCentre(new MapDS.LatLng(lat, lng), 16);
    },

    /**
    * The main initialisation method for the Locator object.
    */
    /*
    */

    // rough and resady display to be used at start up when category values
    // are found on the query string
    displayCategorySearch: function(slow, high, rlow) {
        var _SELF = this;
        $(_SELF.getElementID(_SELF.ElementIDs.RetailerSearch)).css("display", "none");
        $(_SELF.getElementID(_SELF.ElementIDs.RetailerFilterGroup)).css("top", rlow);
        $(_SELF.getElementID(_SELF.ElementIDs.RetailerSearchTrigger)).attr("checked", "");
        $(_SELF.getElementID(_SELF.ElementIDs.CategorySearchTrigger)).attr("checked", "checked");
        $(_SELF.getElementID(_SELF.ElementIDs.CategorySearch)).css("display", "block");

        $(_SELF.getElementID(_SELF.ElementIDs.SearchDiv)).css("top", slow);
        $(_SELF.getElementID(_SELF.ElementIDs.SearchFilters)).css("display", "block");
        $(_SELF.getElementID(_SELF.ElementIDs.AdvancedSearchLink)).text('Simple Search');

        $(_SELF.getElementID(_SELF.ElementIDs.HomeUlDiv)).hide();
        $(_SELF.getCollapse('#catHome-row')).css("display", "none");
        $(_SELF.getExpand('#catHome-row')).css("display", "block");

        $(_SELF.getElementID(_SELF.ElementIDs.HealthUlDiv)).hide();
        $(_SELF.getCollapse('#catHealth-row')).css("display", "none");
        $(_SELF.getExpand('#catHealth-row')).css("display", "block");

        $(_SELF.getElementID(_SELF.ElementIDs.OtherUlDiv)).hide();
        $(_SELF.getCollapse('#catOther-row')).css("display", "none");
        $(_SELF.getExpand('#catOther-row')).css("display", "block");

    },
    // rough and resady display to be used at start up when retailer values
    // are found on the query string
    displayRetailerSearch: function(low, high) {
        var _SELF = this;
        $(_SELF.getElementID(_SELF.ElementIDs.CategorySearch)).css("display", "none");
        $(_SELF.getElementID(_SELF.ElementIDs.CategorySearchTrigger)).attr("checked", "");
        $(_SELF.getElementID(_SELF.ElementIDs.RetailerSearchTrigger)).attr("checked", "checked");
        $(_SELF.getElementID(_SELF.ElementIDs.RetailerSearch)).css("display", "block");
        $(_SELF.getElementID(_SELF.ElementIDs.RetailerFilterGroup)).css("top", high);
        $(_SELF.getElementID(_SELF.ElementIDs.SearchDiv)).css("top", low);
        $(_SELF.getElementID(_SELF.ElementIDs.SearchFilters)).css("display", "block");
        $(_SELF.getElementID(_SELF.ElementIDs.AdvancedSearchLink)).text('Simple Search');
    },
    getExpand: function(cat) {
        var expand = $($(cat).children().get(1)).children().get(0);
        return expand;
    },
    getCollapse: function(cat) {
        var collapse = $($(cat).children().get(2)).children().get(0);
        return collapse;
    },
    init: function(options) {
        var _SELF = this;

        if (typeof console == "undefined") var console = { log: function() { } };

        var routeType = 'search';
        var searchActive = false;
        var searchClear = false;
        $().ready(function() {

            _SELF.countryID = $(_SELF.getElementID(_SELF.ElementIDs.countryID)).val();

            // set up the category filters
            // ... the order here represents the category index value - 1
            // ... when referencing this as zero based use category_ID - 1 

            if (document.getElementById('storeID').value == 'CC') {
                $(_SELF.getElementID(_SELF.ElementIDs.RetailerLabel)).text('Or choose one of the major practices');
            }

            _SELF.category_filters.push("Bedding");
            _SELF.category_filters.push("Computers");
            _SELF.category_filters.push("Fitness");
            _SELF.category_filters.push("Furniture");
            _SELF.category_filters.push("Jewellery");
            _SELF.category_filters.push("Tyres");
            _SELF.category_filters.push("Electrical");
            _SELF.category_filters.push("Flooring/carpets");
            _SELF.category_filters.push("Renovations");
            _SELF.category_filters.push("Sporting");
            _SELF.category_filters.push("Home improvement");
            _SELF.category_filters.push("Other");
            _SELF.category_filters.push("Outdoor");
            _SELF.category_filters.push("Dental");
            _SELF.category_filters.push("Vision care");
            _SELF.category_filters.push("Veterinary");
            _SELF.category_filters.push("Audiology");
            _SELF.category_filters.push("Orthodontic");
            _SELF.category_filters.push("Cosmetic non-surgical");
            _SELF.category_filters.push("Stationery");

            //catHome
            $(_SELF.getElementID(_SELF.ElementIDs.CatHome)).click(function() {
                var homeplus = _SELF.getExpand('#catHome-row');
                var homeminus = _SELF.getCollapse('#catHome-row');

                if ($(_SELF.getElementID(_SELF.ElementIDs.HomeUlDiv)).css("display") == "none") {
                    $(_SELF.getElementID(_SELF.ElementIDs.HomeUlDiv)).slideDown();
                    if (!_SELF.useCategoryExclusions) { $(_SELF.getElementID(_SELF.ElementIDs.HealthUlDiv)).slideUp(); }
                    $(_SELF.getElementID(_SELF.ElementIDs.OtherUlDiv)).slideUp();

                    // cathome icon to minimise
                    $(homeplus).css("display", "none");
                    $(homeminus).css("display", "block");

                    // cathealth icon to maximise
                    if (!_SELF.useCategoryExclusions) {
                        $(_SELF.getExpand('#catHealth-row')).css("display", "block");
                        $(_SELF.getCollapse('#catHealth-row')).css("display", "none");
                    }

                    $(_SELF.getExpand('#catOther-row')).css("display", "block");
                    $(_SELF.getCollapse('#catOther-row')).css("display", "none");

                } else {
                    $(_SELF.getElementID(_SELF.ElementIDs.HomeUlDiv)).slideUp();

                    // cathome icon to plus
                    $(homeplus).css("display", "block");
                    $(homeminus).css("display", "none");
                }
            });

            //catHealth
            $(_SELF.getElementID(_SELF.ElementIDs.CatHealth)).click(function() {
                if (!_SELF.useCategoryExclusions) {
                    var healthplus = _SELF.getExpand('#catHealth-row');
                    var healthminus = _SELF.getCollapse('#catHealth-row');

                    if ($(_SELF.getElementID(_SELF.ElementIDs.HealthUlDiv)).css("display") == "none") {
                        $(_SELF.getElementID(_SELF.ElementIDs.HealthUlDiv)).slideDown();
                        $(_SELF.getElementID(_SELF.ElementIDs.HomeUlDiv)).slideUp();
                        $(_SELF.getElementID(_SELF.ElementIDs.OtherUlDiv)).slideUp();

                        // cathealth icon to minise
                        $(healthplus).css("display", "none");
                        $(healthminus).css("display", "block");

                        // cathome icon to maximise
                        $(_SELF.getExpand('#catHome-row')).css("display", "block");
                        $(_SELF.getCollapse('#catHome-row')).css("display", "none");

                        // catother to maximise
                        $(_SELF.getExpand('#catOther-row')).css("display", "block");
                        $(_SELF.getCollapse('#catOther-row')).css("display", "none");

                    } else {
                        $(_SELF.getElementID(_SELF.ElementIDs.HealthUlDiv)).slideUp();

                        // cathealth icon to plus
                        $(healthplus).css("display", "block");
                        $(healthminus).css("display", "none");
                    }
                }
            });

            //catOther
            $(_SELF.getElementID(_SELF.ElementIDs.CatOther)).click(function() {
                var otherplus = _SELF.getExpand('#catOther-row');
                var otherminus = _SELF.getCollapse('#catOther-row');

                if ($(_SELF.getElementID(_SELF.ElementIDs.OtherUlDiv)).css("display") == "none") {
                    $(_SELF.getElementID(_SELF.ElementIDs.OtherUlDiv)).slideDown();
                    $(_SELF.getElementID(_SELF.ElementIDs.HomeUlDiv)).slideUp();
                    if (!_SELF.useCategoryExclusions) { $(_SELF.getElementID(_SELF.ElementIDs.HealthUlDiv)).slideUp(); }

                    // catother icon to minus
                    $(otherplus).css("display", "none");
                    $(otherminus).css("display", "block");

                    // cathealth icon to maximise
                    if (!_SELF.useCategoryExclusions) {
                        $(_SELF.getExpand('#catHealth-row')).css("display", "block");
                        $(_SELF.getCollapse('#catHealth-row')).css("display", "none");
                    }

                    // cathome icon to maximise
                    $(_SELF.getExpand('#catHome-row')).css("display", "block");
                    $(_SELF.getCollapse('#catHome-row')).css("display", "none");

                } else {
                    $(_SELF.getElementID(_SELF.ElementIDs.OtherUlDiv)).slideUp();

                    // catother icon to plus
                    $(otherplus).css("display", "block");
                    $(otherminus).css("display", "none");
                }
            });

            var searchdiv_high = "-340px";
            var searchdiv_low = "-38px";

            _SELF.retailergrouptop_low = "300px";
            _SELF.retailergrouptop_high = "80px";

            if ($.browser.msie && $.browser.version == "6.0") {
                _SELF.retailergrouptop_low = "360px";
                _SELF.retailergrouptop_high = "140px";
                searchdiv_high = "-400px";
                searchdiv_low = "0px";
            }

            $(_SELF.getElementID(_SELF.ElementIDs.CategorySearchTrigger)).click(function() {
                if ($(_SELF.getElementID(_SELF.ElementIDs.CategorySearchTrigger)).attr("checked")) {
                    $(_SELF.getElementID(_SELF.ElementIDs.CategorySearch)).css("display", "block");
                    $(_SELF.getElementID(_SELF.ElementIDs.RetailerSearchTrigger)).attr("checked", "");
                    $(_SELF.getElementID(_SELF.ElementIDs.RetailerSearch)).css("display", "none");

                    // slide retailer group check down
                    $(_SELF.getElementID(_SELF.ElementIDs.RetailerFilterGroup)).css("top", _SELF.retailergrouptop_low);
                } else {
                    $(_SELF.getElementID(_SELF.ElementIDs.CategorySearch)).css("display", "none");
                    $(_SELF.getElementID(_SELF.ElementIDs.RetailerSearchTrigger)).attr("checked", "checked");
                    $(_SELF.getElementID(_SELF.ElementIDs.RetailerSearch)).css("display", "block");

                    // slide up retailer group
                    $(_SELF.getElementID(_SELF.ElementIDs.RetailerFilterGroup)).css("top", _SELF.retailergrouptop_high);
                }
            });

            $(_SELF.getElementID(_SELF.ElementIDs.RetailerSearchTrigger)).click(function() {
                if ($(_SELF.getElementID(_SELF.ElementIDs.RetailerSearchTrigger)).attr("checked")) {
                    $(_SELF.getElementID(_SELF.ElementIDs.RetailerSearch)).css("display", "block");
                    $(_SELF.getElementID(_SELF.ElementIDs.CategorySearchTrigger)).attr("checked", "");
                    $(_SELF.getElementID(_SELF.ElementIDs.CategorySearch)).css("display", "none");

                    //slide up retailer group
                    $(_SELF.getElementID(_SELF.ElementIDs.RetailerFilterGroup)).css("top", _SELF.retailergrouptop_high);
                } else {
                    $(_SELF.getElementID(_SELF.ElementIDs.RetailerSearch)).css("display", "none");
                    $(_SELF.getElementID(_SELF.ElementIDs.CategorySearchTrigger)).attr("checked", "checked");
                    $(_SELF.getElementID(_SELF.ElementIDs.CategorySearch)).css("display", "block");

                    // slide down retailer group
                    $(_SELF.getElementID(_SELF.ElementIDs.RetailerFilterGroup)).css("top", _SELF.retailergrouptop_low);
                }
            });

            // maximise the home category
            // without specifically hiding the home div it will show ... 
            // ... however the expand icon will need to be changed for the collapse icon instead

            // cathome icon to minimise
            $(_SELF.getExpand('#catHome-row')).css("display", "none");
            $(_SELF.getCollapse('#catHome-row')).css("display", "block");

            $(_SELF.getElementID(_SELF.ElementIDs.AdvancedSearchLink)).click(function() {
                if ($(_SELF.getElementID(_SELF.ElementIDs.SearchFilters)).css("display") == "none") {
                    $(_SELF.getElementID(_SELF.ElementIDs.SearchFilters)).css("display", "block");

                    // expand which ever type is set either by default or choice
                    if ($(_SELF.getElementID(_SELF.ElementIDs.CategorySearchTrigger)).attr("checked")) {
                        $(_SELF.getElementID(_SELF.ElementIDs.CategorySearch)).css("display", "block");

                        if (!_SELF.useCategoryExclusions) { $(_SELF.getElementID(_SELF.ElementIDs.HealthUlDiv)).slideUp(50); }
                        $(_SELF.getElementID(_SELF.ElementIDs.OtherUlDiv)).slideUp(50);

                        // slide down retailer group
                        $(_SELF.getElementID(_SELF.ElementIDs.RetailerFilterGroup)).css("top", _SELF.retailergrouptop_low);
                        $(_SELF.getElementID(_SELF.ElementIDs.AdvancedSearchLink)).text('Simple Search');

                    } else if ($(_SELF.getElementID(_SELF.ElementIDs.RetailerSearchTrigger)).attr("checked")) {
                        $(_SELF.getElementID(_SELF.ElementIDs.RetailerSearch)).css("display", "block");

                        // slide up retailer group
                        $(_SELF.getElementID(_SELF.ElementIDs.RetailerFilterGroup)).css("top", _SELF.retailergrouptop_high);
                    }

                    $(_SELF.getElementID(_SELF.ElementIDs.SearchDiv)).css("top", searchdiv_low);
                } else {
                    $(_SELF.getElementID(_SELF.ElementIDs.SearchFilters)).css("display", "none");
                    $(_SELF.getElementID(_SELF.ElementIDs.CategorySearch)).css("display", "none");
                    $(_SELF.getElementID(_SELF.ElementIDs.RetailerSearch)).css("display", "none");
                    $(_SELF.getElementID(_SELF.ElementIDs.SearchDiv)).css("top", searchdiv_high);

                    // slide down retailer group
                    $(_SELF.getElementID(_SELF.ElementIDs.RetailerFilterGroup)).css("top", _SELF.retailergrouptop_low);
                    $(_SELF.getElementID(_SELF.ElementIDs.AdvancedSearchLink)).text('Advanced Search');

                    // reset
                    _SELF.reset();
                }
            });

            $(_SELF.getElementID(_SELF.ElementIDs.BackToResultsButton)).click(function() {
                _SELF.MoveBackToResults();
            });

            // Grab all anchor elements on the page that have an href and target is external. Set their target to blank.
            $('a[rel="external"]').filter('[href!=""]').each(function() { this.target = "_blank"; });

            $(_SELF.getElementID(_SELF.ElementIDs.SearchButton)).click(function() {
                Locator.findAddress();
                _SELF.routeType = 'search';
                _SELF.searchActive = true;
            });

            $(_SELF.getElementID(_SELF.ElementIDs.NewSearchButton)).click(function() {
                Locator.reset();
            });

            // need to have the current text blanked on focus, reset on blur...
            $(_SELF.getElementID(_SELF.ElementIDs.Search) + ' input[title!=""]').keypress(
                function(evt) {
                    _SELF._lastFieldFocussed = this;
                    if (evt.keyCode == 13) {
                        $(_SELF.getElementID(_SELF.ElementIDs.SearchButton)).click();
                    }
                }
            ).hint();

            // ensure that Enter presses on the form don't cause a submit
            $("form").keypress(function(e) { if (e.keyCode == 13) { return false; } });

            // attach the exception dialog
            $(_SELF.getElementID(_SELF.ElementIDs.ExceptionDialog)).dialog({
                bgiframe: true,
                modal: true,
                draggable: false,
                resizable: false,
                autoOpen: false,
                close: function(evt, ui) {
                    if (_SELF._lastFieldFocussed) {
                        _SELF._lastFieldFocussed.focus();
                    }
                },
                buttons: {
                    Ok: function() {
                        $(this).dialog('close');
                    }
                }
            });

            // attach the multiple results dialog.
            $(_SELF.getElementID(_SELF.ElementIDs.MultipleAddressDialog)).dialog({
                bgiframe: true,
                height: 300,
                width: 400,
                modal: true,
                draggable: false,
                resizable: false,
                autoOpen: false,
                zIndex: 99999,
                buttons: {
                    'Use Address': function() {
                        var idx = $(this).find(_SELF.getElementID(_SELF.ElementIDs.MultipleAddresses)).attr('selectedIndex');
                        if (!_SELF.isUndefined(idx) && idx != null && idx != 0) {
                            // go back one to get correct array location.
                            idx--;
                            // Call FindNearest....
                            _SELF._lastSearchedLocation = _SELF._foundLocations[idx];
                            _SELF.findNearest(_SELF._foundLocations[idx], false);
                        }
                        $(this).dialog('close');
                    },
                    'Cancel': function() {
                        $(this).dialog('close');
                    }

                }
            });

            // default to category
            $(_SELF.getElementID(_SELF.ElementIDs.CategorySearchTrigger)).attr("checked", "checked");
            qs = $.getUrlVars();

            if (_SELF.countryID == "NZ") {
                txtSuburb = $(_SELF.getElementID(_SELF.ElementIDs.SearchSuburbNZ));
            } else {
                txtSuburb = $(_SELF.getElementID(_SELF.ElementIDs.SearchSuburb));
            }

            if (qs.length > 1) {
                if ((!_SELF.isUndefined(qs['suburb']) && qs['suburb'] != '') &&
                    !_SELF.isUndefined(qs['postcode']) && qs['postcode'] != '') {
                    $(txtSuburb).val(qs['suburb'].toProperCase() + ' ' + qs['postcode']);
                } else if (!_SELF.isUndefined(qs['suburb']) && qs['suburb'] != '') {
                    $(txtSuburb).val(qs['suburb']);
                } else if (!_SELF.isUndefined(qs['postcode']) && qs['postcode'] != '') {
                    $(txtSuburb).val(qs['postcode']);
                }

                // load state
                if (qs['state'] != '' && !_SELF.isUndefined(qs['state'])) {
                    $(_SELF.getElementID(_SELF.ElementIDs.SearchState)).val(qs['state'].toUpperCase());
                } else if (qs['region'] != '' && !_SELF.isUndefined(qs['region'])) {
                    $(_SELF.getElementID(_SELF.ElementIDs.SearchState)).val(qs['region'].toUpperCase());
                }
            }

            _SELF.initMap();

            // default to home subcategory open ...
            //Get parameters from query string   
            //var qs = $.getUrlVars();
            var checked = '';
            var catID = '';
            var retailID = '';
            var filterChk = false;
            var FilterList;
            var addRetail = false;
            var addCategory = false;
            var prodID = document.getElementById('prodID').value;
            // load category filters

            $("#" + _SELF.ElementIDs.TxtRetailer).attr('title', 'Enter Name');

            // at this time we are either doing a retailer or category search
            catID = (qs.category) ? qs.category : '';
            retailID = (qs.retailer) ? qs.retailer : '';

            // check this and get it working
            if (!_SELF.isUndefined(qs.category)) {
                addCategory = true;
            }

            // check this and get it working - if category is in the param list
            if (!_SELF.isUndefined(qs.retailer)) {
                addRetail = true;
            }

            // product exclusion ... must be set per brand. This is not addretail or addcategory dependent
            // HACK Health...
            var storeID = document.getElementById('storeID').value;
            if (storeID.toLowerCase() == "go" || storeID.toLowerCase() == "be") {
                $(_SELF.getElementID(_SELF.ElementIDs.HealthUlDiv)).css("display", "none");
                $(_SELF.getElementID(_SELF.ElementIDs.CatHealth)).css("display", "none");
                _SELF.useCategoryExclusions = true;

                // construct a list of excluded category_ID
                _SELF.excluded_categories.push(3);
                _SELF.excluded_categories.push(10);
                _SELF.excluded_categories.push(14);
                _SELF.excluded_categories.push(15);
                _SELF.excluded_categories.push(17);
                _SELF.excluded_categories.push(18);
                _SELF.excluded_categories.push(19);
            }

            // add all the retailer checkboxes for this brand
            $.getJSON("GetRetailerFilters.ashx?prodID={0}".format(prodID),
            function(data) {
                $.each(data.items, function(i, retailer) {
                    var chk = false;
                    if (!_SELF.isUndefined(qs['retailer'])) {
                        if (typeof (qs['retailer']) != 'string') {
                            var index = $.inArray(retailer.RETAILERID, qs['retailer']);
                            if (index >= 0) {
                                chk = true;
                                if (_SELF._param_retailer.length > 0) {
                                    _SELF._param_retailer += ',';
                                }
                                _SELF._param_retailer += retailer.RETAILERNAME;
                            }
                        }
                        else {
                            if (retailer.RETAILERID == qs['retailer']) {
                                chk = true;
                                if (_SELF._param_retailer.length > 0) {
                                    _SELF._param_retailer += ',';
                                }
                                _SELF._param_retailer += retailer.RETAILERNAME;
                            }
                        }
                    }

                    var checked = "";
                    if (chk && qs.length > 1 && addRetail) {
                        checked = "checked='checked'";
                    }

                    _SELF._retailers.push(retailer);

                    var chkBox = '';
                    if (retailer.FILTER != "") {
                        chkBox = $("<label><input type='checkbox' class='retailerCheck' name='retailer' id='" + retailer.RETAILERID + "' " + checked + " /> <img src='http://www.gemoney.com.au/common/locator/" + retailer.RETAILERID + ".gif' class='logo'  alt='" + retailer.RETAILERNAME + "' /></label>");
                        $('#ulRetailer').append($('<li class="retailerLI" ></li>').html(chkBox));
                    } else {
                        chkBox = $("<label><input type='checkbox' class='retailerCheck' name='retailer' id='" + retailer.RETAILERID + "' " + checked + " /></label>");
                        $('#ulRetailer').append($('<li class="retailerLI" style="display:none"></li>').html(chkBox));
                    }
                });

                if (addRetail) {
                    if ($(txtSuburb).val() != '' && $(txtSuburb).val() != $(txtSuburb).attr("title")) {

                        _SELF.displayRetailerSearch(searchdiv_low, _SELF.retailergrouptop_high);
                        IsParamSearch = true;

                        _SELF.searchActive = true;
                        _SELF.routeType = 'search';
                        _SELF.findAddress();
                    }
                }
            });

            // if there are parameters process them
            if (qs.length > 1) {
                if (addCategory) {
                    _SELF.displayCategorySearch(searchdiv_low,
                                                _SELF.retailergrouptop_high,
                                                _SELF.retailergrouptop_low);

                    // uncheck ALL 
                    $('input:checkbox[name=all]').attr('checked', '');

                    var chk = false;
                    if (!_SELF.isUndefined(qs['category'])) {
                        if (typeof (qs['category']) != 'string') {
                            $('input:checkbox[name=category]').each(function(i) {
                                $('input:checkbox[name=category][id=' + catID[i] + ']').attr('checked', 'checked');
                                chk = true;
                                filterChk = true;
                            });
                        }
                        else {
                            $('input:checkbox[name=category][id=' + catID + ']').attr('checked', 'checked');
                            chk = true;
                            filterChk = true;
                        }
                    }

                    if (!chk) {
                        _SELF.displayException("Category ID:{0} is not a valid category. Unknown category searches are no longer supported.".format(FilterList[i].toString()));
                    }

                    if ($(txtSuburb).val() != '' && $(txtSuburb).val() != $(txtSuburb).attr("title")) {
                        _SELF.searchActive = true;
                        _SELF.routeType = 'search';
                        _SELF.findAddress();
                    }
                }

                if (!addRetail && !addCategory) {
                    if ($(txtSuburb).val() != '' && $(txtSuburb).val() != $(txtSuburb).attr("title")) {
                        _SELF.searchActive = true;
                        _SELF.routeType = 'search';
                        _SELF.findAddress();
                    }
                }

            }
        });
    }
};
Locator.init();


   
