var map = null;
var dealerLayer = null;
var directionLayer = null;
var markerPoints = new Array();
var prefix = null;
var lastInfoBoxShape = null;
var panStarted = false;
var panStartLatLng = null;
var locationID = null;
var locationShape = null;
var mapWidth = null;
var ignorePan = false;
var centeredShapeID = "";
var movingCustomerPin = false;
var timerID = null;
var dealerShapes = new Array();
var showingRoute = false;
var destinationDealershipID = null;

$(function() {
    $('#location').keypress(function(e) {
            if (e.which == 13){
                TrackPageView('/virtualpv/dealerlocate');
                FindAddressAndDealers();
                return false;
            }
    });

    if (window.attachEvent) {
        //IE and Opera
        window.attachEvent("onload", GetMap);
        window.attachEvent("onunload", UnloadMap);
    } else if (window.addEventListener) {
        // IE 6
        window.addEventListener("load", GetMap, false);
        window.addEventListener("unload", UnloadMap, false);
    } else {
        //FireFox
        document.addEventListener("load", GetMap, false);
        document.addEventListener("unload", UnloadMap, false);
    }
    if ( (/true/i).test($('#tpv').text()) )
    {
        TrackPageView('/virtualpv/dealerlocate/result');
    }
});

function InitGA() {
    $('a.findDealer').click(function() {
            TrackPageView('/virtualpv/dealerlocate');
    });
    $('a.resultLink').click(function() {
            TrackEvent('Outlink', 'Dealer', $(this).text().replace(/\d+\. /, ''), 3);
    });
    $('a.resultDirection').click(function() {
            TrackPageView('/virtualpv/dealerlocate/directions');
    });
}
function InitDetailGA() {
    TrackPageView('/virtualpv/dealerlocate/detail');
    
    var title = $('div.VE_Pushpin_Popup_Title');
    if ($(title).find('div.initPinGA').length == 0) {
        $(title).append('<div class="initPinGA"></div>');
        
        $('a.detailLink').click(function() {
                TrackEvent('Outlink', 'Dealer', $('div.dealerTitle').text().replace(/\d+\. /, ''), 3);
        });
        $('a.detailDirection').click(function() {
                TrackPageView('/virtualpv/dealerlocate/directions');
        });
        $('input.detailDirectionInput').keypress(function(e) {
            if (e.which == 13){
                $('a.detailDirection').click();
                return false;
            }
        });
    }
}

function ClearText() {
    if (IsLocationDefault())
        document.getElementById("location").value = "";
}

function IsFrenchPage() {
    var searchHeader = document.getElementById("searchHeader");
    if (searchHeader == null || searchHeader.className == "")
        return false;
    
    return searchHeader.className.match(/FR/);
}
function IsInternetExplorer() {
    return navigator.userAgent.indexOf('MSIE') != -1;
}
function IsLocationDefault() {
    var location = document.getElementById("location").value;
    var defaultText = document.getElementById("defaultText").value;
    return location == defaultText;
}
function GetPinURL() {
    return document.getElementById("pinURL").value;
}
function GetLargeIconURL() {
    return document.getElementById("logoLarge").value;
}
function GetSmallIconURL() {
    return document.getElementById("logoSmall").value;
}
function GetControlPrefix() {
	return document.getElementById("controlPrefix").value;
}

function GetCustomerAddress() {
    return document.getElementById("customerLocation").value;
}

function GetCustomerLatLng() {
    var lat = document.getElementById(prefix + "lat");
    var lng = document.getElementById(prefix + "lng");
    if (lat != null)
        lat = lat.value;
    else
        return null;
    if (lng != null)
        lng = lng.value;
    else
        return null;
    
    if (lat == "" && lng == "")
        return null;
    
    return new VELatLong(lat, lng);
}

function GetCustomerCoordinates(layer, resultsArray, places, hasMore, veErrorMessage)
{
    if (places == null)
        return;
    
    findPlaceResults = places[0].LatLong;
    var customerShape = new VEShape(VEShapeType.Pushpin, findPlaceResults);
    var description = '<div id="titleDiv" class="locationTitle">' + places[0].Name;
    
    document.getElementById("location").value = places[0].Name;
    document.getElementById("customerLocation").value = places[0].Name;
    
    if (places[0].Description != "" && places[0].Description != undefined)
        description += places[0].Description;
    description += '</div>';
    customerShape.SetTitle(description);
    map.AddShape(customerShape);
    customerShape.SetCustomIcon('<div class="locationPin"></div>');
    
    locationID = customerShape.GetID();
    locationShape = customerShape;
    
    var lat = document.getElementById(prefix + "lat");
    var lng = document.getElementById(prefix + "lng");
    if (lat != null)
        lat.value = findPlaceResults.Latitude;
    if (lng != null)
        lng.value = findPlaceResults.Longitude;
    
    markerPoints[markerPoints.length] = places[0].LatLong;
    map.SetMapView(markerPoints);
    map.SetCenter(places[0].LatLong);
    
    HideLoadingIcon();
}

function GetMap() {
    prefix = GetControlPrefix();
    var mapDiv = "mapDiv";
    
    mapWidth = document.getElementById(mapDiv).style.width;
    
    /*
    var options = {credentials: $('div#bingKey').text(),
        center: new Microsoft.Maps.Location(55, -100),
        mapTypeId: Microsoft.Maps.MapTypeId.road};
    map = new Microsoft.Maps.Map($('div#mapDiv').get()[0], options);
    return;
    */
    
    map = new VEMap(mapDiv);
    map.SetCredentials($('div#bingKey').text());
    
    if (navigator.userAgent.match(/Gecko/i) && !navigator.userAgent.match(/Firefox/i)) {
        Msn.Drawing.Graphic.CreateGraphic = function(f,b) { return new Msn.Drawing.SVGGraphic(f,b) };
    }
    try {
        map.LoadMap();
    }
    catch (e) {
        alert(e);
    }
    map.SetMouseWheelZoomToCenter(false);
    
    SetupInfobox();
    SetupControls();
    
    var customerAddress = document.getElementById('location').value;
    var customerPosition = GetCustomerLatLng();
    if (customerPosition != null)
    {
        
        var places = new Array();
        places[0] = {LatLong:customerPosition, Name:customerAddress};
        
        GetCustomerCoordinates(null, null, places, false, null);
        
        /*
        markerPoints[markerPoints.length] = customerPosition;
        map.SetMapView(markerPoints);
        map.SetCenter(customerPosition);
        */
    }
    else if (customerAddress != undefined && customerAddress != "" &&
        !IsLocationDefault())
    {
        map.Geocode(customerAddress, GetCustomerCoordinates, new VEGeocodeOptions());
    }
    else
        map.SetCenter(new VELatLong(55, -100));
    dealerLayer = new VEShapeLayer();
    directionLayer = new VEShapeLayer();
    map.AddShapeLayer(dealerLayer);
    map.AddShapeLayer(directionLayer);
    
    map.SetScaleBarDistanceUnit(VEDistanceUnit.Kilometers);
    map.AttachEvent("onendpan", PanZoomFindDealers);
    map.AttachEvent("onstartpan", StartPan);
    
    map.AttachEvent("onendpan", OnMapMoved);
    map.AttachEvent("onchangeview", OnMapMoved);

    map.AttachEvent("onmousemove", MouseMoveHandler);
    map.AttachEvent("onmousedown", MouseDownHandler);
    map.AttachEvent("onmouseup", MouseUpHandler);

    map.AttachEvent("onendzoom", ZoomEndHandler);
    
    map.ShowMiniMap(0, 0);
    // Attach our onresize event handler
    map.AttachEvent("onresize", MapResize);
    // Align the position of the Mini Map where we want it
    RealignMiniMap();
    var minimap = document.getElementById("MSVE_minimap");
    var aerial = document.getElementById("MSVE_navAction_AerialMapStyle");
    var button = document.getElementById("MSVE_minimap_h_style_button");
    if (minimap != null && aerial != null && button != null) {
        aerial = aerial.innerText.substring(0, 1);
        button.innerText = aerial;
    }
    
    map.AttachEvent("onmouseover",ShapeHandler);
    map.AttachEvent("onmouseout",ShapeHandler);
    
    map.AttachEvent("onchangemapstyle", MapStyleChangeHandler);
    
    map.AttachEvent("onobliqueenter", BirdsEyeHandler);
    map.AttachEvent("onobliqueleave", BirdsEyeHandler);
    SetBirdStyle();
    
    var dealerInfo = document.getElementById(prefix + "dealerInfo");
    if (dealerInfo != null && (dealerInfo.value == null || dealerInfo.value == "")) {
        FindAddressAndDealers();
    }
    else
    {
        ignorePan = true;
        ShowDealers(ParseDealers(), false);
    }
    
    if (IsInternetExplorer())
    {
        var mapDiv = document.getElementById("mapDiv");
        mapDiv.style.width = 859;
        mapDiv.style.left = "9px";
        mapDiv.style.top = "-7px";
    }
}

