﻿
// global variables
var map;
var geocoder;
var directions;
var infoHtmls;
var countResults = 0;


// jump to function load() when the document is ready to be manipulated.
$(document).ready(load);


// Cleanup to prevent memory leaks (IE specific)
$(window).unload(function() {
    GUnload();
});

var selectedPosition = 0;

jQuery.fn.exists = function() { return jQuery(this).length > 0; }


function load() {
    // begin load()
    $("#formSearchPorscheCenter").submit(function() {
        initMap();
        return false;
    });

    // move states overlay immediately into parent element "div#wrapper"
    $("#states_imagemap").remove().appendTo("#wrapper");

    // Change text color for default text when input gets focus, and return to
    // normal color on focus lost. ("Enter search term here..", bla)

    $("#searchInput").focus(function() {
        if (this.value == this.defaultValue) {
            this.value = "";
            this.style.color = '#000';
        }
    }).blur(function() {
        if (!this.value.length) {
            this.value = this.defaultValue;
            this.style.color = '#999999';
        }
    }).keyup(function() {
        // reset all dropdowns
        $("select.stateDropdown").attr("selectedIndex", 0);

    });

    $("select.stateDropdown").each(function() {
        $(this).data('content', $(this).html());
        //log("dropdown data property set. value: " + $(this).data('content'));
    });



    $("select.stateDropdown").change(function() {
        selectedState = $('option[selected]', this).val(); // = value of the selected option.
        
        if (selectedState != '') {
            log('selectedState: ' + selectedState);
            // highlight the first option field (e.g. "Choose state")
            $(this).css("color", "#000");

            // reset any _other_ dropdowns (so that their selected value becomes invalid).
            // and paint them gray (-> disabled)
            $("select.stateDropdown[class!='" + this.className + "']").attr("selectedIndex", 0).css("color", "#999"); ;

            // handle default input field text
            if ($("#searchInput").exists()) {
                var searchInput = $("#searchInput")[0];
                if (searchInput.value != searchInput.defaultValue) {
                    searchInput.value = searchInput.defaultValue;
                    searchInput.style.color = '#999999';
                }
            }
            initMap(this, selectedState);
        }
        else {
            $(this).css("color", "#999");
        }
    });   // function load


    if (GBrowserIsCompatible()) {

        // Create a new map type incorporating the tile layer
        map = new GMap2($("#map_canvas")[0], { mapTypes: [G_NORMAL_MAP, G_SATELLITE_MAP, G_HYBRID_MAP] });
        // see mapTypes: declaration in the GMap2 init routine above.
        map.addControl(new GLargeMapControl());
        map.addControl(new GMapTypeControl());

        // set centerpoint
        //(parameters for each market: boundary, zoom level)

        var mapCenterPoint = new GLatLng(UI_MAP_DEFAULTCOORDS_LAT, UI_MAP_DEFAULTCOORDS_LNG); // TODO Use GLatLngBounds instead (requires two GLatLng points)

        // Mouse wheel zoom in/out
        map.enableScrollWheelZoom();

        // set map mode
        map.setMapType(UI_MAP_DEFAULTMAPTYPE);
        
        // set minimum zoom level
        var mt = map.getMapTypes();
        for (var i = 0; i < mt.length; i++) {
            mt[i].getMinimumResolution = function() { return UI_MAP_DEFAULTCOORDS_MINZOOMLEVEL; }
        }

        geocoder = new GClientGeocoder();
        

        // setup Directions ("calculate route")
        directions = new GDirections();
        GEvent.addListener(directions, "error", onDirectionsError);
        GEvent.addListener(directions, "load", function() {
            onDirectionsLoad();
        });

        /* Jump to direct search */
        // check if there is a direct search (e.g. location.aspx?locationId=123456)
        var hiddenLocationId = $("#searchPorscheCenter form input[name$='hiddenLocationId']").val();
        var hiddenLocationType = $("#searchPorscheCenter form input[name$='hiddenLocationType']").val();
        if (hiddenLocationId != undefined && hiddenLocationId != '') {
            //showSingleLocation(hiddenLocationId, hiddenLocationType);
            showSingleSite(hiddenLocationId, hiddenLocationType);
        }
        else {
            // external search (we came here from the market homepage)
            if (typeof(GLOBAL_SEARCHKEY) != 'undefined') {
                doExternalSearch(GLOBAL_SEARCHKEY);
            }
            else {
                // center map into default position
                map.setCenter(mapCenterPoint, UI_MAP_DEFAULTCOORDS_ZOOMLEVEL);
            }
        }
        

    }
}
// this handles the master/slave relationship 
// between dropdowns.
// Ex: when a country is selected from regions dropdown, 
// show and update the values in the corresponding dealers list.
function handleSlaves(master, data) {
    var ownerType;
    if ($(master).hasClass('state'))
        ownerType = 'state';
    else if ($(master).hasClass('city'))
        ownerType = 'city';
    else return;
    
    var selectedKey = $(master).val();
    log("selectedKey: '" + selectedKey + "'");
    arrSlaves = $("select.dependsOn_" + ownerType);
    log("arrSlaves found: " + arrSlaves.length);

    // update depending dropdowns
    UpdateSlaveOptions(selectedKey, ownerType, arrSlaves, data);

    return (arrSlaves > 0);
}