function ShowLoadingIcon()
{
    var icon = document.getElementById("mapLoadingIcon");
    if (icon == null)
        return;
    icon.style.display = "block";
}
function HideLoadingIcon()
{
    var icon = document.getElementById("mapLoadingIcon");
    if (icon == null)
        return;
    icon.style.display = "none";
    $('div#mapLoadingIcon').hide();
}
function ShowInfobox(shape)
{
    var pixelOffset = null;
    var titleDiv = document.getElementById("titleDiv");
    if (titleDiv != null && titleDiv.className == "directionTitle")
        pixelOffset = new VEPixel(5, -11);
    else
        pixelOffset = new VEPixel(28, -11);
    map.ShowInfoBox(shape, shape.GetIconAnchor(), pixelOffset);
    
    UpdateInfoboxCSS(shape);
}
function SetupInfobox()
{
    var VEMapControl = document.getElementById("MSVE_navAction_palette");
    var infobox = VEMapControl.nextSibling;
    infobox.id = "VEInfobox";
    
    var beak = infobox.lastChild;
    beak.id = "VEInfoboxBeak";
}
function SetupControls() {
    if (map == null)
        return;
    
    map.HideDashboard();
    
    var top = document.getElementById("MSVE_navAction_topBar");
    var VE2Dmode = document.getElementById("MSVE_navAction_FlatlandMapMode");
    if (VE2Dmode != null) {
        var flatMode = document.getElementById("top_flatMode").firstChild;
        flatMode.innerText = VE2Dmode.innerText;
        flatMode.title = VE2Dmode.title;
    }
    var VE3Dmode = document.getElementById("MSVE_navAction_View3DMapMode");
    if (VE3Dmode != null) {
        var threeDMode = document.getElementById("top_threeDMode").firstChild;
        threeDMode.innerText = VE3Dmode.innerText;
        threeDMode.title = VE3Dmode.title;
    }
    
    var VEroadStyle = document.getElementById("MSVE_navAction_RoadMapStyle");
    if (VEroadStyle != null) {
        var roadStyle = document.getElementById("top_roadStyle").firstChild;
        roadStyle.innerText = VEroadStyle.innerText;
        roadStyle.title = VEroadStyle.title;
    }
    var VEaerialStyle = document.getElementById("MSVE_navAction_AerialMapStyle");
    if (VEaerialStyle != null) {
        var aerialStyle = document.getElementById("top_aerialStyle").firstChild;
        aerialStyle.innerText = VEaerialStyle.innerText;
        aerialStyle.title = VEaerialStyle.title;
    }
    var VEbirdStyle = document.getElementById("MSVE_navAction_ObliqueMapView");
    if (VEbirdStyle != null) {
        var birdStyle = document.getElementById("top_birdStyle").firstChild;
        birdStyle.innerText = VEbirdStyle.innerText;
        birdStyle.title = VEbirdStyle.title;
        if (VEbirdStyle.className.match(/MSVE_MapStyle_disabled/))
        {
            birdStyle.className += " disabled";
        }
    }
    var VElabels = document.getElementById("MSVE_navAction_showLabels");
    if (VElabels != null) {
        var showLabels = document.getElementById("top_showLabels").firstChild;
        showLabels.innerText = VElabels.innerText;
        showLabels.title = VElabels.title;
        if (VElabels.className.match(/MSVE_MapStyle_disabled/))
        {
            showLabels.className += " disabled";
        }
    }
}
function Set2DMode() {
    if (map == null)
        return;
    map.SetMapMode(VEMapMode.Mode2D);
}
function Set3DMode() {
    if (map == null)
        return;
    map.SetMapMode(VEMapMode.Mode3D);
}
function SetRoadStyle() {
    if (map == null)
        return;
    map.SetMapStyle(VEMapStyle.Road);
    var roadStyle = document.getElementById("top_roadStyle");
    SelectStyles(roadStyle);
}
function SetAerialStyle() {
    if (map == null)
        return;
    map.SetMapStyle(VEMapStyle.Hybrid);
    var aerialStyle = document.getElementById("top_aerialStyle");
    SelectStyles(aerialStyle);
}
function SetBirdStyle() {
    if (map == null)
        return;
    var birdStyle = document.getElementById("top_birdStyle");
    if (birdStyle.firstChild.className.match(/disabled/))
        return;
    map.SetMapStyle(VEMapStyle.BirdseyeHybrid);
    map.SetBirdseyeOrientation(VEOrientation.North);
    SelectStyles(birdStyle);
}
function SelectStyles(element) {
    var roadStyle = document.getElementById("top_roadStyle");
    roadStyle.firstChild.className = roadStyle.firstChild.className.replace(/\s*selected\s*/, '');
    var aerialStyle = document.getElementById("top_aerialStyle");
    aerialStyle.firstChild.className = aerialStyle.firstChild.className.replace(/\s*selected\s*/, '');
    var birdStyle = document.getElementById("top_birdStyle");
    birdStyle.firstChild.className = birdStyle.firstChild.className.replace(/\s*selected\s*/, '');
    
    if (element == roadStyle)
        roadStyle.firstChild.className += " selected";
    else if (element == aerialStyle)
        aerialStyle.firstChild.className += " selected";
    else if (element == birdStyle)
        birdStyle.firstChild.className += " selected";
}
function ToggleLabels() {
    if (map == null)
        return;
    var style = map.GetMapStyle();
    if (style == VEMapStyle.Road || style == VEMapStyle.Shaded)
        return;
    else if (style == VEMapStyle.Aerial)
        map.SetMapStyle(VEMapStyle.Hybrid);
    else if (style == VEMapStyle.Hybrid)
        map.SetMapStyle(VEMapStyle.Aerial);
    else if (style == VEMapStyle.BirdseyeHybrid)
        map.SetMapStyle(VEMapStyle.Birdseye);
    else
        map.SetMapStyle(VEMapStyle.BirdseyeHybrid);
}
function SetBirdControls(enabled)
{
    var birdStyle = document.getElementById("top_birdStyle").firstChild;
    if (enabled)
    {
        birdStyle.className = birdStyle.className.replace(/\s*disabled\s*/, '');
    }
    else
    {
        if (!birdStyle.className.match(/disabled/))
            birdStyle.className += " disabled";
    }
}
function BirdsEyeHandler(e)
{
    if (e.eventName == "onobliqueenter") {
        SetBirdControls(true);
    }
    else {
        SetBirdControls(false);
    }
}
function RotateRight() {
    var scene = map.GetBirdseyeScene();
    var orientation = scene.GetOrientation();
    var targetOrientation = null;
    if (orientation == VEOrientation.North)
        targetOrientation = VEOrientation.East;
    else if (orientation == VEOrientation.South)
        targetOrientation = VEOrientation.West;
    else if (orientation == VEOrientation.East)
        targetOrientation = VEOrientation.South;
    else if (orientation == VEOrientation.West)
        targetOrientation = VEOrientation.North;
    
    map.SetBirdseyeOrientation(targetOrientation);
    UpdateCompass(targetOrientation);
}
function RotateLeft() {
    var scene = map.GetBirdseyeScene();
    var orientation = scene.GetOrientation();
    var targetOrientation = null;
    if (orientation == VEOrientation.North)
        targetOrientation = VEOrientation.West;
    else if (orientation == VEOrientation.South)
        targetOrientation = VEOrientation.East;
    else if (orientation == VEOrientation.East)
        targetOrientation = VEOrientation.North;
    else if (orientation == VEOrientation.West)
        targetOrientation = VEOrientation.South;
    
    map.SetBirdseyeOrientation(targetOrientation);
    UpdateCompass(targetOrientation);
}
function UpdateCompass(orientation) {

    var north = document.getElementById("navCircleNorth");
    var east = document.getElementById("navCircleEast");
    var south = document.getElementById("navCircleSouth");
    var west = document.getElementById("navCircleWest");
    
    if (orientation == VEOrientation.North)
    {
        north.innerText = "N";
        east.innerText = "E";
        south.innerText = "S";
        west.innerText = "W";
    }
    else if (orientation == VEOrientation.East)
    {
        north.innerText = "E";
        east.innerText = "S";
        south.innerText = "W";
        west.innerText = "N";
    }
    else if (orientation == VEOrientation.South)
    {
        north.innerText = "S";
        east.innerText = "W";
        south.innerText = "N";
        west.innerText = "E";
    }
    else if (orientation == VEOrientation.West)
    {
        north.innerText = "W";
        east.innerText = "N";
        south.innerText = "E";
        west.innerText = "S";
    }
}
function MapStyleChangeHandler(e)
{
    if (e == null)
        return;
    
    var showLabels = document.getElementById("top_showLabels").firstChild;
    if (e.mapStyle == "r")
    {
        showLabels.className = "disabled";
    }
    else
    {
        showLabels.className = "";
    }
    
    var navLeft = document.getElementById("navLeft");
    if (e.mapStyle != "o" && e.mapStyle != "b")
        navLeft.className = "navLeftShort";
    else
        navLeft.className = "navLeftLong";
}
function ToggleControlSize() {
    var mapControls = document.getElementById("mapControls");
    mapControls.style.position = "relative";
    var controlContainer = document.getElementById("mapControlContainer");
    var anchor = document.getElementById("top_collapse").firstChild;
    
    if (parseInt(mapControls.offsetLeft) >= 0) {
        controlContainer.style.overflow = "hidden";
        mapControls.style.left = -488;
        // Print/Email is disabled
        if (IsFrenchPage())
            mapControls.style.left = -336;
        else
            mapControls.style.left = -369;
        anchor.className = "rightCollapse";
    }
    else {
        controlContainer.style.overflow = "visible";
        mapControls.style.left = 0;
        anchor.className = "";
    }
}
function MouseMoveHandler(e) {
    if (movingCustomerPin) {
        var loc = map.PixelToLatLong(new VEPixel(e.mapX, e.mapY));
        map.HideInfoBox();
        var shape = map.GetShapeByID(e.elementID);
        if (shape != null) {
            shape.SetPoints(loc);
            if (timerID != null)
                return;
            
            timerID = setInterval(ReverseGeocodeLocation, 333);
        }
    }

}
function MouseDownHandler(e) {
    if (e.elementID && e.leftMouseButton && e.shiftKey) {
        var shape = map.GetShapeByID(e.elementID);
        if (shape == locationShape) {
            map.vemapcontrol.EnableGeoCommunity(true);
            var shape = map.GetShapeByID(e.elementID);
            if (shape != null) {
                movingCustomerPin = true;
//                document.getElementById("mapDiv").style.cursor = 'Move';
            }
        }
    }
}
function MouseUpHandler(e) {
    if (movingCustomerPin && e.leftMouseButton) {
        map.vemapcontrol.EnableGeoCommunity(false);
        movingCustomerPin = false;
        if (timerID != null) {
            clearInterval(timerID);
            timerID = null;
            ReverseGeocodeLocation();
        }
//        document.getElementById("mapDiv").style.cursor = '';
    }
}
function ReverseGeocodeLocation() {
    map.FindLocations(locationShape.GetPoints()[0],
        function(location) {
            if (location == null || location.length <= 0)
                return;
            document.getElementById("location").value = location[0].Name;
            document.getElementById("customerLocation").value = location[0].Name;
            
            if (locationShape != null)
                locationShape.SetTitle(location[0].Name);
            
            UpdateDealers();
        });
}
function UpdateDealers() {
    for (var i = 0; i < dealerShapes.length; i++) {
        var shape = dealerShapes[i];
        if (shape == null)
            continue;

        var description = shape.GetDescription();
        description = description.replace(/value=\"[^\"]*\"/, 'value="' + GetCustomerAddress() + '"');
        shape.SetDescription(description);
    }
}

function OnMapMoved(e) {
    if (centeredShapeID != null) {
        var shape = map.GetShapeByID(centeredShapeID);
        if (shape != null) {
            setTimeout(function() {
                    var shape = map.GetShapeByID(centeredShapeID);
                    if (shape != null) {
                        ShowInfobox(shape);
                    }
                    centeredShapeID = null;
            }, 10);
        }
    }
    else if (e.eventName == "onpanend")
        PanZoomFindDealers();
}

function MapResize(e)
{
    // When the map is resized, Realign the position of the Mini Map
    RealignMiniMap();
}

function RealignMiniMap()
{
    // Realign the position of the Mini Map so it appears
    // where we want it - The Upper Right Corner
    var minimap = document.getElementById("MSVE_minimap");
    var xoffset = (GetMapWidth() - minimap.offsetWidth);
    map.ShowMiniMap(xoffset, 0);
   
    /// Hide the Mini Map resizer so the Mini Map cannot be resized
    document.getElementById("MSVE_minimap_resize").style.display = "none";
}

function GetMapWidth()
{  
    // Get the Width of the Map as an integer
    return document.getElementById("mapDiv").offsetWidth;
}
function GetMapHeight()
{
    // Get the Height of the Map as an integer
    return document.getElementById("mapDiv").offsetHeight;
}

function ParseDealers() {
    var data = document.getElementById(prefix + "dealerInfo").value;
    data = HtmlDecode(data);
    
    var xmlDoc;
    try //Internet Explorer
    {
        xmlDoc = new ActiveXObject('Microsoft.XMLDOM');
        xmlDoc.async = "false";
        xmlDoc.loadXML(data);
    }
    catch(e)
    {
        try //Firefox, Mozilla, Opera, etc.
        {
            parser = new DOMParser();
            xmlDoc = parser.parseFromString(data, "text/xml");
        }
        catch(e)
        {
            return null;
        }
    }
    
    return xmlDoc;
}
function ShowDealers(xmlDoc, ignoreCentering) {
    var markers = xmlDoc.getElementsByTagName('marker');
    if (markers.length <= 0) {
        HideLoadingIcon();
        return;
    }
    
    for (var i in dealerShapes)
    {
        var shape = dealerShapes[i];
        map.DeleteShape(shape);
    }
    dealerShapes = new Array();
    
    var address = GetCustomerAddress();
    
    var results = "";
    for (var i = 0; i < markers.length; i++) {
        var lat = markers[i].getAttribute('latitude');
        var lng = markers[i].getAttribute('longitude');
        var position = new VELatLong(lat, lng);

        var shape = new VEShape(VEShapeType.Pushpin, position);
        dealerLayer.AddShape(shape);

        var isServiceOnly = (markers[i].getAttribute('serviceOnly') == 'Y') ? true : false;
        var serviceOnlyText = '';
        if (isServiceOnly)
            serviceOnlyText = '<div class="partServiceOnly">' + $('div#serviceOnlyText').text() + '</div>';
        var title = '<div id="titleDiv" class="dealerTitle">' + (i+1) + '. ' + markers[i].getAttribute('name') + '</div>';

        var description = '';
        if (serviceOnlyText == '')
            description += '<div class="dealerDesc"><a class="detailLink" href="' + markers[i].getAttribute('href') + '" target="_blank">' + markers[i].getAttribute('href') + '</a></div>';
        else
            description += serviceOnlyText;
        description += '<div class="dealerDesc">' + markers[i].getAttribute('address1') + '</div>';
        if (markers[i].getAttribute('address2') != null)
            description += '<div class="dealerDesc">' + markers[i].getAttribute('address2') + '</div>';
        description += '<div class="dealerDesc">' + markers[i].getAttribute('city') + ', ' + markers[i].getAttribute('province') + ' ' + markers[i].getAttribute('postalCode') + '</div>';
        description += '<div class="dealerDesc">T: ' + markers[i].getAttribute('phone') + '</div>';
        description += '<div class="dealerDesc">F: ' + markers[i].getAttribute('fax') + '</div>';
        description += '<div class="dealerDesc" style="padding-bottom:5px"><hr />~' + markers[i].getAttribute('distance') + ' KM</div>';
        var directionText = document.getElementById("directionsText").value;
        description += '<div class="';
        if (IsFrenchPage())
            description += 'dealerDirections dealerDirectionsFR';
        else
            description += 'dealerDirections';
        description +='">' + directionText + '</div>';
        var inputName = shape.GetID() + "_input";
        description += '<div class="dealerInput"><input class="detailDirectionInput" style="margin-left:5px" type="text" id="' + inputName + '" name="' + inputName + '" value="' + address + '"/>';
        description += '<a ';
        if (IsFrenchPage())
            description += 'class="goFR detailDirection" ';
        else
            description += 'class="detailDirection" ';
        description += 'href="javascript:void(0)" onclick="GetDirections(\'' + shape.GetID() + '\',document.getElementById(\'' + inputName + '\').value)"></a></div>';

        description += '<script type="text/javascript">InitDetailGA();</script>';
        if (map.GetZoomLevel() <= 9)
            shape.SetCustomIcon(GetSmallIconURL());
        else
            shape.SetCustomIcon(GetLargeIconURL());
        shape.SetTitle(title);
        shape.SetDescription(description);
        
        dealerShapes[dealerShapes.length] = shape;
        markerPoints[markerPoints.length] = position;
        
        //results += "<li class='dealerLI' onmouseover=\"MouseOverSidebarItem(\'" + shape.GetID() + "\')\">";
        results += "<li class='dealerLI'>";
        results += '<div class="displayHidden data">' + shape.GetID() + '</div>';
        if (serviceOnlyText == '')
            results += '<a class="resultLink" href="' + markers[i].getAttribute('href') + '" target="_blank">' + (i+1) + '. ' + markers[i].getAttribute('name') + '</a>';
        else
            results += '<div class="resultLink">' + (i+1) + '. ' + markers[i].getAttribute('name') + '</div>';
        results += '<div class="addressResult">' + serviceOnlyText + '<div>' + markers[i].getAttribute('address1') + '</div>';
        if (markers[i].getAttribute('address2') != null)
            results += '<div>' + markers[i].getAttribute('address2') + '</div>';
        results += '<div>' + markers[i].getAttribute('city') + ', ' + markers[i].getAttribute('province') + ' ' + markers[i].getAttribute('postalCode') + '</div>';
        results += '<div>T: ' + markers[i].getAttribute('phone') + '</div>';
        results += '<div>F: ' + markers[i].getAttribute('fax') + '</div>';
        results += '<hr class="dealerLine"/>';
        results += '<div>~' + markers[i].getAttribute('distance') + ' KM</div>';
        results += '<a ';
        if (IsFrenchPage())
            results += 'class="getDirectionsFR resultDirection" ';
        else
            results += 'class="resultDirection" ';
        results += 'href="javascript:void(0);" onclick="GetDirections(\'' + shape.GetID() + '\')"></a>';
        if (i < markers.length - 1)
            results += '<div style="background-color:White;height:15px;width:100%;"></div></div>';
        else
            results += '</div>';
        results += "</li>";
    }
    
    if (results != "") {
        var legals = document.getElementById("Legals");
        if (!IsInternetExplorer()) 
            legals.style.top = -553;
        /*
        else
            legals.style.top = -795;
        */
        
        results = '<ul>' + results + "</ul>";
        
        var searchResultDiv = document.getElementById("searchResults");
        searchResultDiv.innerHTML = results;
        
        OpenSearchHeader();
        
        $('li.dealerLI').hover(
            function() {
                MouseOverSidebarItem($(this).find('div.data').text());
            },
            function() { }
        );
        
        var sidebarCollapse = document.getElementById("navSidebarCollapse");
        if (sidebarCollapse.style.display == "block")
        {
            EnlargeMap();
            HideLoadingIcon();
            return;
        }
        else {
            ShrinkMap();
            ResizeSidebar();
        }
    }
    
    if (!ignoreCentering) {
        map.SetMapView(markerPoints);
        
        var zoomLevel = map.GetZoomLevel();
        
        var customerPosition = GetCustomerLatLng();
        if (customerPosition != null)
            map.SetCenter(customerPosition);
        else if (markerPoints.length > 1)
            map.SetCenter(markerPoints[0]);
    }
    
    InitGA();
    HideLoadingIcon();
}
function EnlargeMap() {
    ignorePan = true;
    var sideBar = document.getElementById("sideBar");
    sideBar.style.display = "none";
    
    mapWidth = null;
    newMapWidth = 844;
    var mapDiv = document.getElementById("mapDiv");
    mapDiv.style.left = 1;
    if (IsInternetExplorer())
        newMapWidth = 842;
    mapDiv.style.width = newMapWidth;
    map.Resize(newMapWidth, 500);
    MapResize();
    
    var controlContainer = document.getElementById("mapControlContainer");
    controlContainer.style.left = 1;
    
    var sidebarCollapse = document.getElementById("navSidebarCollapse");
    sidebarCollapse.style.display = "block";
    //setTimeout(EnlargeMap, 25);
}
function ShrinkMap() {
    var sideBar = document.getElementById("sideBar");
    sideBar.style.display = "block";
    sideBar.style.border = "solid 1px #686860";
    sideBar.style.top = "9px";
    if (IsInternetExplorer()) {
        sideBar.style.top = "6px";
        sideBar.style.left = "0px";
    }
    sideBar.style.position = "relative";
    sideBar.style.height = "500px";

    if (mapWidth != 681) {
        mapWidth = 681;
        
        var mapDiv = document.getElementById("mapDiv");
        mapDiv.style.width = 681;
        mapDiv.style.left = "2px";
        
        var controlContainer = document.getElementById("mapControlContainer");
        controlContainer.style.left = mapDiv.style.left;

        if (IsInternetExplorer())
        {
            mapDiv.style.top = "6px";
            controlContainer.style.top = "-493px";
        }
        
        map.Resize(681, 500);
        MapResize();

        var sidebarCollapse = document.getElementById("navSidebarCollapse");
        sidebarCollapse.style.display = "none";
    }
}
function ResizeSidebar() {
    var searchHeader = document.getElementById("searchHeader");
    var searchResults = document.getElementById("searchResults");
    var directionsHeader = document.getElementById("directionsHeader");
    var directions = document.getElementById("directions");
    var resultHeight = 500;
    if (IsInternetExplorer())
        resultHeight = 499;
    if (directionsHeader.style.display == "none")
        resultHeight = resultHeight - searchHeader.offsetHeight;
    else
        resultHeight = resultHeight - searchHeader.offsetHeight - directionsHeader.offsetHeight;
    searchResults.style.height = resultHeight;
    directions.style.height = resultHeight;
}

function OpenSearchHeader() {
    var directionsHeader = document.getElementById("directionsHeader");
    if (directionsHeader.style.display != "none" &&
        directionsHeader.style.display != "") {
        directionsHeader.style.display = "block";
        directionsHeader.style.cursor = "pointer";
        directionsHeader.onclick = OpenDirectionHeader;
    }

    var directions = document.getElementById("directions");
    directions.style.display = "none";

    var searchResultDiv = document.getElementById("searchResults");
    searchResultDiv.style.display = "block";
    searchResultDiv.style.overflow = "auto";
    
    var searchHeader = document.getElementById("searchHeader");
    searchHeader.style.display = "block";
    searchHeader.style.cursor = "default";
    searchHeader.onclick = null;
}
function OpenDirectionHeader() {
    var searchHeader = document.getElementById("searchHeader");
    searchHeader.style.display = "block";
    searchHeader.style.cursor = "pointer";
    searchHeader.onclick = OpenSearchHeader;
    
    var searchResultsDiv = document.getElementById("searchResults");
    searchResultsDiv.style.display = "none";
    
    var directionsHeader = document.getElementById("directionsHeader");
    directionsHeader.style.display = "block";
    directionsHeader.style.cursor = "default";
    directionsHeader.onclick = null;
    
    var directions = document.getElementById("directions");
    directions.style.display = "block";
    directions.style.overflow = "auto";
}

function RemoveDirections() {
    map.DeleteRoute();
    map.DeleteShapeLayer(directionLayer);
    directionLayer = new VEShapeLayer();
    map.AddShapeLayer(directionLayer);
    showingRoute = false;
}
function GetDirections(shapeID, location) {
    ShowLoadingIcon();
    
    map.HideInfoBox();
    
    // remove all routes and directions
    RemoveDirections();
    
    var locations = new Array();
    
    var customerShape = map.GetShapeByID(locationID);
    var dealerShape  = map.GetShapeByID(shapeID);
    destinationDealershipID = shapeID;

    if (location == undefined || location == null)
        locations[0] = customerShape.GetPoints()[0];
    else
        locations[0] = location;
    locations[1] = dealerShape.GetPoints()[0];
    var options = new VERouteOptions();
//    options.DrawRoute = false;
    options.DistanceUnit = VERouteDistanceUnit.Kilometer;
    options.RouteColor = new VEColor(14, 30, 125, 1);
//    options.SetBestMapView = true;
    options.RouteCallback = GetDirectionsHandler;
    
    map.GetDirections(locations, options);
}
function GetDirectionsHandler(route) {
    if (route == null)
        return;

    OpenDirectionHeader();

    /*
    var routeShape = new VEShape(VEShapeType.Polyline, route.ShapePoints);
    directionLayer.AddShape(routeShape);
    routeShape.HideIcon();
    routeShape.SetLineWidth(5);
    routeShape.SetLineColor(new VEColor(14, 30, 125, 1));
    
    markerPoints = new Array();
    */
    
    showingRoute = true;
    
    var result = '<div style="text-align:center">' + round(route.Distance, 1, true) + " KM - ~" + round(route.Time/60, 0) + " mins</div>";
    result += '<hr />';
    result += '<div class="start" onmouseover="MouseOverSidebarItem(\'' + locationID +'\')"><div style="margin-left:40px">' + GetCustomerAddress() + '</div></div>';
    result += "<ul>";
    if (route.RouteLegs != null && route.RouteLegs.length > 0 &&
        route.RouteLegs[0].Itinerary != null) {
        var items = route.RouteLegs[0].Itinerary.Items;
        
        for (var i in items) {
            var step = items[i];
            
            markerPoints[markerPoints.length] = step.LatLong;
            
            var shape = step.Shape;
            if (i == 0 || i == route.RouteLegs[0].Itinerary.Items.length - 1) {
                if (shape != null) {
                    shape.Hide();
                }
                continue;
            }
            var title = shape.GetTitle();
            title = '<div id="titleDiv" class="directionTitle">' + title + '</div>';
            shape.SetTitle(title);
            /*
            else {
                shape = new VEShape(VEShapeType.Pushpin, step.LatLong);
                directionLayer.AddShape(shape);
                var number = parseInt(i)+1;
                shape.SetCustomIcon("<div class='pinStyle2'>" + number + "</div>");
                shape.SetTitle('Step ' + number);
                shape.SetDescription(step.Text);
            }
            */
            
            if (shape != null) {
                result += '<li style="clear:both" onmouseover="MouseOverSidebarItem(\'' + shape.GetID() + '\')">' + 
                          '<div><span>' + i + '</span>' + round(step.Distance,1, true) + ' KM</div>' + 
                          '<div class="directionText">' + step.Text + '</div></li>';
            }
            else
                result += '<li style="clear:both">' + 
                          '<div><span>' + i + '</span>' + round(step.Distance,1, true) + ' KM</div>' + 
                          '<div class="directionText">' + step.Text + '</div></li>';
        }
    }
    result += "</ul>";
    result += '<hr />';
    var dealership = map.GetShapeByID(destinationDealershipID);
    var dealerName = null;
    if (dealership != null)
        dealerName = dealership.GetTitle();
    dealerName = dealerName.replace(/\d+\. /, '');
    dealerName = dealerName.match(/<div.+>(.+)<.+div>/);
    dealerName =  RegExp.$1;
    result += '<div class="end" onmouseover="MouseOverSidebarItem(\'' + destinationDealershipID +'\')"><div style="margin-left:55px">' + dealerName + '</div></div>';

    /*
    map.SetMapView(markerPoints);
    
    var zoomLevel = map.GetZoomLevel();
    map.SetCenterAndZoom(GetCustomerLatLng(), zoomLevel-1);
    */
    var directions = document.getElementById("directions");
    directions.innerHTML = result;
    
    ResizeSidebar();
    HideLoadingIcon();
}
function RollOverControls() {
    var controls = document.getElementById("mapControlContainer");
    if (controls == null)
        return;

    if (IsInternetExplorer()) {
        controls.style.filter = "alpha(opacity=60)";
    }
    else {
        controls.style.MozOpacity = 1.0;
        controls.style.opacity = 1.0;
    }
    
//    if (parseFloat(controls.style.MozOpacity) <= 1.0)
//        setTimeout(function() {RollOverControls();}, 10);
}
function RollOutControls() {
    var controls = document.getElementById("mapControlContainer");
    if (controls == null)
        return;
    
    if (IsInternetExplorer()) {
        controls.style.filter = "alpha(opacity=30)";
    }
    else {
        controls.style.MozOpacity = 0.7;
        controls.style.opacity = 0.7;
    }
    
//    if (parseFloat(controls.style.opacity) > 0.7)
//        setTimeout(function() {RollOutControls();}, 10);
}
function RouteOver(e) {
    if (e == null)
        return;

    if(e || e.elementID) {
        var route = map.GetShapeByID(e);
        if (route == null)
            route = mape.GetShapeById(e.elementID);
        if (route == null || route.GetType() != VEShapeType.PolyLine)
            return;
        
        route.SetLineColor(new VEColor(25, 56, 229, 0.8));
    }
}
function RouteOut(e) {
    if(e.elementID) {
        var route = map.GetShapeByID(e.elementID);
        if (route == null || route.GetType() != VEShapeType.PolyLine)
            return;
        
        route.SetLineColor(new VEColor(14, 30, 125, 1));
    }
//document.getElementById("findDealers").value = e.elementID;
    return;
//    alert("routeOut");
//document.getElementById("findDealers").value = "routeOut";
    var route = map.GetShapeByID(shapeID);
    if (route == null)
        return;
}
function ShapeHandler(e)
{
    if (e.elementID != null) {
//        document.getElementById('findDealers').value = e.eventName + " event occurred on shape (id=" + e.elementID + ").";
        if (e.eventName == "onmouseover")
        {
            var shape = map.GetShapeByID(e.elementID);
            if (shape == null)
                return;
            
            if (shape.GetType() == VEShapeType.Pushpin)
            {
                UpdateInfoboxCSS(shape);
            }
            /*
            var route = map.GetShapeByID(e.elementID);
//            document.getElementById('findDealers').value = route.GetType() == VEShapeType.Polyline;
            if (route == null || route.GetType() != VEShapeType.Polyline)
                return;
            route.SetLineColor(new VEColor(25, 56, 229, 0.8));
            */
        }
        else if (e.eventName == "onmouseout")
        {
            var route = map.GetShapeByID(e.elementID);
//            document.getElementById('findDealers').value = route.GetType() == VEShapeType.Polyline;
            if (route == null || route.GetType() != VEShapeType.Polyline)
                return;
            
            route.SetLineColor(new VEColor(14, 30, 125, 1));
        }
    }
//    else
//        document.getElementById('findDealers').value = e.eventName + " event occurred on map. " + e.elementID;
}

function MouseOverSidebarItem(shapeID) {
    var infobox = document.getElementById("VEInfobox");
    if (lastInfoBoxShape == shapeID &&
        infobox != null && infobox.style.visibility != "hidden")
        return;
    lastInfoBoxShape = shapeID;
    map.HideInfoBox();
    
    
    ignorePan = true;
    var shape = map.GetShapeByID(shapeID);
    if (shape != null) {
        if (shape.GetType() == VEShapeType.Pushpin) {
            centeredShapeID = shapeID;
            map.HideInfoBox();
            var position = shape.GetPoints()[0];
            map.SetCenter(position);
            var center = map.GetCenter();
            
            if (round(center.Latitude,2,true) == round(position.Latitude,2,true) && 
                round(center.Longitude,2,true) == round(position.Longitude,2,true))
                ShowInfobox(shape);
                
        }
    }
}

function FindAddressAndDealers() {
    var address = document.getElementById("location").value;
    if (address == undefined || address == "")
        return;

    var condensedPostal = /(\w\d\w)(\d\w\d)/;
    address = address.replace(condensedPostal, '$1 $2');

    if (IsLocationDefault())
        return;
    
    ShowLoadingIcon();
    
    document.getElementById("customerLocation").value = address;
    
    document.getElementById("directionsHeader").style.display = "none";
    document.getElementById("directions").style.display = "none";
    document.getElementById("directions").innerHTML = "";

    markerPoints = new Array();
    dealerShapes = new Array();
    
    map.DeleteShapeLayer(dealerLayer);
    dealerLayer = new VEShapeLayer();
    map.AddShapeLayer(dealerLayer);

    map.HideInfoBox();
    map.DeleteAllShapes();
    RemoveDirections();
    map.Geocode(address, FindAddressHandler, new VEGeocodeOptions());
}
function FindAddressHandler(layer, resultsArray, places, hasMore, veErrorMessage) {
    var errorHeader = document.getElementById("errorHeader");
    var errorResult = document.getElementById("errorResult");
    if (places == null)
    {
//        alert('address not found');
        ShrinkMap();
        ResizeSidebar();
        var searchHeader = document.getElementById("searchHeader");
        searchHeader.style.display = "block";
        var searchResultDiv = document.getElementById("searchResults");
        searchResultDiv.style.display = "none";
        
        errorHeader.style.display = "block";
        errorResult.style.display = "block";

        var lat = document.getElementById(prefix + "lat");
        var lng = document.getElementById(prefix + "lng");
        if (lat != null)
            lat.value = "";
        if (lng != null)
            lng.value = "";

        HideLoadingIcon();
        return;
    }
    else {
        errorHeader.style.display = "none";
        errorResult.style.display = "none";
    }
    
    GetCustomerCoordinates(layer, resultsArray, places, hasMore, veErrorMessage)
    if (places != null && places.length > 0)
        FindDealers(places[0].Name);
    else
        FindDealers();
}
function FindDealers(locationString) {
    var domain = document.getElementById("domain").value;
    if (domain == undefined || domain == "")
        domain = "www.subaru.ca";
    
    var lat = document.getElementById(prefix + "lat");
    if (lat != null)
        lat = lat.value;
    var lng = document.getElementById(prefix + "lng");
    if (lng != null)
        lng = lng.value;
    
    ShowLoadingIcon();
    var url = domain + '/Map/2010/DealerFeed.aspx?latitude=' + lat + '&longitude=' + lng + '&maxRadius=' + 2000 + '&numResults=5';
    if (locationString != undefined)
        url += '&location=' + locationString;
    
    LoadXML(url, function(data) {
        $(prefix + "dealerInfo").val(data);
        
        ShowDealers(data, false);
        }      );
}

function PanMap(control) {
    if (control == null)
        return;
    
    if (control.id == "northArrow")
        map.StartContinuousPan(0,-10);
    else if (control.id == "southArrow")
        map.StartContinuousPan(0,10);
    else if (control.id == "eastArrow")
        map.StartContinuousPan(10,0);
    else if (control.id == "westArrow")
        map.StartContinuousPan(-10,0);
}
function PanMapStop() {
    if (map == null)
        return;
    
    map.EndContinuousPan();
}

function StartPan() {
    panStarted = true;
    panStartLatLng = map.GetCenter();
}
function PanZoomFindDealers() {
    if (ignorePan) {
        ignorePan = false;
        return;
    }

    if (IsLocationDefault())
        return;

    if (document.getElementById(prefix + "lat").value == "" || 
        document.getElementById(prefix + "lng").value == "")
        return;
    if (!panStarted)
        return;
    if (panStartLatLng == null)
        return;
    var center = map.GetCenter();
    if (round(center.Latitude,1) == round(panStartLatLng.Latitude,1) && 
        round(center.Longitude,1) == round(panStartLatLng.Longitude,1)) {
        return;
    }
    
    ShowLoadingIcon();
    
    panStarted = false;
    panStartLatLng = null;
    
    var domain = document.getElementById("domain").value;
    if (domain == undefined || domain == "")
        domain = "www.subaru.ca";
    
    var latLng = GetCustomerLatLng();
    var center = map.GetCenter();
    var url = domain + '/Map/2010/DealerFeed.aspx?latitude=' + center.Latitude + '&longitude=' + center.Longitude + '&maxRadius=' + 2000 + '&numResults=10';
    url += '&startLatitude=' + latLng.Latitude + '&startLongitude=' + latLng.Longitude;
    
    LoadXML(url, function(data) {
        $(prefix + "dealerInfo").val(data);
        
        ShowDealers(data, true);
        }
    );
}

function UpdateInfoboxCSS(shape)
{
    setTimeout(function() {
        var infobox = document.getElementById("VEInfobox");
        var beak = document.getElementById("VEInfoboxBeak");
        var title = shape.GetTitle();
        var progress = infobox.nextSibling;
        
        var top = parseInt(progress.style.top);

        if (title != null) {
            if (title.match(/dealerTitle/))
            {
                top = top + 18;
                infobox.style.top = top +"px"
        
                beak.style.top = "-3px"
                beak.style.marginTop = "0px";
            }
            else if (title.match(/locationTitle/))
            {
                beak.style.marginTop = "6px";
            }
        }
        infobox.style.marginTop = "0px";
        
        
        if (!IsInternetExplorer()) {
            var pixelPos = map.LatLongToPixel(shape.GetPoints()[0]);
            if (pixelPos.x > 500) {
                infobox.className = "ero-rightBeak ero";
                infobox.style.left = parseInt(infobox.style.left) - infobox.clientWidth - beak.clientWidth - 30;
                beak.style.left = infobox.clientWidth - 15;
            }
            else {
                infobox.className = "ero-leftBeak ero";
                beak.style.left = "3px";
            }
        }

        var titleDiv = document.getElementById("titleDiv");
        if (titleDiv == null)
            return;
        var VETitleDiv = titleDiv.parentNode;
        var VEBodyDiv = VETitleDiv.nextSibling;
        if (titleDiv.className == "directionTitle") {
            VETitleDiv.className = "DirectionPushpinTitle";
            VEBodyDiv.className  = "DirectionPushpinBody";
            if (infobox.className.match(/rightBeak/)) {
                beak.className = "DirectionRightBeak";
                if (!IsInternetExplorer()) {
                    beak.style.left = infobox.clientWidth - 15;
                    infobox.style.left = parseInt(progress.style.left) - infobox.clientWidth - beak.clientWidth + 10;
                }
            }
            else
                beak.className = "DirectionLeftBeak";
            infobox.style.top = top + 14;
            beak.style.top = "-3px"
            beak.style.marginTop = "0px";
        }
        else {
            VETitleDiv.className = "VE_Pushpin_Popup_Title";
            VEBodyDiv.className  = "VE_Pushpin_Popup_Body";
            beak.className = "ero-beak";
        }
    }, 10);
}

function UnloadMap()
{
    if (map != null) {
        map.Dispose();
        map = null;
    }
}

function ZoomEndHandler(e) {
    if (dealerShapes == null || dealerShapes.length <= 0)
        return;

    var zoomLevel = map.GetZoomLevel();
    for (var i in dealerShapes) {
        var shape = dealerShapes[i];
        if (shape == null)
            break;
        
        if (zoomLevel <= 9)
            shape.SetCustomIcon(GetSmallIconURL());
        else
            shape.SetCustomIcon(GetLargeIconURL());
    }
}

function ZoomIn() {
    if (map == null)
        return;
    map.HideInfoBox();
    map.ZoomIn();
}
function ZoomOut() {
    if (map == null)
        return;
    map.HideInfoBox();
    map.ZoomOut();
}

function LoadXML(url, callback) {
    var xmlrequest = null;
    if (window.XMLHttpRequest) {
        xmlrequest = new XMLHttpRequest();
    }
    else if (window.ActiveXObject) {
        xmlrequest = new ActiveXObject('Microsoft.XMLHTTP')
    }
    else {
        return;
    }
    
    xmlrequest.onreadystatechange = function() {
        if (xmlrequest.readyState == 4)
        {
            if (xmlrequest.status == 200) {
                callback(xmlrequest.responseXML);
            }
        }
    };
    
    xmlrequest.open("GET", url, true);
    xmlrequest.send(null);
}

function round(value, decimals, roundUp)
{
    if (roundUp)
        return Math.round(value*Math.pow(10,decimals))/Math.pow(10,decimals);
    else
        return Math.floor(value*Math.pow(10,decimals))/Math.pow(10,decimals);
}

// HtmlDecode http://blogs.msdn.com/aoakley/archive/2003/11/12/49645.aspx
//   client side version of the useful Server.HtmlDecode method
//   takes one string (encoded) and returns another (decoded)
function HtmlDecode(s)
{
      var out = "";
      if (s==null) return;
 
      var l = s.length;
      for (var i=0; i<l; i++)
      {
            var ch = s.charAt(i);
           
            if (ch == '&')
            {
                  var semicolonIndex = s.indexOf(';', i+1);
                 
            if (semicolonIndex > 0)
            {
                        var entity = s.substring(i + 1, semicolonIndex);
                        if (entity.length > 1 && entity.charAt(0) == '#')
                        {
                              if (entity.charAt(1) == 'x' || entity.charAt(1) == 'X')
                                    ch = String.fromCharCode(eval('0'+entity.substring(1)));
                              else
                                    ch = String.fromCharCode(eval(entity.substring(1)));
                        }
                    else
                      {
                              switch (entity)
                              {
                                    case 'quot': ch = String.fromCharCode(0x0022); break;
                                    case 'amp': ch = String.fromCharCode(0x0026); break;
                                    case 'lt': ch = String.fromCharCode(0x003c); break;
                                    case 'gt': ch = String.fromCharCode(0x003e); break;
                                    case 'nbsp': ch = String.fromCharCode(0x00a0); break;
                                    case 'iexcl': ch = String.fromCharCode(0x00a1); break;
                                    case 'cent': ch = String.fromCharCode(0x00a2); break;
                                    case 'pound': ch = String.fromCharCode(0x00a3); break;
                                    case 'curren': ch = String.fromCharCode(0x00a4); break;
                                    case 'yen': ch = String.fromCharCode(0x00a5); break;
                                    case 'brvbar': ch = String.fromCharCode(0x00a6); break;
                                    case 'sect': ch = String.fromCharCode(0x00a7); break;
                                    case 'uml': ch = String.fromCharCode(0x00a8); break;
                                    case 'copy': ch = String.fromCharCode(0x00a9); break;
                                    case 'ordf': ch = String.fromCharCode(0x00aa); break;
                                    case 'laquo': ch = String.fromCharCode(0x00ab); break;
                                    case 'not': ch = String.fromCharCode(0x00ac); break;
                                    case 'shy': ch = String.fromCharCode(0x00ad); break;
                                    case 'reg': ch = String.fromCharCode(0x00ae); break;
                                    case 'macr': ch = String.fromCharCode(0x00af); break;
                                    case 'deg': ch = String.fromCharCode(0x00b0); break;
                                    case 'plusmn': ch = String.fromCharCode(0x00b1); break;
                                    case 'sup2': ch = String.fromCharCode(0x00b2); break;
                                    case 'sup3': ch = String.fromCharCode(0x00b3); break;
                                    case 'acute': ch = String.fromCharCode(0x00b4); break;
                                    case 'micro': ch = String.fromCharCode(0x00b5); break;
                                    case 'para': ch = String.fromCharCode(0x00b6); break;
                                    case 'middot': ch = String.fromCharCode(0x00b7); break;
                                    case 'cedil': ch = String.fromCharCode(0x00b8); break;
                                    case 'sup1': ch = String.fromCharCode(0x00b9); break;
                                    case 'ordm': ch = String.fromCharCode(0x00ba); break;
                                    case 'raquo': ch = String.fromCharCode(0x00bb); break;
                                    case 'frac14': ch = String.fromCharCode(0x00bc); break;
                                    case 'frac12': ch = String.fromCharCode(0x00bd); break;
                                    case 'frac34': ch = String.fromCharCode(0x00be); break;
                                    case 'iquest': ch = String.fromCharCode(0x00bf); break;
                                    case 'Agrave': ch = String.fromCharCode(0x00c0); break;
                                    case 'Aacute': ch = String.fromCharCode(0x00c1); break;
                                    case 'Acirc': ch = String.fromCharCode(0x00c2); break;
                                    case 'Atilde': ch = String.fromCharCode(0x00c3); break;
                                    case 'Auml': ch = String.fromCharCode(0x00c4); break;
                                    case 'Aring': ch = String.fromCharCode(0x00c5); break;
                                    case 'AElig': ch = String.fromCharCode(0x00c6); break;
                                    case 'Ccedil': ch = String.fromCharCode(0x00c7); break;
                                    case 'Egrave': ch = String.fromCharCode(0x00c8); break;
                                    case 'Eacute': ch = String.fromCharCode(0x00c9); break;
                                    case 'Ecirc': ch = String.fromCharCode(0x00ca); break;
                                    case 'Euml': ch = String.fromCharCode(0x00cb); break;
                                    case 'Igrave': ch = String.fromCharCode(0x00cc); break;
                                    case 'Iacute': ch = String.fromCharCode(0x00cd); break;
                                    case 'Icirc': ch = String.fromCharCode(0x00ce ); break;
                                    case 'Iuml': ch = String.fromCharCode(0x00cf); break;
                                    case 'ETH': ch = String.fromCharCode(0x00d0); break;
                                    case 'Ntilde': ch = String.fromCharCode(0x00d1); break;
                                    case 'Ograve': ch = String.fromCharCode(0x00d2); break;
                                    case 'Oacute': ch = String.fromCharCode(0x00d3); break;
                                    case 'Ocirc': ch = String.fromCharCode(0x00d4); break;
                                    case 'Otilde': ch = String.fromCharCode(0x00d5); break;
                                    case 'Ouml': ch = String.fromCharCode(0x00d6); break;
                                    case 'times': ch = String.fromCharCode(0x00d7); break;
                                    case 'Oslash': ch = String.fromCharCode(0x00d8); break;
                                    case 'Ugrave': ch = String.fromCharCode(0x00d9); break;
                                    case 'Uacute': ch = String.fromCharCode(0x00da); break;
                                    case 'Ucirc': ch = String.fromCharCode(0x00db); break;
                                    case 'Uuml': ch = String.fromCharCode(0x00dc); break;
                                    case 'Yacute': ch = String.fromCharCode(0x00dd); break;
                                    case 'THORN': ch = String.fromCharCode(0x00de); break;
                                    case 'szlig': ch = String.fromCharCode(0x00df); break;
                                    case 'agrave': ch = String.fromCharCode(0x00e0); break;
                                    case 'aacute': ch = String.fromCharCode(0x00e1); break;
                                    case 'acirc': ch = String.fromCharCode(0x00e2); break;
                                    case 'atilde': ch = String.fromCharCode(0x00e3); break;
                                    case 'auml': ch = String.fromCharCode(0x00e4); break;
                                    case 'aring': ch = String.fromCharCode(0x00e5); break;
                                    case 'aelig': ch = String.fromCharCode(0x00e6); break;
                                    case 'ccedil': ch = String.fromCharCode(0x00e7); break;
                                    case 'egrave': ch = String.fromCharCode(0x00e8); break;
                                    case 'eacute': ch = String.fromCharCode(0x00e9); break;
                                    case 'ecirc': ch = String.fromCharCode(0x00ea); break;
                                    case 'euml': ch = String.fromCharCode(0x00eb); break;
                                    case 'igrave': ch = String.fromCharCode(0x00ec); break;
                                    case 'iacute': ch = String.fromCharCode(0x00ed); break;
                                    case 'icirc': ch = String.fromCharCode(0x00ee); break;
                                    case 'iuml': ch = String.fromCharCode(0x00ef); break;
                                    case 'eth': ch = String.fromCharCode(0x00f0); break;
                                    case 'ntilde': ch = String.fromCharCode(0x00f1); break;
                                    case 'ograve': ch = String.fromCharCode(0x00f2); break;
                                    case 'oacute': ch = String.fromCharCode(0x00f3); break;
                                    case 'ocirc': ch = String.fromCharCode(0x00f4); break;
                                    case 'otilde': ch = String.fromCharCode(0x00f5); break;
                                    case 'ouml': ch = String.fromCharCode(0x00f6); break;
                                    case 'divide': ch = String.fromCharCode(0x00f7); break;
                                    case 'oslash': ch = String.fromCharCode(0x00f8); break;
                                    case 'ugrave': ch = String.fromCharCode(0x00f9); break;
                                    case 'uacute': ch = String.fromCharCode(0x00fa); break;
                                    case 'ucirc': ch = String.fromCharCode(0x00fb); break;
                                    case 'uuml': ch = String.fromCharCode(0x00fc); break;
                                    case 'yacute': ch = String.fromCharCode(0x00fd); break;
                                    case 'thorn': ch = String.fromCharCode(0x00fe); break;
                                    case 'yuml': ch = String.fromCharCode(0x00ff); break;
                                    case 'OElig': ch = String.fromCharCode(0x0152); break;
                                    case 'oelig': ch = String.fromCharCode(0x0153); break;
                                    case 'Scaron': ch = String.fromCharCode(0x0160); break;
                                    case 'scaron': ch = String.fromCharCode(0x0161); break;
                                    case 'Yuml': ch = String.fromCharCode(0x0178); break;
                                    case 'fnof': ch = String.fromCharCode(0x0192); break;
                                    case 'circ': ch = String.fromCharCode(0x02c6); break;
                                    case 'tilde': ch = String.fromCharCode(0x02dc); break;
                                    case 'Alpha': ch = String.fromCharCode(0x0391); break;
                                    case 'Beta': ch = String.fromCharCode(0x0392); break;
                                    case 'Gamma': ch = String.fromCharCode(0x0393); break;
                                    case 'Delta': ch = String.fromCharCode(0x0394); break;
                                    case 'Epsilon': ch = String.fromCharCode(0x0395); break;
                                    case 'Zeta': ch = String.fromCharCode(0x0396); break;
                                    case 'Eta': ch = String.fromCharCode(0x0397); break;
                                    case 'Theta': ch = String.fromCharCode(0x0398); break;
                                    case 'Iota': ch = String.fromCharCode(0x0399); break;
                                    case 'Kappa': ch = String.fromCharCode(0x039a); break;
                                    case 'Lambda': ch = String.fromCharCode(0x039b); break;
                                    case 'Mu': ch = String.fromCharCode(0x039c); break;
                                    case 'Nu': ch = String.fromCharCode(0x039d); break;
                                    case 'Xi': ch = String.fromCharCode(0x039e); break;
                                    case 'Omicron': ch = String.fromCharCode(0x039f); break;
                                    case 'Pi': ch = String.fromCharCode(0x03a0); break;
                                    case ' Rho ': ch = String.fromCharCode(0x03a1); break;
                                    case 'Sigma': ch = String.fromCharCode(0x03a3); break;
                                    case 'Tau': ch = String.fromCharCode(0x03a4); break;
                                    case 'Upsilon': ch = String.fromCharCode(0x03a5); break;
                                    case 'Phi': ch = String.fromCharCode(0x03a6); break;
                                    case 'Chi': ch = String.fromCharCode(0x03a7); break;
                                    case 'Psi': ch = String.fromCharCode(0x03a8); break;
                                    case 'Omega': ch = String.fromCharCode(0x03a9); break;
                                    case 'alpha': ch = String.fromCharCode(0x03b1); break;
                                    case 'beta': ch = String.fromCharCode(0x03b2); break;
                                    case 'gamma': ch = String.fromCharCode(0x03b3); break;
                                    case 'delta': ch = String.fromCharCode(0x03b4); break;
                                    case 'epsilon': ch = String.fromCharCode(0x03b5); break;
                                    case 'zeta': ch = String.fromCharCode(0x03b6); break;
                                    case 'eta': ch = String.fromCharCode(0x03b7); break;
                                    case 'theta': ch = String.fromCharCode(0x03b8); break;
                                    case 'iota': ch = String.fromCharCode(0x03b9); break;
                                    case 'kappa': ch = String.fromCharCode(0x03ba); break;
                                    case 'lambda': ch = String.fromCharCode(0x03bb); break;
                                    case 'mu': ch = String.fromCharCode(0x03bc); break;
                                    case 'nu': ch = String.fromCharCode(0x03bd); break;
                                    case 'xi': ch = String.fromCharCode(0x03be); break;
                                    case 'omicron': ch = String.fromCharCode(0x03bf); break;
                                    case 'pi': ch = String.fromCharCode(0x03c0); break;
                                    case 'rho': ch = String.fromCharCode(0x03c1); break;
                                    case 'sigmaf': ch = String.fromCharCode(0x03c2); break;
                                    case 'sigma': ch = String.fromCharCode(0x03c3); break;
                                    case 'tau': ch = String.fromCharCode(0x03c4); break;
                                    case 'upsilon': ch = String.fromCharCode(0x03c5); break;
                                    case 'phi': ch = String.fromCharCode(0x03c6); break;
                                    case 'chi': ch = String.fromCharCode(0x03c7); break;
                                    case 'psi': ch = String.fromCharCode(0x03c8); break;
                                    case 'omega': ch = String.fromCharCode(0x03c9); break;
                                    case 'thetasym': ch = String.fromCharCode(0x03d1); break;
                                    case 'upsih': ch = String.fromCharCode(0x03d2); break;
                                    case 'piv': ch = String.fromCharCode(0x03d6); break;
                                    case 'ensp': ch = String.fromCharCode(0x2002); break;
                                    case 'emsp': ch = String.fromCharCode(0x2003); break;
                                    case 'thinsp': ch = String.fromCharCode(0x2009); break;
                                    case 'zwnj': ch = String.fromCharCode(0x200c); break;
                                    case 'zwj': ch = String.fromCharCode(0x200d); break;
                                    case 'lrm': ch = String.fromCharCode(0x200e); break;
                                    case 'rlm': ch = String.fromCharCode(0x200f); break;
                                    case 'ndash': ch = String.fromCharCode(0x2013); break;
                                    case 'mdash': ch = String.fromCharCode(0x2014); break;
                                    case 'lsquo': ch = String.fromCharCode(0x2018); break;
                                    case 'rsquo': ch = String.fromCharCode(0x2019); break;
                                    case 'sbquo': ch = String.fromCharCode(0x201a); break;
                                    case 'ldquo': ch = String.fromCharCode(0x201c); break;
                                    case 'rdquo': ch = String.fromCharCode(0x201d); break;
                                    case 'bdquo': ch = String.fromCharCode(0x201e); break;
                                    case 'dagger': ch = String.fromCharCode(0x2020); break;
                                    case 'Dagger': ch = String.fromCharCode(0x2021); break;
                                    case 'bull': ch = String.fromCharCode(0x2022); break;
                                    case 'hellip': ch = String.fromCharCode(0x2026); break;
                                    case 'permil': ch = String.fromCharCode(0x2030); break;
                                    case 'prime': ch = String.fromCharCode(0x2032); break;
                                    case 'Prime': ch = String.fromCharCode(0x2033); break;
                                    case 'lsaquo': ch = String.fromCharCode(0x2039); break;
                                    case 'rsaquo': ch = String.fromCharCode(0x203a); break;
                                    case 'oline': ch = String.fromCharCode(0x203e); break;
                                    case 'frasl': ch = String.fromCharCode(0x2044); break;
                                    case 'euro': ch = String.fromCharCode(0x20ac); break;
                                    case 'image': ch = String.fromCharCode(0x2111); break;
                                    case 'weierp': ch = String.fromCharCode(0x2118); break;
                                    case 'real': ch = String.fromCharCode(0x211c); break;
                                    case 'trade': ch = String.fromCharCode(0x2122); break;
                                    case 'alefsym': ch = String.fromCharCode(0x2135); break;
                                    case 'larr': ch = String.fromCharCode(0x2190); break;
                                    case 'uarr': ch = String.fromCharCode(0x2191); break;
                                    case 'rarr': ch = String.fromCharCode(0x2192); break;
                                    case 'darr': ch = String.fromCharCode(0x2193); break;
                                    case 'harr': ch = String.fromCharCode(0x2194); break;
                                    case 'crarr': ch = String.fromCharCode(0x21b5); break;
                                    case 'lArr': ch = String.fromCharCode(0x21d0); break;
                                    case 'uArr': ch = String.fromCharCode(0x21d1); break;
                                    case 'rArr': ch = String.fromCharCode(0x21d2); break;
                                    case 'dArr': ch = String.fromCharCode(0x21d3); break;
                                    case 'hArr': ch = String.fromCharCode(0x21d4); break;
                                    case 'forall': ch = String.fromCharCode(0x2200); break;
                                    case 'part': ch = String.fromCharCode(0x2202); break;
                                    case 'exist': ch = String.fromCharCode(0x2203); break;
                                    case 'empty': ch = String.fromCharCode(0x2205); break;
                                    case 'nabla': ch = String.fromCharCode(0x2207); break;
                                    case 'isin': ch = String.fromCharCode(0x2208); break;
                                    case 'notin': ch = String.fromCharCode(0x2209); break;
                                    case 'ni': ch = String.fromCharCode(0x220b); break;
                                    case 'prod': ch = String.fromCharCode(0x220f); break;
                                    case 'sum': ch = String.fromCharCode(0x2211); break;
                                    case 'minus': ch = String.fromCharCode(0x2212); break;
                                    case 'lowast': ch = String.fromCharCode(0x2217); break;
                                    case 'radic': ch = String.fromCharCode(0x221a); break;
                                    case 'prop': ch = String.fromCharCode(0x221d); break;
                                    case 'infin': ch = String.fromCharCode(0x221e); break;
                                    case 'ang': ch = String.fromCharCode(0x2220); break;
                                    case 'and': ch = String.fromCharCode(0x2227); break;
                                    case 'or': ch = String.fromCharCode(0x2228); break;
                                    case 'cap': ch = String.fromCharCode(0x2229); break;
                                    case 'cup': ch = String.fromCharCode(0x222a); break;
                                    case 'int': ch = String.fromCharCode(0x222b); break;
                                    case 'there4': ch = String.fromCharCode(0x2234); break;
                                    case 'sim': ch = String.fromCharCode(0x223c); break;
                                    case 'cong': ch = String.fromCharCode(0x2245); break;
                                    case 'asymp': ch = String.fromCharCode(0x2248); break;
                                    case 'ne': ch = String.fromCharCode(0x2260); break;
                                    case 'equiv': ch = String.fromCharCode(0x2261); break;
                                    case 'le': ch = String.fromCharCode(0x2264); break;
                                    case 'ge': ch = String.fromCharCode(0x2265); break;
                                    case 'sub': ch = String.fromCharCode(0x2282); break;
                                    case 'sup': ch = String.fromCharCode(0x2283); break;
                                    case 'nsub': ch = String.fromCharCode(0x2284); break;
                                    case 'sube': ch = String.fromCharCode(0x2286); break;
                                    case 'supe': ch = String.fromCharCode(0x2287); break;
                                    case 'oplus': ch = String.fromCharCode(0x2295); break;
                                    case 'otimes': ch = String.fromCharCode(0x2297); break;
                                    case 'perp': ch = String.fromCharCode(0x22a5); break;
                                    case 'sdot': ch = String.fromCharCode(0x22c5); break;
                                    case 'lceil': ch = String.fromCharCode(0x2308); break;
                                    case 'rceil': ch = String.fromCharCode(0x2309); break;
                                    case 'lfloor': ch = String.fromCharCode(0x230a); break;
                                    case 'rfloor': ch = String.fromCharCode(0x230b); break;
                                    case 'lang': ch = String.fromCharCode(0x2329); break;
                                    case 'rang': ch = String.fromCharCode(0x232a); break;
                                    case 'loz': ch = String.fromCharCode(0x25ca); break;
                                    case 'spades': ch = String.fromCharCode(0x2660); break;
                                    case 'clubs': ch = String.fromCharCode(0x2663); break;
                                    case 'hearts': ch = String.fromCharCode(0x2665); break;
                                    case 'diams': ch = String.fromCharCode(0x2666); break;
                                    default: ch = ''; break;
                              }
                        }
                        i = semicolonIndex;
                  }
            }
           
            out += ch;
      }
 
      return out;
}