// makes a backend request to fetch relevant items
// and fills the dropdown with them.
function UpdateSlaveOptions(selectedKey, masterType, arrSlaves, data) {
    //console.dir(data);
    if (selectedKey == '') {
        // if nothing is selected in the master, hide its slaves.
        $(arrSlaves).hide();
        return;
    }

    var resultXml = $(data);
    $(arrSlaves).each(function() {
        if (selectedKey != '') {
            // turn it off first.
            $(this).attr('disabled', 'disabled');

            // resurrect its html from data field.
            $(this).html($(this).data('content'));

            if (masterType == 'state') {
                // master is region dropdown, so we adjust 
                // slave dropdowns so that they only show 
                // related options
                if ($(this).hasClass('dealer')) {
                    // ('this' => slave dropdown).
                    // if slave is a dealer-list dropdown, 
                    // filter the ones not belonging to this region.
                    $("option[value!='']", this).each(function() {
                        // remove non-empty dropdown options (empty => header option)
                        // not in the result list.
                        var optionVal = $(this).attr('value');
                        //var match = $("dealer[nr='" + optionVal + "']", '#dealerNonHTML');
                        var match = resultXml.find('Location Id:contains("' + optionVal + '")');
                        log("optionVal: " + optionVal + " - match.length(): " + match.length);
                        if (match.length == 0) {
                            // remove element
                            $(this).remove();
                        }
                    });
                }
            }
            // we're done. 
            // Enable and display it again (if it was hidden)
            $(this)
            .removeAttr('disabled')
            .show();
        }

    });


        
}

function doExternalSearch(key) {
    log("doExternalSearch, key: " + key);
    $('#searchInput').focus().val(unescape(key));
    $('#searchButton').click();
}

function initMap(master, selectedState) {

    geocoder.setBaseCountryCode(GLOBAL_CCTLD);

    // set mouse cursor to sandbox etc.
    // IMPORTANT: initMap() calls functions which have callbacks with delays,
    // so we call toggleSearch(false) not here, but at the appropriate position
    // in these callbacks, which is mostly, the end.
    toggleSearch(true);

    // come back to search pane, if the last pane was directions.
    $("#directions").hide(300);
    $("#results").show(300);


    // clear results
    showResultMessage('');

    // fade the states map overlay out.
    $("#states_imagemap").fadeOut(UI_STATESOVERLAY_FADEOUT_TIME);

    if (master && selectedState) {
        // State selected, skip keyword search.
        log("Entering showStateDealers(master)..");
        showStateDealers(master, selectedState);
    }
    else {
        // reset states dropdown 
        $("select.stateDropdown").attr("selectedIndex", 0);

        // read input value (address).
        var input = $("#searchInput").val();

        // check if search input complies with market specialities
        if (checkInputValid(input)) {
            //var inputWithCCTLD = GLOBAL_CCTLD ? input + ' ' + GLOBAL_CCTLD : input;
            var inputWithCCTLD = buildSearchInput(input, GLOBAL_CCTLD);
            // do a Maps Geocoder Search and take result to
            // the function addAddressesToMap()
            if (GLOBAL_PROXIMITY_SEARCH_ACTIVE)
                if (geocoder && input.length && input.length > 0) { geocoder.getLocations(inputWithCCTLD, addAddressesToMap); }
        }
    }
}

function buildSearchInput(input, cctld) {
    var retVal = input;
    if (GLOBAL_POOL == 'france') {
        var i = parseInt(input, 10);
        if (isNaN(i)) {
            // no postcode
            // set search globally.
            geocoder.setBaseCountryCode(null);
            // retVal = input;
        }
        else {
            // postcode, add "fr"
            retVal = input + ' ' + cctld;
        }
    }
    else
        retVal = input + ' ' + cctld;

    return retVal;

}

function checkInputValid(input) {

    switch (GLOBAL_POOL) {
        case 'france':
            var i = parseInt(input, 10);
            if (isNaN(i)) {
                // not a number, go on with the search                 
                return true;
            }
            else {
                if (input.length != 5) {
                    handleError(UI_STRINGCONST_NORESULTSFOUND_INVALIDPOSTCODE);
                    toggleSearch(false);
                    return false;
                }
                else {
                    geocoder.setBaseCountryCode(null);
                    return true;
                }
            }
            break;
        default:
            return true;
    }
}

function isPostCode(str, regexString, regexOptions) {

    var testRegex = new RegExp(regexString, regexOptions);
    return testRegex.test(str);
}


// shows the porsche centres within the borders of a state/Bundesland.
// we are here because the user has chosen item from the dropdown.
// the variable selectedState is a global one.
function showStateDealers(master, selectedState) {
    log("showStateDealers(master) running..");
    var searchurl = "";
    var searchmode = "";

    var search = {
        siteId: GLOBAL_POOL,
        market: GLOBAL_MARKET,
        language: GLOBAL_LANGUAGE,
        locationType: 'Search.LocationTypes.Dealer',
        searchMode: '',
        searchKey: escape(selectedState),      
        errorMsg: UI_STRINGCONST_NORESULTSFOUND
        
        
    }

    if ($(master).hasClass('dealer')) {
        log("Execute location search..");
        search.searchMode = 'location';
    }
    else if ($(master).hasClass('state')) {
        log("Execute region search..");
        search.searchMode = 'state';
        search.errorMsg = UI_STRINGCONST_NORESULTSFOUND_REGION;
    }
    else if ($(master).hasClass('city')) {
        log("Execute city search..");
        search.searchMode = 'city';
    }
    else 
        return;

    performQuery(search, master);

    selectedState = false; // reset selected state variable.

}

function performQuery(search, master) {
    searchurl = buildSearchURL(search);

    // AJAX Request
    $.ajax({
        url: searchurl,
        dataType: "xml",
        success: function (data) {
            // go through nodes in the selection
            var resultNodes = $(data).find("ListofLocations Location");

            if (resultNodes.length > 0) {
                appendResultsToDOM(resultNodes);
                log('ajax: search.searchMode: ' + search.searchMode);
                showDealersOnMap(search.searchMode);
                // handle master/slave dropdown relationships, if any.
                if (master) handleSlaves(master, data);
            }
            else {
                // nothing found, display corresponding error message.
                handleError(search.errorMsg);
                log("ajax: no results found (resultNodes.length == 0)");
            }
        },
        error: function (request, error) {
            log("ajax: http error: " + error);
        },
        complete: function () {
            toggleCursor(false);
            toggleSearch(false);
        }
    });
}

function handleError(errMsg) {
    log("handling error: " + errMsg);
    $('#results').html('<p class="error">' + errMsg + '</p>');

    
}


function buildListItem(node, position) {
    node = $(node);
    var dealer = {
        position: position,
        id: node.find('Id').text(),
        coords: { lat: node.find('Coordinates Lat').text(), lng: node.find('Coordinates Lng').text() },
        name: node.find('Name').text(),
        name2: node.find('Name2').text(),
        street: node.find('AddressData').find('Street').text(),
        postcode: node.find('AddressData').find('PostCode').text(),
        city: node.find('AddressData').find('City').text(),
        stateCode: node.find('StateCode').text(),
        stateName: node.find('StateName').text(),
        countryCode: node.find('CountryCode').text(),
        phone: node.find('AddressData').find('Phone').text(),
        fax: node.find('AddressData').find('Fax').text(),
        email1: node.find('Email1').text(),
        email2: node.find('Email2').text(),
        url1: node.find('Url1').text(),
        infoWinThumbPath: node.find('InfoWinThumbPath').text()
    }
    //log(dealer);
    

    var poolLangUrlPrefix = buildPoolLang();

    var a_html = '<a href="javascript:void(0)">' +
                    '<h3>' +
                        '<img class="resultmarker" src="' + APPPATH + '/assets/images/porschelogo_small.gif" />' +
                        '<img class="resulttitle" src="http://www.porsche.com/' + poolLangUrlPrefix + '/ImageMachines/LinkBlockTitle.ashx/rendered.gif?text=' + encodeURIComponent(dealer.name) + '" alt="' + dealer.name + '"/>' +
                     '</h3>' +
                 '</a>';

    if (GLOBAL_POOL != 'japan') {
        if (GLOBAL_POOL == 'italy') {
            a_html += '<span class="name2">' + dealer.name2 + '</span>';
        }

        a_html += '<div class="clearfix"></div>' +
                  '<p class="dealerdetails">';
        switch (GLOBAL_POOL) {
            case 'portugal':
                a_html += dealer.street + ',<br/>' +
                      dealer.postcode + ' ' + dealer.city;
                if (dealer.phone && trim(dealer.phone) != '')
                    a_html += '<br/><span class="nowrap">' + dealer.phone + '</span>';
                break;
            case 'canada':
                a_html += dealer.street + ',<br/>' +
                      dealer.city + ' ' + dealer.postcode;
                break;
            default:
                a_html += dealer.street + ',<br/>' +
                      dealer.postcode + ' ' + dealer.city;
                if (dealer.phone && trim(dealer.phone) != '')
                    a_html += ' - <span class="nowrap">' + dealer.phone + '</span>';
        }
        a_html += '</p>';
    }


    var listItem = $('<li id=\"' + dealer.id + '\"></li>')
                    .click(function() {
                        gotoPorscheCenter(position, dealer.coords.lat, dealer.coords.lng);
                    })
                    .hover(function() {
                        $(this).css('cursor', 'pointer');
                        highlight(position);
                    },
                    function() {
                        $(this).css('cursor', 'default');
                        highlight(position, true);
                    })
                    .html(a_html);

    listItem.data('dealerObj', dealer);

    return listItem;
}


function appendResultsToDOM(nodes) {
    $("#results").append('<div id="resultData"></div>');
    var ul = $('<ul></ul>').appendTo('#resultData');

    $(nodes).map(function(idx, element) {
        // processing <Location> nodes
        buildListItem($(element), idx).appendTo(ul);
    });
}

function showSingleSite(locationId, locationType) {
    
    log("Entering showSingleSite()");
    log("locationId: " + locationId);
    log("locationType: " + locationType);

    var search = {
        siteId: GLOBAL_POOL,
        market: GLOBAL_MARKET,
        language: GLOBAL_LANGUAGE,
        locationType: 'Search.LocationTypes.Site',
        searchMode: 'location',
        searchKey: locationId,
        errorMsg: UI_STRINGCONST_NORESULTSFOUND
    }

    performQuery(search);    
}


function buildSearchURL(s) {

    var webserviceURI = "/GetLocationsWebService.asmx/GetLocations";
    var paramStr = APPPATH_SEARCH + webserviceURI
                       + "?market=" + s.siteId
                       + "&siteId=" + s.siteId
                       + "&language=" + s.language
                       + "&_locationType=" + s.locationType
                       + "&searchMode=" + s.searchMode
                       + "&searchKey=" + s.searchKey;
    if (s.address && s.address != '')
        paramStr += "&address=" + encodeURIComponent(s.address);

    return paramStr;
}

function addAddressesToMap(response) {
    if (!response || response.Status.code != 200) {
        showResultMessage(UI_STRINGCONST_NORESULTSFOUND);
        log("google search failed - no results;");
        toggleSearch(false);
        toggleCursor(false);
    } else {
        // take the first result
        place = response.Placemark[0];
        point = new GLatLng(place.Point.coordinates[1],
                            place.Point.coordinates[0]);

        //proximity search (centered around point.lat() and point.lng()
        // the reason why this is here, is because the google internal search function
        // redirects the result into a callback function, which is this one.

        // build query URL

        var search = {
            siteId: GLOBAL_POOL,
            market: GLOBAL_MARKET,
            language: GLOBAL_LANGUAGE,
            locationType: 'Search.LocationTypes.Dealer',
            searchMode: 'proximity',
            searchKey: point.lat() + '|' + point.lng(),
            address: $("#searchInput").val(),
            errorMsg: UI_STRINGCONST_NORESULTSFOUND
        }

        performQuery(search);

    }
}


function showDealersOnMap(searchmode) {
    log('entering showDealersOnMap');
    // reset selected position
    selectedPosition = 0;

    // turn off search mode.
    toggleSearch(false);
    //$("#directions").hide(300);
    //$("#results").show(300);

    // handle mouse over icon on li's
    $('#results ul li').hover(
        function() {
            $(this).css('cursor', 'pointer');
            highlight($(this).prevAll().length);
        },
        function() {
            $(this).css('cursor', 'default');
            highlight($(this).prevAll().length, true);
        }
    );


    map.clearOverlays();
    // anonymous function to deal with the resulting data
    // from perimeter search in the database.

    countResults = $('#resultData ul li').length;

    log("countResults: " + countResults);
    
    var points = new Array();
    

    for (var i = 0; i < countResults; i++) {
        points[i] = getDealerLatLng(i);
    }
    if (UI_MAP_DEFAULTCOORDS_MAXZOOMLEVEL && UI_MAP_DEFAULTCOORDS_MAXZOOMLEVEL > 0)
        fitMap(map, points, true, UI_MAP_DEFAULTCOORDS_MAXZOOMLEVEL);
    else
        fitMap(map, points, true);

    installMarkers(map, points);

    // show the info window directly if there is an exact hit.
    if (countResults == 1) {
        gotoPorscheCenter(0, points[0].lat(), points[0].lng());
    }

    toggleSearch(false);
}

function gotoPorscheCenter(pos, lat, lng) {
    toggleCursor(true);
    selectedPosition = pos;
    highlight(pos);
    var point = new GLatLng(lat, lng);
    var html = buildInfoHtml(pos);
    map.openInfoWindowHtml(point, html, UI_MAP_INFOWINDOWOPTIONS);
    toggleCursor(false);
}

function buildInfoHtml(pos) {
    var html;
    var _br_ = '<br/>';
    log("buildInfoHtml: calling getDealerObject(position=" + pos + ")");
    var d = getDealerObject(pos);

    html =  '<div class="markerInfoWindow">';
    html += '    <div class="infowinHeadline"><img src="http://www.porsche.com/' + buildPoolLang() + '/ImageMachines/PageTitle.ashx/rendered.gif?text=' + encodeURIComponent(d.name) + '" alt="' + d.name + '"/></div>';
    html += '    <div class="infowinContact">'
    html += '        <p class="infowinPara">';
    switch (GLOBAL_POOL) {
        case 'japan':
            html += d.postcode + _br_ + d.stateName + ' ' + d.city + ' ' + d.street;
            break;
        case 'canada':
            html += d.street + _br_ + d.city + ' ' + d.postcode;
            break;

        default:
            if (GLOBAL_SHOWOWNERNAME === true) {
                html += d.name2 + _br_; // italy.
            }

            html += d.street + _br_;
            if (d.countryCode && trim(d.countryCode) != '') {
                html += d.countryCode + ' - ';
            }
            html += d.postcode + ' ' + d.city;
            break;
    
    }
    html += '        </p>';
    
    if ((d.phone && trim(d.phone) != '') || (d.fax && trim(d.fax) != '')) {
        html += '        <p class="infowinPara">';
        if (d.phone && trim(d.phone) != '') {
            html += UI_STRINGCONST_DEALERINFOTEL + d.phone;
        }
        if (d.fax && trim(d.fax) != '') {
            html += _br_ + UI_STRINGCONST_DEALERINFOFAX + d.fax;
        }
        html += '        </p>';
    }
    
    html += '    </div>'; // end of "infowincontact"
    
    html += '  <img src="' + d.infoWinThumbPath  + '" alt="' + d.name + '" class="infowinThumb"/>';
    html += '  <div class="clearfix"></div>';
    if ((d.email1 && trim(d.email1) != '') || (d.url1 && trim(d.url1)!='')) {
        html += '  <p class="infowinPara">';
        if (GLOBAL_POOL != 'france') {
            if (d.email1 && trim(d.email1) != '') {
                html += UI_STRINGCONST_DEALERINFOEMAIL + '<a href="mailto:' + d.email1 + '">' + d.email1 + '</a>';
            }
            if (d.email1 && trim(d.email1) != '' && d.url1 && trim(d.url1) != '') {
                html += _br_;
            }
        }
        
        if (d.url1 && trim(d.url1)!='') {
            html += UI_STRINGCONST_DEALERINFOWEBSITE + '<a href="javascript:openSiteFS(null, \'dealerWebsite\', \'' + d.url1 + '\')">' + d.url1 + '</a>';
        }
                    
        html += '  </p>';
    }

    /*
     Directions nut supported in Japan (yet):
       http://gmaps-samples.googlecode.com/svn/trunk/mapcoverage_filtered.html
    */

    if (GLOBAL_POOL != 'japan') {
        html += '  <p class="infowinDirectionLinks">';
        html += UI_STRINGCONST_DEALERINFOROUTE +
                    '<a href="javascript:void(0);" onclick="openDirections(true, ' + pos + ')">' + UI_STRINGCONST_DEALERINFOTOHERE + '</a> - ' +
                    '<a href="javascript:void(0);" onclick="openDirections(false, ' + pos + ')">' + UI_STRINGCONST_DEALERINFOFROMHERE + '</a>';
        html += '  </p>';
    }
    html += '</div>';

    return html;
}


function highlight(position, bOff) {
    var i;
    for (i = 0; i < countResults; i++) {
        var elm = $("#resultData ul li:eq(" + i + ")")[0];
        if (position == i) {
            if (bOff && i != selectedPosition)
                $(elm).removeClass("hover");
            else
                $(elm).addClass("hover");
        }
        else {
            if (i != selectedPosition) {
                $(elm).removeClass("hover");
            }
        }
    }

}




function handleStateMapClick(stateCode, regiontype) {
    var idx = 0;
    var increment = true;
    $("select[class='stateDropdown " + regiontype + "'] option").each(function() {
        if (this.value == stateCode) {
            increment = false;
        }
        if (increment) idx += 1;
    });

    $("select[class='stateDropdown " + regiontype + "']").attr("selectedIndex", idx).change();
   
    
}


function installMarkers(map, points) {    
    var point;
    var marker;
    for (var i = 0; i < points.length; i++) {
        marker = createMarker(points[i], i, buildInfoHtml(i));
        map.addOverlay(marker);
    }
}

function createMarker(point, number, html) {
    // Marker Setup
    var porscheIcon = new GIcon();
    porscheIcon.image = UI_MAPMARKERS_IMAGE;
    porscheIcon.shadow = false;
    porscheIcon.iconSize = new GSize(24, 30);
    porscheIcon.shadowSize = null;
    porscheIcon.iconAnchor = new GPoint(12, 30);
    porscheIcon.infoWindowAnchor = new GPoint(0, 20);

    markerOptions = { icon: porscheIcon };
    
    var marker = new GMarker(point, markerOptions);
    /* pixelOffset: Distance (x, y) of the info window from the current map point. 
       
       */
    var infoWindowoptions = UI_MAP_INFOWINDOWOPTIONS;
    marker.value = number;
    GEvent.addListener(marker, "click", function() {
        selectedPosition = number;
        highlight(number);
        map.openInfoWindowHtml(point, html, infoWindowoptions);
    });
    return marker;
}


function fitMap(map, points, save, maxZoomLevel) {
    // map bounds
    var bounds = new GLatLngBounds();
    var zoomLevel;
    var numPoints = points.length;
    // add each point to the map and extend the bounds if necessary.
    for (var i = 0; i < points.length; i++) bounds.extend(points[i]);
    // set map center, so that we can set zoom level.
    map.setCenter(bounds.getCenter());
    // calculate dynamic zoom level.
    var calculatedZoomLevel = map.getBoundsZoomLevel(bounds);
    // if there are too few markers on the map,
    // it's highly probable one of them is too close to the edge
    // so we just take step zoom out one step.
    if (numPoints < 5) calculatedZoomLevel -= 1;
    // that is, unless there is a max. zoom level defined
    // and that zoom level is smaller (i.e., zooms out more) than 
    // the calculated zoom level.
    zoomLevel = (maxZoomLevel && maxZoomLevel < calculatedZoomLevel) ? maxZoomLevel : calculatedZoomLevel;
    // set final zoom level.
    map.setZoom(zoomLevel);
    // save last map position so that the user can come back to it
    // using the center button in the pan/scale control (left-top)
    if (save) map.savePosition();
}



function getDealerObject(i) {
    return $("#resultData ul li:eq(" + i + ")").data("dealerObj");
}


/* returns a new GLatLng of the i-th location in the result xml.
*/
function getDealerLatLng(i) {
    //log("getting dealer object (getDealerObject), i=" + i);
    var d = getDealerObject(i);
    if (d != null) {
        //log(d);
        var lat = parseFloat(d.coords.lat);
        var lng = parseFloat(d.coords.lng);
        return new GLatLng(lat, lng);
    }
    else {
        log('getDealerLatLng(i) - i:' + i + ' has no data');
        return null;
    }
}


function openDirections(toHere, pos) {
    var d = getDealerObject(pos);
    var gLatLngDealer;

    $("#results").hide(300); // hide the results.
    // disable printing.
    $('#directionsPrintBtn, #directionsPrint')
        .css("cursor", "default")
        .fadeTo(1, 0.33)
        .unbind("click")
        .unbind("mouseover")
        .unbind("mouseout")
        .removeAttr('alt')
        .parent().parent().removeAttr("title")
        ;
    
    //d.addressLine = d.street + ', ' + d.postcode + ' ' + d.city; //<xsl:value-of select="street"/>, <xsl:value-of select="plz"/><xsl:text> </xsl:text><xsl:value-of select="city"/>   
    
    $("#directions_results").empty();
    $("#directions").show(300);

   
    var addressLine = d.street + ', ' + d.postcode + ' ' + d.city; //$("#dealerInFoWindowData .markerInfoWindow:nth-child(" + pos + ") p.addresslineHidden:first").html();    
    gLatLngDealer = getDealerLatLng(pos);

    if (toHere) {
        $("#directionsFrom").val("")[0].focus();
        $("#directionsTo").val(addressLine);
    }
    else {
        $("#directionsFrom").val(addressLine);
        $("#directionsTo").val("")[0].focus();
    }

    $("#formSearchDirections").submit(function() {
        toggleSearch(true);
        try {
            if (toHere) {
                directions.loadFromWaypoints(new Array($("#directionsFrom").val(), gLatLngDealer), UI_MAP_DIRECTIONOPTIONS);
            }
            else {
                directions.loadFromWaypoints(new Array(gLatLngDealer, $("#directionsTo").val()), UI_MAP_DIRECTIONOPTIONS);
            }
        }
        catch (ex) {
        }
        return false;
    });


    // Ende openDirections    
}



// Will run when GDirections loads succesfully and without errors,
// otherwise it will call to onDirectionsError()
function onDirectionsLoad() {
    // => statusCode = 200 (G_GEO_SUCCESS);

    /******************/
    /* setup map pane */
    /******************/
    map.clearOverlays();

    // setup polylines
    var poly = directions.getPolyline();
    map.addOverlay(poly);

    // fit and center map.
    var bounds = directions.getBounds();
    map.setCenter(bounds.getCenter());
    map.setZoom(map.getBoundsZoomLevel(bounds));

    // setup icons
    var baseIcon = new GIcon();
    baseIcon.shadow = UI_MAP_DIRECTIONS_SHADOWIMAGE;
    baseIcon.iconSize = new GSize(20, 20);
    baseIcon.shadowSize = new GSize(30,30);
    baseIcon.iconAnchor = new GPoint(10, 10);
    G_START_ICON = new GIcon(baseIcon);
    G_START_ICON.image = UI_MAP_DIRECTIONS_STARTIMAGE;
    G_END_ICON = new GIcon(baseIcon);
    G_END_ICON.image = UI_MAP_DIRECTIONS_ENDIMAGE;
    //G_PAUSE_ICON.image = UI_MAP_DIRECTIONS_PAUSEIMAGE;

    // plot start and end markers 
    map.addOverlay(new GMarker(poly.getVertex(0), G_START_ICON));
    map.addOverlay(new GMarker(poly.getVertex(poly.getVertexCount() - 1), G_END_ICON));

    // plot pause markers for any waypoints in between.
    // i < directions.getNumRoutes() - 1, because we do not add a pause for the last route.
    /*
    for (var i = 0; i < directions.getNumRoutes() - 1; i++) {
        var route = directions.getRoute(i);
        map.addOverlay(new GMarker(route.getEndLatLng(), G_PAUSE_ICON));
    }
    */

    /*********************/
    /* fill results pane */
    /*********************/

    //Summary

    var distMeters = directions.getDistance().meters; // distance in meters (integer);
    var distHtml = directions.getDistance().html; // string representation of distance / set by Google.

    var durSeconds = directions.getDuration().seconds; // duration in seconds (integer);
    var durHtml = directions.getDuration().html; // string representation of duration / set by Google.

    var results = $("#directions_results");
    var htmlResultSummary = UI_STRINGCONST_RESULTSUMMARY_1.replace(/\[ADDRESSLINE\]/, $("#directionsTo").val());
    htmlResultSummary += "<br/>\n";
    htmlResultSummary += UI_STRINGCONST_RESULTSUMMARY_2.replace(/\[DISTANCE\]/, distHtml).replace(/\[DURATION\]/, durHtml);

    $(results).html("<p class=\"summary\">" + htmlResultSummary + "</p>\n");

    $(results).append("<div class=\"resultWaypoint\">\n" +
                        "<img src=\"" + UI_DIRECTIONS_STARTIMAGE + "\" alt=\"\"/>\n" +
                        "<span>" + $("#directionsFrom").val() + "</span>" +
                        "<div class=\"clearfix\"></div>" + 
                        "</div>\n");

    //for (var i = 0; i < directions.getNumRoutes()-1; i++) {
    //var route = directions.getRoute(i);
    var route = directions.getRoute(0);


    var tableHtml = "<table>\n";
    for (var step = 0; step < route.getNumSteps(); step++) {
        currStep = route.getStep(step);
        var rowClass = (step == 0) ? " class=\"firstRow\"" : "";
        tableHtml += "<tr" + rowClass + ">\n" +
                        "<td>" + (step + 1) + ".</td>\n" +
                        "<td>" + currStep.getDescriptionHtml().replace(/\<b\>|\<\/b\>|/g, '') + "</td>\n" +
                        "<td class=\"distance\">" + currStep.getDistance().html + "</td>" + 
                      "</tr>\n";
    }
    tableHtml += "</table>\n";
    $(results).append(tableHtml);
    //}


    $(results).append("<div class=\"resultWaypoint\">\n" +
                    "  <img src=\"" + UI_DIRECTIONS_ENDIMAGE + "\" alt=\"\"/>\n" +
                    "  <span>" + $("#directionsTo").val() + "</span>" +
                    "  <div class=\"clearfix\"></div>" +
                    "</div>\n");

    var fromLatLng = route.getStep(0).getLatLng();
    var toLatLng = route.getEndLatLng();

    
    // enable printing.
    $('#directionsPrintBtn, #directionsPrint')
        .bind("mouseover", function() { $(this).css("cursor", "pointer") })
        .bind("mouseout", function() { $(this).css("cursor", "default") })
        .fadeTo("fast", 1.0)
        .bind("click", function() {
            try {
                console.log(fromLatLng.lng());
                console.log(toLatLng.lng());
                console.log($("#directionsFrom").val());
                console.log($("#directionsTo").val());
            }
            catch (e) {
            }
            var win = window.open(APPPATH_SEARCH
                        + "/direct.aspx?siteid=" + GLOBAL_POOL
                        + "&market=" + GLOBAL_MARKET
                        + "&language=" + GLOBAL_LANGUAGE
                        + "&fromText=" + $("#directionsFrom").val()
                        + "&toText=" + $("#directionsTo").val()
                        + "&fromLatLng=" + serializeLatLng(fromLatLng)
                        + "&toLatLng=" + serializeLatLng(toLatLng)
                        + "&actiontype=directions"
                        + "&print=1"
                        , "printPreview"
                        , "width=594,height=750,left=200,top=20,scrollbars=yes,resizable=yes");
        })
        .attr('alt', $("#lblPrint").text())
        .parent().parent().attr('title', $("#lblPrint").text() /*$('#directionsPrintBtn').attr('alt')*/)
        ;
       
    toggleSearch(false);

}

function onDirectionsError() {
    // Directions could not load because of some error (address wrong or ambigious)
    var errCode = directions.getStatus().code;
    $('#directions_results').html("<p class=\"error\">" + UI_STRINGCONST_NORESULTSFOUND + "</p>");
    toggleSearch(false);
}

function serializeLatLng(gLatLng) {
    var arrGLatLng = new Array();
    arrGLatLng[0] = gLatLng.lat();
    arrGLatLng[1] = gLatLng.lng();
    var s = arrGLatLng.join(';');
    log(s);
    
    return s;
        
}

function buildPoolLang() {
    return GLOBAL_LANGUAGE == 'none' ? GLOBAL_POOL : GLOBAL_POOL + '/' + GLOBAL_LANGUAGE;
}

function showResultMessage(msg) {
    $("#results").html("<p class=\"error\">" + msg + "</p>")
}

function hiliteAreaToggle(areaId, show) {
    if (show) {
        //showResultMessage(areaId + ": show");
        $("#state_over_" + areaId).show();
    }
    else {
        //showResultMessage(areaId + ": hide");
        $("#state_over_" + areaId).hide();
    }
}

// toggle Elements to indicate search or similar activity, 
// so that the user knows something's going on in the background.
function toggleSearch(searching) {
    toggleCursor(searching);
    if (searching) {
    }
    else {
        //alert($("#searchInput")[0] + " " + $("#directionsFrom")[0]);
        //alert(($("#searchInput").length > 0).toString() + ", " + ($("#searchInput").css("display") == 'block').toString());
        if ($("#searchInput").length > 0 && $("#searchInput").css("display") == 'block') {
            $("#searchInput")[0].focus();
        }
        else {
            //alert($("#directionsFrom").css("display") == 'block');
            if ($("#directions").css("display") == 'block'
                && $("#directionsFrom").length > 0
                && $("#directionsFrom").css("display") == 'block') {
                    $("#directionsFrom")[0].focus();
            }
        }
        
    }
}

// toggles mouse cursor icon between "progress" (sand clock) 
// and "pointer" (default)
function toggleCursor(on) {
    if (on) 
        document.body.style.cursor = 'progress';
    else 
        document.body.style.cursor = 'auto';
}

function openSite(refForm, sWidth, sHeight, sName, sUrl) {
    if (!sUrl) sUrl = "";
    var topOffset = 40;


    if (sHeight > (self.screen.availHeight + topOffset - 40)) {
        sHeight = self.screen.availHeight - 40;
        topOffset = 0;
    }
    newWin = window.open(sUrl, sName, "width=" + sWidth + ",height=" + sHeight + ",left=40,top=" + topOffset + ",scrollbars=yes,dependent=yes,location=no,resizable=yes,status=no");

    if (refForm) {
        refForm.target = sName;

    }

}

function openSiteFS(refForm, sName, sUrl) {
    var width = screen.width; 
    var height = screen.height; 
    var left = (screen.width / 2) - ((width + 10) / 2); 
    if (left < 0)
        left = 0;
    var top = (screen.height / 2) - ((height + 55) / 2); 
    if (top < 0)
        top = 0;

    openSite(refForm, width, height, sName, sUrl)
}

function trim(str)
{
 	return str.replace(/^\s+/g, '').replace(/\s+$/g, '');
}

function log(str) {
    try { console.log(str); } catch (e) {}
}


