var CommonMap = 
{
    getZoomLevel: function()
    {
        if (MapMode.getMapMode() != 'app')
            return hittaMap.map.getZoom();
        
        return TDapplet.getZoomLevel();
    }             
}


/**
 * Search queue
 *
 * Optimized for speedy searches. Based on the assumption that no human is going 
 * to perform back to back searches in the space of 400ms and actually be able
 * to comprehend the results.
 *
 * This queue culls consecutive searches that are registered within a 400ms time span.
 *
 * Could actually make this into a priority queue instead - but not necessary at 
 * this stage.
 */
/*
var MapSearchQueue = {

    queue: [],
    
    timer: null,
    
    push: function(args) {
    
        var me = MapSearchQueue;
        
        if (me.timer) { clearTimeout(me.timer); }
        
        me.queue.push(args);
        me.timer = setTimeout("MapSearchQueue.search()", 400);
    },
    
    search: function() {
    
        var me = MapSearchQueue;    
        var args = me.queue[me.queue.length - 1];
        
        me.queue = [];
        
        MapSearch.queryAjax.apply(MapSearch, args);
    }   
};
*/

function MapSearchQueueItem(func, params) {
    this.func = func;
    this.params = params;
}


var MapSearchQueue = {

    queue: [],

    timer: null,

    push: function(item) {

        var me = MapSearchQueue;

        if (me.timer) { clearTimeout(me.timer); }

        me.queue.push(item);
        me.timer = setTimeout("MapSearchQueue.search()", 400);
    },

    search: function() {

        var me = MapSearchQueue;
        var item = me.queue[me.queue.length - 1];

        me.queue = [];

        //MapSearch.queryAjax.apply(MapSearch, args);
        item.func.apply(MapSearch, item.params);
    }
};


var MapSearchArea = 
{
    global: 1,
    region: 2
}

var MapSearchBook = 
{
    all: 1,
    white: 2,
    pink: 3,
    none: 4
}

var SearchFieldUsage =
{
    both: 1,
    who: 2,
    where: 3,
    
    getUsage: function(who, where)
    {
        if (who != '' && where != '')
            return SearchFieldUsage.both;
        
        if (who != '')
            return SearchFieldUsage.who;
            
        return SearchFieldUsage.where;
    }
}

function MapSearchBoundary(x1, y1, x2, y2, x3, y3, x4, y4) {
    this.x1 = x1;
    this.y1 = y1;
    this.x2 = x2;
    this.y2 = y2;
    this.x3 = x3;
    this.y3 = y3;
    this.x4 = x4;
    this.y4 = y4; 

    if (typeof(x1) == 'undefined') {
        if (MapMode.getMapMode() == 'app') {            
            try {
                this.getBoundaryFromApp();       
            } catch(ex) {
                this.getBoundaryFromMap();
            }
        } else {
            this.getBoundaryFromMap();
        }
    }
    
    // These variables are easier to understand.
    // Variable names valid for 2D map only.
    this.westing = this.x1;
    this.southing = this.y1;
    this.easting = this.x2;
    this.northing = this.y2;
}

MapSearchBoundary.prototype.getBoundaryFromMap = function() {
    var boundary = hittaMap.map.getBounds();

    this.x1 = boundary.sw.east;  //minX
    this.y1 = boundary.sw.north; //minY
    this.x2 = boundary.ne.east;  //maxX
    this.y2 = boundary.ne.north; //maxY
};

MapSearchBoundary.prototype.getBoundaryFromApp = function() {
    var boundary = TDapplet.getBoundary();

    this.x1 = Math.round(boundary[1]);
    this.y1 = Math.round(boundary[0]);
    this.x2 = Math.round(boundary[7]);
    this.y2 = Math.round(boundary[6]);
    this.x3 = Math.round(boundary[3]);
    this.y3 = Math.round(boundary[2]);
    this.x4 = Math.round(boundary[5]);
    this.y4 = Math.round(boundary[4]);
};

// Crops the boundary, subtracting the areas of the hit list and the toolbars so only the viewable area remains.
MapSearchBoundary.prototype.crop = function(boundary) {
    if (MapMode.getMapMode() != 'app') {
        var deltaX = MapSearch.getHitlistWidth(true) * ZOOM_LEVELS[10 - hittaMap.map.getZoom()];
        this.x1 = this.westing = Math.round(this.x1 + deltaX); // träfflistan
        if (MapMode.getMapMode() != 'mj') {
            var deltaY = _MapToolbarsTop.getHeight() * ZOOM_LEVELS[10 - hittaMap.map.getZoom()];
            this.y2 = this.northing = Math.round(this.y2 - deltaY); //toolbars
        }
    }
};

var KartPrio = {
    kartPrioVkiidsArray: [],
    kartPrioData: {},
    noOfKartPrioHits: 0,
    randomHitList: [],

    HITS_PER_PAGE: 20,

    /**
    * Init KartPrio state with response from queryAjax callback.
    */
    init: function (response) {

        var header = response.value.Tables[0].Rows[0];

        KartPrio.noOfKartPrioHits = header.NoOfKartPrioHitsReturned;

        // do not overwrite existing KartPrio state, and make sure header includes data
        if (KartPrio.kartPrioVkiidsArray.length > 0 || !header.KartPrioVkiids) {
            return;
        }

        // Get our prioratized VKIID's
        KartPrio.kartPrioVkiidsArray = header.KartPrioVkiids.split(';');

        // Save the Image src-links
        var kartPrioLinksArray = header.KartPrioLinks.split(';');

        KartPrio.kartPrioData = {};
        for (var i = 0; i < KartPrio.kartPrioVkiidsArray.length; i++) {
            KartPrio.kartPrioData[KartPrio.kartPrioVkiidsArray[i]] = {
                link: kartPrioLinksArray[i],
                closed: false
            }
        }

        // get locations of kart prio to later determine if they should be included in region search
        var pinkTable = response.value.Tables[2];
        for (var i = 0; i < pinkTable.Rows.length; i++) {
            var row = pinkTable.Rows[i];
            if (KartPrio.isPrio(row.Vkiid)) {
                KartPrio.kartPrioData[row.Vkiid].point = new HPointRT90(row.Xpos, row.Ypos);
            } else {
                break; // KartPrio always first in result
            }
        }

        if (MapSearch.isNewSearch) {
            var NUMBER_OF_MAP_HITS = 2;
            var tempRandomList = KartPrio.kartPrioVkiidsArray.length >= NUMBER_OF_MAP_HITS ? generateRandomNumbers(0, KartPrio.kartPrioVkiidsArray.length - 1, NUMBER_OF_MAP_HITS) : [0];

            // Create an Array with 2 random available Vkiid's
            KartPrio.randomHitList = [];

            var north = null;
            var northVkiid = "";

            for (var i = 0; i < tempRandomList.length; i++) {
                var randVkiid = KartPrio.kartPrioVkiidsArray[tempRandomList[i]];
                KartPrio.randomHitList.push(randVkiid);

                var item = KartPrio.kartPrioData[randVkiid];

                if (north == null || item.point.north < north) {
                    north = item.point.north;
                    northVkiid = randVkiid;
                }
            }

            KartPrio.kartPrioData[northVkiid].flipBubble = true;
        }

    },

    /**
    * Reset kart prio state.
    */
    reset: function () {
        KartPrio.kartPrioVkiidsArray = [];
        KartPrio.kartPrioData = {};
        KartPrio.noOfKartPrioHits = 0;
    },

    /** 
    * Returns true if (encrypted) vkiid is a chosen kart prio product for current search.
    */
    isPrio: function (vkiid) {
        return !!KartPrio.kartPrioData[vkiid];
    },

    isClosed: function (vkiid) {
        return (KartPrio.kartPrioData[vkiid] && KartPrio.kartPrioData[vkiid].closed);
    },

    setClosed: function (vkiid) {
        if (KartPrio.kartPrioData[vkiid]) {
            KartPrio.kartPrioData[vkiid].closed = true;
        }
    },

    getLink: function (vkiid) {
        if (KartPrio.kartPrioData[vkiid]) {
            return KartPrio.kartPrioData[vkiid].link;
        }
        return false;
    },

    /**
    * Returns string of KartPrio vkiids, if bounds is not null only
    * those with location within bounds.
    *
    * @param {HBoundsRT90} bounds
    */
    getVkiids: function (bounds) {
        if (!KartPrio.kartPrioVkiidsArray) {
            return "";
        }

        if (bounds) {
            KartPrio.bounds = bounds;
            var boundsResult = [];
            for (var i = 0; i < KartPrio.kartPrioVkiidsArray.length; i++) {
                var vkiid = KartPrio.kartPrioVkiidsArray[i];
                if (KartPrio.kartPrioData[vkiid] && KartPrio.kartPrioData[vkiid].point != null && bounds.containsRT90(KartPrio.kartPrioData[vkiid].point)) {
                    boundsResult.push(vkiid);
                }
            }
            return boundsResult.join(";");
        }

        return KartPrio.kartPrioVkiidsArray.join(";");
    },

    /**
    * Get anchor type based on position.
    *
    * @param {HPointRT90} rt90point
    * @param {HPointRT90} pointvkiid Used to differ between multiple points in same location
    * @return {Number|null} Anchor type or null if default should be used
    */
    /*
    getAnchorType: function(rt90point, pointvkiid) {
    if (KartPrio.kartPrioVkiidsArray.length == 0) {
    return null;
    }

    var len = KartPrio.kartPrioVkiidsArray.length;

    for (var i = 0; i < len; i++) {
    var vkiid = KartPrio.kartPrioVkiidsArray[i];
    if (KartPrio.kartPrioData[vkiid]) {
    if (KartPrio.kartPrioData[vkiid].point.north < rt90point.north || (KartPrio.kartPrioData[vkiid].point.north == rt90point.north && vkiid < pointvkiid)) {
    return null; // default anchor
    }
    }
    }

    return HInfoBox.ANCHOR_TOPLEFT;
    },*/

    /**
    * Bind custom behavior info box to KartPrio markers.
    *
    * @param {HMarker} marker
    * @param {String} content
    * @param {String} imgUrl URL to logo
    */
    bindInfoBox: function (marker, content, vkiid, infoBoxMode) {
        // add image
        var imgUrl = KartPrio.getLink(vkiid);
        if (imgUrl) {
            content = '<table cellspacing="0" style="margin-left:-1px; margin-bottom:-1px;"><tr><td class="KartPrioContent">' + content + '</td><td valign="top"><img class="KartPrioImg" src="' + 'http://bf.static.hitta.se/static/v1/products/images/' + imgUrl + '"/></td></tr></table>';
        }

        marker.bindInfoBoxHtml(content);
        if (HMapHelpers.isIE()) {
            HMapHelpers.applyStyle([marker.infoBox.getContentContainer()], { width: "290px" });
        }

        // make sure KartPrio info boxes do not overlap others
        marker.infoBox.zIndex -= 100;

        if (!KartPrio.isClosed(vkiid)) {

            marker.closeInfoBoxKartPrio = function () {
                if (marker.isInfoBoxOpen()) {
                    marker.hmap.removeOverlay(marker.infoBox);
                }

                // restore close functionality
                marker.closeInfoBox = function () { if (marker.isInfoBoxOpen()) marker.hmap.removeOverlay(marker.infoBox); };
                marker.setMode(HMarker.MODE_INFOBOX_HOVER);

                KartPrio.setClosed(vkiid);
            };
            hittaMap.appendCloseLinkToInfoBox(marker, marker.closeInfoBoxKartPrio);

            // force infobox not to change anchor type (set southern point to top left anchor)
            /*var anchorType = KartPrio.getAnchorType(marker.getRT90Point(), vkiid);
            if (anchorType !== null) {                
            marker.infoBox.setAnchorType(anchorType);
            }*/

            if (KartPrio.kartPrioData[vkiid].flipBubble)
                marker.infoBox.setAnchorType(HInfoBox.ANCHOR_TOPLEFT);

            marker.infoBox.mapMove = function () { };

            if (infoBoxMode == InfoBoxMode.AlwaysDisplay)
                marker.openInfoBoxBound();
            else
                marker.setMode(HMarker.MODE_INFOBOX_HOVER);
        }
    }
}

var currentPointRef;
var MapSearch =
{
    mapHeight: 0,
    mapWidth: 0,
    level: 0,
    noOfhitsPerPage: 20,
    resultFieldWidth: 0,
    searchFieldsUsed: null,
    offset: 0,
    hitlistUrl: '',
    pageOneBook: MapSearchBook.all,
    keepIdPoint: false,
    previousWho: '',
    previousWhere: '',
    lockHits: false,
    singleHitCallback: null,
    markers: [],
    currentBranches: '',
    currentLogoExpoVkiid: '',
    currentLogoExpoProdId: '',
    isNewSearch: false,
    nrOfHits: 0,

    IMAGE_BASE_URL: "http://static.hitta.se/streetview/",
    STREETVIEW_DEFAULT_ZOOM_LEVEL: 6,

    init: function (mapWidth, mapHeight) {
        MapSearch.mapHeight = mapHeight;
        MapSearch.mapWidth = mapWidth;

        OnHittaMapLoaded.add(MapSearch.hittaMapLoaded);
        //MapJack.loadedListener = MapSearch.mapJackLoaded;
        HEvent.addListener(MapJack, "isLoaded", MapSearch.mapJackLoaded);
    },

    hittaMapLoaded: function () {

        // OBS! Detta kodblock kommenterades ut för att fixa bugg med pivottracker-id 3437950
        // (en sökning gjordes alltid när kartan laddats, även när man bara skulle visa större karta från en detaljträff.
        // för närvarande kan inte den bortkommenterade kodens nytta fastställas. Låt dock stå!
        /*
        callback = function() {
        setTimeout(function() {
        HEvent.addListener(hittaMap.map, HMap.EVENT_MAP_MOVE_END, MapSearch.hittaMapMoveEnd);
        }, 10)       
        }
        doMapSearch(callback);
        */

        HEvent.addListener(hittaMap.map, HMap.EVENT_MAP_MOVE_END, MapSearch.hittaMapMoveEnd);

    },

    hittaMapMoveEnd: function () {
        //alert("hitta map move end");
        MapSearch.dynamicSearch('pan');
    },

    mapJackLoaded: function () {
        MapSearch.hideStreetImage();
        for (var i = 0; i < MapSearch.markers.length; i++) {
            MapSearch.markers[i].closeInfoBox();
            MapSearch.markers[i].setMode(HMarker.MODE_INFOBOX_HOVER);
        }
    },

    getHitById: function (id) {
        if (MapSearch.markers[id]) {
            return MapSearch.markers[id];
        }
        return null;
    },

    allowDynamicSearch: true,

    // The main search function. This is called on "fresh" searches (i.e. when user clicks "visa på karta"), and also when paging through hit results.
    search: function (who, where, book, pageNumber, offset, searchArea, level, hitlistUrl) {

        this.isNewSearch = true;

        if (hittaMap == null || hittaMap.map == null) {
            // fix for IE null object
            setTimeout(arguments.callee, 100);
            return;
        }

        // reset KartPrio state when new search is performed
        if (arguments.length == 2) {
            KartPrio.reset();
        }

        if (typeof who == 'undefined') { who = MapSearch.getWhoValue(); }
        if (typeof where == 'undefined') { where = MapSearch.getWhereValue(); }
        if (typeof pageNumber == 'undefined') { pageNumber = 1; }
        if (typeof book == 'undefined') { book = MapSearchBook.all; }

        // remove region search lock on single place hit
        MapSearch.lockHits = false;

        // ensure that when we make a search with a predetermined book, we always get hits from that book,
        // even when paging back to page one.
        if (pageNumber == 1 && book != MapSearchBook.all)
            MapSearch.pageOneBook = book;
        else if (pageNumber == 1)
            MapSearch.pageOneBook = MapSearchBook.all;

        if (hasExternalPoints) {
            hasExternalPoints = false;
            TDapplet.resize();
        }

        MapSearch.hideStreetImage();

        if (who != '' || where != '') {
            if (typeof (hitlistUrl) != 'undefined') { MapSearch.hitlistUrl = hitlistUrl; }

            // Lines below does not seem neccessary as the fields are set in searchblock.ascx.cs
            MapSearch.setWhoValue(who);
            MapSearch.setWhereValue(where);

            var boundary;
            var allowAutoFocus = true;
            MapSearch.searchFieldsUsed = SearchFieldUsage.getUsage(who, where);

            // Is this a region search?
            if (searchArea != MapSearchArea.global && (searchArea == MapSearchArea.region || (CommonMap.getZoomLevel() > 1 && MapSearch.searchFieldsUsed != SearchFieldUsage.both && MapSearch.searchFieldsUsed != SearchFieldUsage.where))) {
                // Get the current boundary. Sending this to queryAjax signals a region search.
                boundary = new MapSearchBoundary();
                allowAutoFocus = false;
            }

            //if (MapJack.isLoaded) allowAutoFocus = true;

            //MapSearch.queryAjax(who, where, boundary, allowAutoFocus, book, pageNumber, offset, level);

            //MapSearchQueue.push([who, where, boundary, allowAutoFocus, book, pageNumber, offset, level]);
            //MapSearchQueue.push([[MapSearch.queryAjax], [who, where, boundary, allowAutoFocus, book, pageNumber, offset, level]]);
            var item = new MapSearchQueueItem(MapSearch.queryAjax, [who, where, boundary, allowAutoFocus, book, pageNumber, offset, level]);
            MapSearchQueue.push(item);
        }
    },

    searchBranches: function (branchString, pageNumber) {
        var item = new MapSearchQueueItem(MapSearch.doSearchBranches, [branchString, pageNumber]);
        MapSearchQueue.push(item);
    },

    doSearchBranches: function (branchString, pageNumber) {
        var boundary = new MapSearchBoundary();
        boundary.crop();
        MapSearch.currentBranches = branchString;
        Hitta.PublicWeb.Web.AjaxMethods.SearchBranchesInMap(branchString, boundary.x1, boundary.y1, boundary.x2, boundary.y2, pageNumber, MapSearch.noOfhitsPerPage, MapSearch.queryAjax_callbackNoFocus);
    },

    getLogoExpo: function (vkiid, prodId, pageNumber, hitlistUrl) {
        var item = new MapSearchQueueItem(MapSearch.doGetLogoExpo, [vkiid, prodId, pageNumber, hitlistUrl]);
        MapSearchQueue.push(item);
    },

    doGetLogoExpo: function (vkiid, prodId, pageNumber, hitlistUrl) {
        if (typeof (hitlistUrl) != 'undefined') { MapSearch.hitlistUrl = hitlistUrl; }
        MapSearch.currentLogoExpoVkiid = vkiid;
        MapSearch.currentLogoExpoProdId = prodId;
        MapMode.doBoundarySearch = false;
        Hitta.PublicWeb.Web.AjaxMethods.GetLogoExpo(vkiid, prodId, pageNumber, MapSearch.noOfhitsPerPage, MapSearch.mapWidth - MapSearch.getHitlistWidth(true), MapSearch.mapHeight - _MapToolbarsTop.getHeight(), MapSearch.queryAjax_callbackWithFocus);
    },

    // This function is used whenever we do a dyanamic search (i.e. when the map is moved).
    dynamicSearch: function (reason, who, where) {
        this.isNewSearch = false;

        if (largeMap && MapSearch.allowDynamicSearch) {                                   // dynamic searching disabled due to a single place hit from initial search?
            if (!MapMode.doBoundarySearch || MapSearch.lockHits) return;
            if (typeof (reason) == 'undefined') { reason = 'unknown'; }
            if (typeof (who) == 'undefined') { who = MapSearch.getWhoValue(); }
            if (typeof (where) == 'undefined') { where = MapSearch.getWhereValue(); }
            MapSearch.searchFieldsUsed = SearchFieldUsage.getUsage(who, where);

            var branchIDs = document.getElementById('BranchIDs').value;

            // If a dynamic search is made with both fields, then only the 'who' field will be used.
            if (who != '' && where != '') {
                __whereBox.value = '';
                where = '';
            }

            //Debug.write('dynamic search, reason=' + reason + ' who=' + who + ' where=' + where);                

            if (who != '' || where != '') {
                var boundary = new MapSearchBoundary();

                //MapSearchQueue.push([who, where, boundary, false]);
                var item = new MapSearchQueueItem(MapSearch.queryAjax, [who, where, boundary, false]);
                MapSearchQueue.push(item);

                //MapSearch.queryAjax(who, where, boundary, false);
            }
            else if (branchIDs != '') {
                var item = new MapSearchQueueItem(MapSearch.doSearchBranches, [branchIDs, 1]);
                MapSearchQueue.push(item);
            }
        }
    },

    // Sends the query via AJAX to the server.
    // Note 1: passing a valid boundary to this function will cause a region search to be made.
    // Note 2: the value of allowAutoFocus will determine what callback function is called on completion of the request.
    queryAjax: function (who, where, boundary, allowAutoFocus, book, pageNumber, offset, level) {
        var isRegionSearch = (typeof (boundary) != 'undefined');
        if (typeof (boundary) == 'undefined') { boundary = new MapSearchBoundary(0, 0, 0, 0); }
        if (typeof (book) == 'undefined') { book = MapSearchBook.all; }
        if (typeof (pageNumber) == 'undefined') { pageNumber = 1; }
        if (typeof (offset) == 'undefined') { offset = 0; }

        if (isRegionSearch) boundary.crop();

        var searchPink = (book == MapSearchBook.all || book == MapSearchBook.pink);
        var searchWhite = (book == MapSearchBook.all || book == MapSearchBook.white);
        var callback = allowAutoFocus ? MapSearch.queryAjax_callbackWithFocus : MapSearch.queryAjax_callbackNoFocus;

        // get KartPrio vkiid string
        var kartPrioVkiids = KartPrio.getVkiids(isRegionSearch ? hittaMap.map.getBounds() : null);
        //var kartPrioVkiids = null;

        if (MapMode.getMapMode() != 'app') {
            Map.showProgress();

            // Before doing the search, update the MapSearch width and height properties (if map has been resized).
            MapSearch.mapHeight = hittaMap.map.getSize().height;
            MapSearch.mapWidth = hittaMap.map.getSize().width;
            var toolbarHeight = 0;
            if (MapMode.getMapMode() != 'mj') {
                toolbarHeight = _MapToolbarsTop.getHeight();
            }
            Hitta.PublicWeb.Web.AjaxMethods.SearchInMap(who, where, isRegionSearch, boundary.westing, boundary.southing, boundary.easting, boundary.northing, pageNumber, MapSearch.noOfhitsPerPage, offset, level, searchWhite, searchPink, MapSearch.mapWidth - MapSearch.getHitlistWidth(true), MapSearch.mapHeight - toolbarHeight, kartPrioVkiids, callback);
        } else {
            Hitta.PublicWeb.Web.AjaxMethods.SearchInMap_poly(who, where, isRegionSearch, boundary.x1, boundary.y1, boundary.x2, boundary.y2, boundary.x3, boundary.y3, boundary.x4, boundary.y4, pageNumber, MapSearch.noOfhitsPerPage, offset, level, searchWhite, searchPink, MapSearch.mapWidth, MapSearch.mapHeight, kartPrioVkiids, callback);
        }
    },

    // Gets called when the ajax search method has finished, and we want to make the map pan and zoom to the points plotted on the map.
    queryAjax_callbackWithFocus: function (response) {
        MapSearch.queryAjax_callback(response, true);
    },


    // Gets called when the ajax search method has finished, and we DO NOT want to make the map pan and zoom to the points plotted on the map.
    queryAjax_callbackNoFocus: function (response) {
        MapSearch.queryAjax_callback(response, false);
    },


    // Main function for handling callback from the ajax search. allowAutoFocus states if the map should zoom and/or pan to show the hits.
    queryAjax_callback: function (response, allowAutoFocus) {
        hittaMap.map.clearOverlaysByCategory('hit');
        hittaMap.map.clearOverlaysByCategory('singleHit');

        if (!response.error) {
            KartPrio.init(response);
            var header = new Header(response);

            MapSearch.headerCorrection(header);

            var noOfHits = header.noOfWhiteDisplayHits + header.noOfPinkDisplayHits + header.noOfPlaceDisplayHits;

            MapSearch.drawHits(response);
            if (!(MapMode.getMapMode() == 'mj' && noOfHits == 1)) {
                MapSearch.showHitlist();
            }
        }

        // 090424: Additional check for header.centerX added due to bug when 'visa på kartan' for hit without coordinate
        if (allowAutoFocus && noOfHits > 0 && header && header.centerX) {

            // Ensure that the HMap.EVENT_MAP_MOVE_END event does not cause an additional search when autofocusing.
            MapSearch.allowDynamicSearch = false;

            var dest = new HPointRT90(header.centerY, header.centerX);

            if (header.zoomLevel == null) {
                hittaMap.map.panTo(dest);
                //hittaMap.map.setCenter(dest);
            } else {
                hittaMap.map.setZoom(10 - header.zoomLevel, dest);
                //hittaMap.map.setCenter(dest, 10 - header.zoomLevel);
            }

            // After the autofocus has finished, it is again OK to do dynamic search upon map move.
            MapSearch.allowDynamicSearch = true;

            if (MapMode.getMapMode() == 'app') {
                if (noOfHits == 1) {
                    TDapplet.setPositionLockedCamera(header.centerX, header.centerY);
                } else {
                    var resolution = Map.getResolutionFromZoomLevel(header.zoomLevel);
                    TDapplet.setPosition(header.centerX, header.centerY, resolution, true);
                }
            }

            if (noOfHits == 1 && typeof (MapSearch.singleHitCallback) == 'function') {
                MapSearch.singleHitCallback();
            }

            // if search is made with a level of 4 or higher, we want to be able to move the map without doing another search
            if (header.level >= 4)
                MapSearch.lockHits = true;

        }
        else if (noOfHits == 0) {
            //var imgSrc = "http://eas.hitta.se/eas?cu=8097;sw=" + escape(MapSearch.getWhoValue()) + ";sw2=" + escape(MapSearch.getWhereValue());
            //var imgSrc = "http://eas.hitta.se/eas?cu=8097;sw=" + escape(MapSearch.getWhoValue()) + "///" + escape(MapSearch.getWhereValue());
            //var voidImg = new Image().src = imgSrc;
        }

        if (MapMode.getMapMode() != 'app')
            Map.hideProgress();
    },

    // Correct header data 
    headerCorrection: function (header) {

        var numHits = header.noOfWhiteDisplayHits + header.noOfPinkDisplayHits + header.noOfPlaceDisplayHits;

        if (numHits === 1 && MapJack.isLoaded) { header.zoomLevel = 4; };
    },


    // Clears all hits on the hit list and all the points on the map(s).
    clearAllHits: function () {
        document.getElementById('resultAjax').innerHTML = '';
        MapSearch.clearPoints();
        MapSearch.markers = [];
        TDapplet.removeAllLabels();
    },

    clearPoints: function () {
        hittaMap.map.clearOverlaysByCategory('hit');
        hittaMap.map.clearOverlaysByCategory('singleHit');
    },

    // Draws all current hits in the response object to the hitlist and plots the corresponding points on the map.
    drawHits: function (response) {
        if (response.error !== null) return; // 090424: check that no error has happened

        var header = new Header(response);
        var startIndex = 0;
        var noOfHits = header.noOfWhiteDisplayHits + header.noOfPinkDisplayHits + header.noOfPlaceDisplayHits;
        this.nrOfHits = noOfHits;
        var showTooltips = noOfHits == 1;
        var hasHits = noOfHits > 0;
        var moreHitsExistsGlobally = (header.noOfWhiteGlobalHits + header.noOfPinkGlobalHits + header.noOfPlaceGlobalHits > 0);

        // Clear before draw, if there is not an ID point to keep.
        if (!MapSearch.keepIdPoint)
            MapSearch.clearAllHits();
        else
            MapSearch.keepIdPoint = false;

        if (hasHits) {
            var zoomChanged = hittaMap.map.getZoom() != header.zoomLevel;
            TDapplet.setLabelMarkerAppearance('id', 'drawhits - hashits');

            if (MapSearch.hitlistUrl != '') {
                MapSearch.writeToHitlist("<div style='padding-left:10px;'><a href='" + MapSearch.hitlistUrl + "' style='font-size:11px;color:blue'>Tillbaka till träfflistan</a></div><br><br>");
            }

            try {
                if (header.noOfPlaceDisplayHits == 1 && (header.noOfWhiteDisplayHits == null || header.noOfWhiteDisplayHits == 0) && (header.noOfPinkDisplayHits == null || header.noOfPinkDisplayHits == 0)) {
                    var imgHit = new PlaceHit(response.value.Tables[3].Rows[0]);
                    if (!MapJack.isLoaded) imgHit.showStreetImage();
                }
                else if ((header.noOfPlaceDisplayHits == null || header.noOfPlaceDisplayHits == 0) && header.noOfWhiteDisplayHits == 1 && (header.noOfPinkDisplayHits == null || header.noOfPinkDisplayHits == 0)) {
                    var imgHit = new WhiteHit(response.value.Tables[1].Rows[0]);
                    if (!MapJack.isLoaded) imgHit.showStreetImage();
                }
                else if ((header.noOfPlaceDisplayHits == null || header.noOfPlaceDisplayHits == 0) && (header.noOfWhiteDisplayHits == null || header.noOfWhiteDisplayHits == 0) && header.noOfPinkDisplayHits == 1) {
                    var imgHit = new WhiteHit(response.value.Tables[2].Rows[0]);
                    if (!MapJack.isLoaded) imgHit.showStreetImage();
                }
            }
            catch (ex) { }


            if (header.noOfPlaceDisplayHits > 0) {
                var isChoice = (MapSearch.searchFieldsUsed == SearchFieldUsage.both);
                MapSearch.drawPlaceHits(response.value.Tables[3], header, isChoice, response);

                // check to see if the search was not a region search and we have exactly one place hit, in which case we lock out all further region searches.
                if (!header.wasRegionSearch && header.noOfPlaceDisplayHits == 1) {
                    MapSearch.lockHits = true;
                }

                return;
            }

            if (header.noOfWhiteDisplayHits > 0)
                startIndex = MapSearch.drawWhiteHits(response.value.Tables[1], header, showTooltips);

            if (header.noOfPinkDisplayHits > 0) {
                MapSearch.drawPinkHits(response.value.Tables[2], startIndex, header, showTooltips);
            }
        }
        // Determine if there are global hits in either book and display a link if we do not have any hits to display (rather than saying 0 hits).            
        else if (moreHitsExistsGlobally)
            MapSearch.writeToHitlist("<div style='padding-left:5px;padding-top:10px;'><a href=\"javascript:MapSearch.search('" + MapSearch.getWhoValue() + "', '" + MapSearch.getWhereValue() + "', MapSearchBook.all, 1, 0, MapSearchArea.global);\" style='font-size:11px;color:blue'>Visa " + (parseInt(header.noOfWhiteGlobalHits) + parseInt(header.noOfPinkGlobalHits) >= 2001 ? '&gt; 2000' : parseInt(header.noOfWhiteGlobalHits) + parseInt(header.noOfPinkGlobalHits)) + " träffar utanför kartan</a></div>");
        else
            MapSearch.writeToHitlist("<div style='padding-left:5px;padding-top:10px;'>Din sökning gav tyvärr inga träffar.</div>");

    },

    // Writes the white hits to the hitlist and plots the corresponding points on the map.
    drawWhiteHits: function (whiteTable, header, showTooltips) {
        if (whiteTable.Rows.length == 0) return;

        var noOfHits = header.noOfWhiteTotalRegionHits;
        var listHeader = "<div style='padding-left:5px;'><b>Personer (" + noOfHits + " st)</b></div>";
        MapSearch.writeToHitlist(listHeader);
        var moreHitsExistsGlobally = (header.noOfWhiteGlobalHits > header.noOfWhiteTotalRegionHits || (header.noOfWhiteGlobalHits == 2001 && header.noOfWhiteTotalRegionHits == 2001));

        // The link "visa X träffar utanför kartan" is displayed if there are global hits to display, 
        // and the hits displayed were not the result of a global search itself, in which case it would be pointless.
        if (moreHitsExistsGlobally && header.wasRegionSearch) {
            MapSearch.writeToHitlist("<div style='padding-left:5px;padding-top:10px;'><a href=\"javascript:MapSearch.search('" + MapSearch.getWhoValue() + "', '', MapSearchBook.white, 1, 0, MapSearchArea.global);\" style='font-size:11px;color:blue'>Visa " + (header.noOfWhiteGlobalHits == 2001 ? '&gt; 2000' : header.noOfWhiteGlobalHits - header.noOfWhiteDisplayHits) + " personer utanför kartan</a></div>");
        }

        MapSearch.writeToHitlist("<div id='hitContainerWhite' class='hitContainer'>");
        var hit;
        for (var i = 0; i < whiteTable.Rows.length; i++) {
            var hit = new WhiteHit(whiteTable.Rows[i]);

            var detailsUrl = "ViewDetailsWhite.aspx?Vkiid=" + hit.vkiid;
            var infoBoxMode = (header.totalHits == 1 ? InfoBoxMode.AlwaysDisplay : InfoBoxMode.DisplayOnMouseOver);
            hit.toolTipContentHtml += "<div name='whiteDetailsLink' id='whiteDetailsLink" + i + "' align=\"left\"><a class=\"tinyTextGrey\" style=\"margin-left:3px; margin-bottom:2px; display:block;\" href=\"" + detailsUrl + "\" target=\"blank\" onclick=\"window.open('" + detailsUrl + "'); MapSearch.preventMapClick(event);\">Detaljerad info</a></div>";

            var marker = null;

            if (header.totalHits == 1) {
                hit.toolTipContentHtml += "<div style=\"float:right;\"><a class=\"tinyTextGrey\" href=\"javascript:void(0)\" onclick=\"MapSearch.closeLoneToolTip(); MapSearch.preventMapClick(event);\">Stäng</a></div>";
                marker = MapSearch.addPoint(hit, null, false, infoBoxMode);
            }
            else {
                marker = MapSearch.addPoint(hit, i, false, infoBoxMode);
            }

            MapSearch.writeToHitlist(MapSearch.formatWhiteHit(hit, i));

            MapSearch.markers[i] = marker;
            var addressId = MapSearch.getAddressId(hit.streetName, hit.streetNumber, hit.streetSuffix, hit.locality);
            if (addressId != "" && (MapMode.getMapMode() != "app")) {
                var url = MapSearch.IMAGE_BASE_URL + addressId;
                HMapHelpers.getJSONP(url, MapSearch.callback, marker);
            }
        }
        if (noOfHits == 1 && MapModeControl) {
            MapModeControl.setHit(hit);
        } else {
            MapModeControl.setHit(null);
        }
        MapSearch.writeToHitlist("</div>");

        // Paging
        var pagingHtml = MapSearch.getWhitePaging(whiteTable, header);
        MapSearch.writeToHitlist(pagingHtml + '<br>');

        return whiteTable.Rows.length;
    },

    callback: function (data) {
        if (data.status == 1) {

            //$('.tinyTextGrey').remove();

            var streetviewLink = document.createElement("a");

            var linkText = document.createTextNode("Se gatubild");
            streetviewLink.href = "#";
            streetviewLink.className = "tinyTextGrey";
            streetviewLink.appendChild(linkText);
            streetviewLink.onclick = function (event) { HEvent.stopEvent(event); MapSearch.gotoStreetview(data.rt90north, data.rt90east, data.angle); };
            var placeHitWrapper = $(".place_hit_wrapper", $(this.infoBox.contentElement));
            if (placeHitWrapper.length > 0) {
                HMapHelpers.applyStyle([streetviewLink], { display: "block" });
                placeHitWrapper.get(0).appendChild(streetviewLink);
            } else {
                HMapHelpers.applyStyle([streetviewLink], { display: "block", marginLeft: "3px" });
                this.infoBox.contentElement.appendChild(streetviewLink);
            }
        }
    },

    gotoStreetview: function (north, east, angle) {
        var point = new HPointRT90(north, east);
        var statusUpdateListener = HEvent.addListener(HViewer, HViewer.EVENT_STATUS_UPDATE, function () { HViewer.turnTo(angle); HEvent.removeListener(statusUpdateListener); });
        MapModeControl.openMapJack(point);
    },

    getAddressId: function (streetName, streetNumber, suffix, city) {
        var addressString = streetName + streetNumber + suffix + city;
        addressString = addressString.replace(/Å/gi, "OE");
        addressString = addressString.replace(/Ä/gi, "AE");
        addressString = addressString.replace(/Ö/gi, "OO");
        addressString = addressString.replace(/Ü/gi, "UU");
        addressString = addressString.replace(/É/gi, "EE");
        addressString = addressString.replace(/[^A-Z0-9]/gi, "");
        addressString = addressString.toLowerCase();
        return addressString;
    },

    // Writes the pink hits to the hitlist and plots the corresponding points on the map.
    drawPinkHits: function (pinkTable, startIndex, header, showTooltips) {

        var me = this;
        if (pinkTable.Rows.length == 0) return;

        var noOfHits = header.noOfPinkTotalRegionHits;
        var listHeader = "<div style='padding-left:5px;'><b>Företag (" + noOfHits + " st)</b></div>";
        MapSearch.writeToHitlist(listHeader);
        var moreHitsExistsGlobally = (header.noOfPinkGlobalHits > header.noOfPinkTotalRegionHits || (header.noOfPinkGlobalHits == 1600 && header.noOfPinkTotalRegionHits == 1600));
        var currentBranchId = 0;

        // The link "visa X träffar utanför kartan" is displayed if there are global hits to display, 
        // and the hits displayed were not the result of a global search itself, in which case it would be pointless.
        if (moreHitsExistsGlobally && header.wasRegionSearch) {
            MapSearch.writeToHitlist("<div style='padding-left:5px;padding-top:10px;'><a href=\"javascript:MapSearch.search('" + MapSearch.getWhoValue() + "', '', MapSearchBook.pink, 1, 0, MapSearchArea.global);\" style='font-size:11px;color:blue'>Visa " + (header.noOfPinkGlobalHits >= 1600 ? '&gt; 2000' : header.noOfPinkGlobalHits - header.noOfPinkDisplayHits) + " företag utanför kartan</a></div>");
        }

        MapSearch.writeToHitlist("<div id='hitContainerPink' class='hitContainer'>");
        /*
        if (this.isNewSearch) {
        var NUMBER_OF_MAP_HITS = 2;
        var tempRandomList = KartPrio.kartPrioVkiidsArray.length >= NUMBER_OF_MAP_HITS ? generateRandomNumbers(0, KartPrio.kartPrioVkiidsArray.length - 1, NUMBER_OF_MAP_HITS) : [0];

        // Create an Array with 2 random available Vkiid's
        me.randomHitList = [];
        for (var i = 0; i < tempRandomList.length; i++) {
        me.randomHitList.push(KartPrio.kartPrioVkiidsArray[tempRandomList[i]]);
        }
        }
        */
        var hit;

        for (var i = 0; i < pinkTable.Rows.length; i++) {
            hit = new PinkHit(pinkTable.Rows[i]);
            hit.isKartPrio = KartPrio.isPrio(hit.vkiid);

            var hitIndex = startIndex + i;

            var detailsUrl = "ViewDetailsPink.aspx?Vkiid=" + hit.vkiid;

            hit.toolTipContentHtml += "<div name='pinkDetailsLink' id='pinkDetailsLink" + i + "' align=\"left\"><a class=\"tinyTextGrey\" style=\"display:block; margin-bottom:2px;\" href=\"" + detailsUrl + "\" target=\"blank\" onclick=\"window.open('" + detailsUrl + "'); MapSearch.preventMapClick(event);\">Detaljerad info</a></div>";

            if (MapSearch.currentBranches != '') {
                if (hit.heading.id != currentBranchId) {
                    MapSearch.writeToHitlist("<div style='font-size: 9px; font-weight:bold;padding-left: 5px; padding-bottom: 5px;" + (i == 0 ? "" : "padding-top:10px;") + "'>" + hit.heading.name.toUpperCase() + '</div>');
                }
                currentBranchId = hit.heading.id;
            }

            // Display the links to the left
            MapSearch.writeToHitlist(MapSearch.formatPinkHit(hit, hitIndex));

            //var infoBoxMode = (noOfHits == 1 || hit.isKartPrio ? InfoBoxMode.AlwaysDisplay : InfoBoxMode.DisplayOnMouseOver);

            var infoBoxMode = InfoBoxMode.AlwaysHidden;

            var marker = null;

            if (Array.exists((KartPrio.randomHitList || []), hit.vkiid)) {
                marker = MapSearch.addPoint(hit, hitIndex, false, InfoBoxMode.AlwaysDisplay);
                marker.closeInfoBox = function () { };
            }
            else {
                if (header.totalHits == 1) {
                    hit.toolTipContentHtml += "<div style=\"float:right;\"><a class=\"tinyTextGrey\" href=\"javascript:void(0)\" onclick=\"MapSearch.closeLoneToolTip(); MapSearch.preventMapClick(event);\">Stäng</a></div>";
                    marker = MapSearch.addPoint(hit, null, false, InfoBoxMode.AlwaysDisplay);
                } else {
                    marker = MapSearch.addPoint(hit, hitIndex, false, InfoBoxMode.DisplayOnMouseOver);
                }
            }

            MapSearch.markers[hitIndex] = marker;

            var addressId = MapSearch.getAddressId(hit.streetName, hit.streetNumber, hit.streetSuffix, hit.locality);

            if (addressId != "" && (MapMode.getMapMode() != "app")) {
                HMapHelpers.getJSONP(MapSearch.IMAGE_BASE_URL + addressId, MapSearch.callback, marker);
            }
        }



        if (noOfHits == 1 && MapModeControl) {
            MapModeControl.setHit(hit);
        } else {
            MapModeControl.setHit(null);
        }

        MapSearch.writeToHitlist("</div>");

        // Paging
        var pagingHtml = MapSearch.getPinkPaging(pinkTable, header);
        MapSearch.writeToHitlist(pagingHtml + '<br>');
    },

    // Writes the place hits to the hitlist and plots the corresponding points on the map. isChoice=true means the user will be presented with
    // a choice among the places, in order to make a new search based on the selected place.
    drawPlaceHits: function (placeTable, header, isChoice, placeHitData) {
        if (placeTable.Rows.length == 0) return;

        var noOfHits = header.noOfPlaceTotalRegionHits;

        var listHeader = "<div style='padding-left:5px;'><b>Platser (" + noOfHits + " st)</b></div>";
        var listChoiceHeader = "<div style='padding-left:5px;'><b>OBS! " + header.noOfPlaceDisplayHits + " platser<br>matchade din sökning. Var god välj en plats nedan.</b></div>";

        MapSearch.writeToHitlist(isChoice ? listChoiceHeader : listHeader);

        if (header.noOfPlaceGlobalHits > header.noOfPlaceTotalRegionHits) {
            MapSearch.writeToHitlist("<div style='padding-left:5px;padding-top:10px;'><a href=\"javascript:MapSearch.search('', '" + MapSearch.getWhereValue() + "');\" style='font-size:11px;color:blue'>Visa " + header.noOfPlaceGlobalHits + " platser utanför kartan</a></div>");
        }

        var moreHitsText = header.level == 1 ? "Visa fler träffar på " + MapSearch.getWhereValue() : "Visa träffar med liknande stavning";

        if (header.nextLevel <= 5)                                                                                          // who, where, book, pageNumber, offset, searchArea, level
            MapSearch.writeToHitlist("<div style='padding-left:5px;padding-top:10px;'><a href=\"javascript:MapSearch.search('', '" + MapSearch.getWhereValue() + "', MapSearchBook.none, 1, 0, MapSearchArea.global, " + header.nextLevel + ");\" style='font-size:11px;color:blue'>" + moreHitsText + "</a></div>");

        MapSearch.writeToHitlist("<div id='hitContainerPlace' class='hitContainer'>");

        var hit;
        var tooltipContentHtmlAddition = '';

        // Add a "close" button to the tooltip if it is open by default (i.e. if only one hit is displayed on the map)
        // otherwise, add a "zoom in" link.
        if (placeTable.Rows.length == 1) {
            tooltipContentHtmlAddition = "<div align=\"right\"><a class=\"tinyTextGrey\" href=\"javascript:void(0)\" onclick=\"MapSearch.closeLoneToolTip(); MapSearch.preventMapClick(event);\">Stäng</a></div>";
        }
        for (var i = 0; i < placeTable.Rows.length; i++) {
            hit = new PlaceHit(placeTable.Rows[i]);
            if (tooltipContentHtmlAddition != '')
                hit.toolTipContentHtml += tooltipContentHtmlAddition;
            else if (header.zoomLevel > 3) {
                var javaCall = "zoomToPlace(" + hit.yPosMid + "," + hit.xPosMid + ",'" + hit.name + "','" + hit.streetNumber + "','" + hit.zipCode + "','" + hit.placeType + "'," + hit.id + ",3);";
                hit.toolTipContentHtml += "<div name='zoomLink' id='zoomLink" + i + "' align=\"left\"><a class=\"tinyTextGrey\" href=\"javascript:void(0)\" onclick=\"" + javaCall + "; MapSearch.preventMapClick(event);\">Zooma in</a></div>";
            }

            MapSearch.writeToHitlist(MapSearch.formatPlaceHit(hit, i, isChoice, placeHitData));
            var infoBoxMode = (noOfHits == 1 && !MapJack.isLoaded ? InfoBoxMode.AlwaysDisplay : InfoBoxMode.DisplayOnMouseOver);

            var marker = null;
            if (header.totalHits == 1)
                marker = MapSearch.addPoint(hit, null, isChoice, infoBoxMode);
            else
                marker = MapSearch.addPoint(hit, i, isChoice, infoBoxMode);

            MapSearch.markers[i] = marker;
        }

        if (header.zoomLevel < 3) {
            var addressId = MapSearch.getAddressId(hit.name, hit.streetNumber, "", hit.locality);
            if (addressId != "" && (MapMode.getMapMode() != "app")) {
                var url = MapSearch.IMAGE_BASE_URL + addressId;
                HMapHelpers.getJSONP(url, MapSearch.callback, marker);
            }
        }

        if (noOfHits == 1 && MapModeControl) {
            MapModeControl.setHit(hit);
        } else {
            MapModeControl.setHit(null);
        }

        MapSearch.writeToHitlist("</div>");

        // Paging
        var pagingHtml = MapSearch.getPlacePaging(placeTable, header);
        MapSearch.writeToHitlist(pagingHtml + '<br>');
    },

    preventMapClick: function (event) {
        HEvent.stopEvent(event);
    },

    showStreetImageByAddress: function (address, addressNo, literal, zip, displayWalkLink) {
        try {
            var div = document.getElementById('largeMapStreetImage');
            if (div) {
                if (MapJack) {
                    div.style.top = (_MapToolbarsTop.getHeight() + document.getElementById(MapJack.MAPJACK_ELEMENT_ID).offsetHeight) + 'px';
                } else {
                    div.style.top = _MapToolbarsTop.getHeight() + 76 + 'px'; // + 76 för nedskjutning pga popup meny
                }

                var ds = AjaxMethods.GetStreet(address, addressNo, literal, zip).value;

                if (ds != null && typeof (ds) == "object" && ds.Tables != null && ds.Tables.length > 0 && ds.Tables[0].Rows[0].thumb != '') {
                    div.style.display = 'block';
                    var html = '<div id=\'imgdiv2\' name=\'imgdiv2\'><div><p>';

                    if (displayWalkLink)
                        html += '<a class="toplinks" href="javascript:void(0);" onclick="MapSearch.showAllStreetImages();">Fler bilder</a><span class="bullet">&#149;</span>';

                    html += '<a class=toplinks href="javascript:MapSearch.hideStreetImage();">Stäng</a></p><img src="' + ds.Tables[0].Rows[0].thumb + '" width=130 height=173 alt="" title="" border=0><p><img class=noIE src="Images/MapPoint_NoNumber.gif" width=10 height=10 border=0> ' + ds.Tables[0].Rows[0].street + ' ' + ds.Tables[0].Rows[0].streetno + ' ' + ds.Tables[0].Rows[0].litera + '</p></div></div>';

                    div.innerHTML = html;
                }
            }
        } catch (ex) { }
    },

    showStreetImage: function (x, y, displayWalkLink) {

        try {

            var div = document.getElementById('largeMapStreetImage');
            if (div) {
                div.style.top = _MapToolbarsTop.getHeight() + 76 + 'px'; // + 76 för nedskjutning pga popup meny
                var ds = AjaxMethods.GetStreetImageByCoords(y, x).value;
                if (ds != null && typeof (ds) == "object" && ds.Tables != null && ds.Tables.length > 0) {
                    div.style.display = 'block';
                    var html = '<div id=\'imgdiv2\' name=\'imgdiv2\'><div><p>';

                    if (displayWalkLink)
                        html += '<a class="toplinks" href="javascript:void(0);" onclick="MapSearch.showAllStreetImages();">Fler bilder</a><span class="bullet">&#149;</span>';

                    html += '<a class=toplinks href="javascript:MapSearch.hideStreetImage();">Stäng</a></p><img src="' + ds.Tables[0].Rows[0].thumb + '" width=130 height=173 alt="" title="" border=0><p><img class=noIE src="Images/MapPoint_NoNumber.gif" width=10 height=10 border=0> ' + ds.Tables[0].Rows[0].street + ' ' + ds.Tables[0].Rows[0].streetno + ' ' + ds.Tables[0].Rows[0].litera + '</p></div></div>';

                    div.innerHTML = html;
                }
            }
        } catch (ex) { }
    },

    showAllStreetImages: function () {
        try {
            var hit = MapModeControl.hit;

            if (hit != null && hit.vkiid != null && hit.type == 'PinkHit')
                document.location.href = appRootpath + 'viewdetailspink.aspx?vkiid=' + hit.vkiid + '&showstreet=true';
            else if (hit != null && hit.vkiid != null && hit.type == 'WhiteHit')
                document.location.href = appRootpath + 'viewdetailswhite.aspx?vkiid=' + hit.vkiid + '&showstreet=true';
            else if (hit != null && hit.id != null && hit.placeType == 'address')
                document.location.href = appRootpath + 'viewdetailsplace.aspx?streetnumberid=' + hit.id + '&showstreet=true';
            else if (MapModeControl.placeId != null)
                document.location.href = appRootpath + 'viewdetailsplace.aspx?streetnumberid=' + MapModeControl.placeId + '&showstreet=true';
        } catch (ex) { }
    },

    hideStreetImage: function () {
        var div = document.getElementById('largeMapStreetImage');
        if (div) div.style.display = 'none';
    },

    formatPinkHit: function (hit, hitIndex) {
        var url = "ViewDetailsPink.aspx?Vkiid=" + hit.vkiid;
        var title = hit.hitListText;
        var klass = "maphitlistnumber pink ";
        klass = hit.isKartPrio ? (klass + 'prio pink-prio') : klass;
        var prio = hit.isKartPrio ? ' prio pink-prio' : '';

        // Add locality if this is a logoexpo (företagsgruppering) view, since otherwise all rows look the same.
        if (MapSearch.currentLogoExpoVkiid.length > 0 && hit.locality.length > 0)
            title += ', ' + hit.normalizedLocality;

        var title = Trunc(title, 25);
        if (hit.xPos != -1)
            return "<div class='" + klass + "'>" + (hitIndex + 1) + ".</div><div class='maphitlistitem pink " + prio + "''><a class='resultAjaxLink' target='_blank' href='" + url + "' onmouseover='MapSearch.showMapToolTip(" + hitIndex + ");' onmouseout='MapSearch.hideMapToolTip(" + hitIndex + ");' >" + title + "</a></div>";
        else
            return "<div class='" + klass + "'>-.</div><div class='maphitlistitem pink " + prio + "'><a class='resultAjaxLink' target='_blank' href='" + url + "' onmouseover='cursor(event);' onmouseout='cursorOut()' >" + title + "</a></div>";
    },


    formatWhiteHit: function (hit, hitIndex) {
        var url = "ViewDetailsWhite.aspx?Vkiid=" + hit.vkiid;
        var klass = "maphitlistnumber white ";
        klass = hit.isKartPrio ? (klass + 'prio white-prio') : klass;
        var prio = hit.isKartPrio ? ' prio white-prio ' : '';

        if (hit.xPos != -1)
            return "<div class='" + klass + "'>" + (hitIndex + 1) + ".</div><div class='maphitlistitem white " + prio + "''><a target='_blank' href='" + url + "' onmouseover='MapSearch.showMapToolTip(" + hitIndex + ");' onmouseout='MapSearch.hideMapToolTip(" + hitIndex + ");' >" + Trunc(hit.hitListText, 25) + "</a></div>";
        else
            return "<div class='" + klass + "'>-.</div><div class='maphitlistitem white " + prio + "'><a class='resultAjaxLink' target='_blank' href='" + url + "' onmouseover='cursor(event);' onmouseout='cursorOut()'>" + Trunc(hit.formattedName, 25) + "</a></div>";
    },


    formatPlaceHit: function (hit, hitIndex, isChoice, placeHitData) {
        var link = isChoice ? hit.hitLinkChoice : hit.hitLink;
        var cssClass = "maphitlistnumber place ";
        cssClass = hit.isKartPrio ? (cssClass + 'prio place-prio') : cssClass;
        var prio = hit.isKartPrio ? ' prio format-prio' : '';

        if (hit.xPos != -1) {

            var showMapTooltpParams, hideMapToolTipParams, zoomToPlaceParams, idForEventBinding, hitCount, hitElement, hitLink;

            idForEventBinding = 'maphitlistitem-place' + hitIndex;

            hitCount = $('<div></div>').attr({ 'class': cssClass }).html(hitIndex + 1 + '.');
            hitElement = $('<div></div>').attr({ 'class': 'maphitlistitem place ' + prio, 'id': idForEventBinding });
            hitLink = $('<a></a>').attr({ 'href': '#' }).html(Trunc(hit.hitListText, 25));

            hitElement.append(hitLink);

            showMapTooltpParams = { hitIndex: hitIndex };
            hideMapToolTipParams = { hitIndex: hitIndex }
            zoomToPlaceParams = { xpos: hit.yPosMid, ypos: hit.xPosMid, name: hit.name, streetNumber: hit.streetNumber, zip: hit.zipCode, placeType: hit.placeType, id: hit.id, level: 3, placeHitData: placeHitData, hitIndex: hitIndex, hitLocality: hit.locality };

            $('#' + idForEventBinding).live('mouseover', showMapTooltpParams, MapSearch.showMapToolTip);
            $('#' + idForEventBinding).live('mouseout', showMapTooltpParams, MapSearch.hideMapToolTip);
            $('#' + idForEventBinding).live('click', zoomToPlaceParams, zoomToPlace);

            return [hitCount.get(0), hitElement.get(0)];
        } else {
            var url = "ViewDetailsPlace.aspx?var=" + MapSearch.getWhereValue() + (hit.type == 'place') ? "&PlaceId=" : "&StreetNumberId=" + hit.id;
            return "<div class='" + cssClass + "'>-.</div><div class='maphitlistitem place " + prio + "'><a class='resultAjaxLink' target='_blank' href='" + url + "' onmouseover='cursor(event);' onmouseout='cursorOut()'>" + Trunc(hit.hitListText, 25) + "</a></div>";
        }
    },

    addPoint: function (hit, hitIndex, isChoice, infoBoxMode) {
        var infoBoxMode = arguments[3] || InfoBoxMode.DisplayOnMouseOver;
        var imageSuffix = MapMode.getMapMode() == 'sat' ? 'b.png' : '.png';
        var category = 'hit';

        var icon = HIcon.H_DEFAULT_ICON;
        if (hitIndex == null) {
            category = 'singleHit';
        } else {
            icon.image = 'images/map/counter/' + hitIndex + imageSuffix;
        }

        var content = isChoice ? hit.toolTipContentHtmlChoice : hit.toolTipContentHtml;

        var point = null;

        if (hit.isKartPrio) {
            point = hittaMap.addPoint(new HPointRT90(hit.xPos, hit.yPos), icon, category, null, null);
            KartPrio.bindInfoBox(point, content, hit.vkiid, infoBoxMode);
        } else {
            point = hittaMap.addPoint(new HPointRT90(hit.xPos, hit.yPos), icon, category, content, infoBoxMode);
        }

        TDapplet.addPoint(hitIndex + 1, point, false, hit.toolTipContentApp);
        currentPointRef = point;

        return point;
    },

    closeLoneToolTip: function () {
        hittaMap.map.closeInfoBoxes();
    },

    // Gets HTML with links for paging among white hits.
    getWhitePaging: function (whiteTable, header) {
        var pagerLinks = "";
        var nextPageNo = parseInt(header.currentPage) + 1;
        var prevPageNo = parseInt(header.currentPage) - 1;
        var who = MapSearch.getWhoValue();
        var where = MapSearch.getWhereValue();

        // set the offset variable to the offset caused by the number of hits on the first page.
        if (header.currentPage == 1) {
            MapSearch.offset = header.noOfWhiteHitsShown;
        }

        var nextPageSize = (header.noOfWhiteTotalRegionHits - header.noOfWhiteHitsShown < header.subPageSearchLimit) ? header.noOfWhiteTotalRegionHits - header.noOfWhiteHitsShown : header.subPageSearchLimit;
        var searchArea = header.wasRegionSearch ? MapSearchArea.region : MapSearchArea.global;

        if (header.currentPage > 2) {                                                                                       // who,       where,          book,                pageNumber,          offset,                   searchArea,         level,            hitlistUrl)
            pagerLinks += "<div class='hitlistpager'><a href=\"javascript:MapSearch.search('" + who + "', '" + where + "', MapSearchBook.white, " + prevPageNo + ", " + MapSearch.offset + ", " + searchArea + ", " + header.level + ");\" style='color:blue' id='pagePrev'>Föregående " + header.subPageSearchLimit + " personer</a></div>";
        }
        else if (header.currentPage == 2) {
            pagerLinks += "<div class='hitlistpager'><a href=\"javascript:MapSearch.search('" + who + "', '" + where + "', MapSearch.pageOneBook, 1, 0, " + searchArea + ", " + header.level + ")\" style='color:blue' id='pagePrev'>Föregående personer</a></div>"
        }

        if (header.noOfWhiteTotalRegionHits > header.noOfWhiteHitsShown) {
            pagerLinks += "<div class='hitlistpager'><a href=\"javascript:MapSearch.search('" + who + "', '" + where + "', MapSearchBook.white, " + nextPageNo + ", " + MapSearch.offset + ", " + searchArea + ", " + header.level + ");\" style='color:blue' id='pageNext'>Nästa " + nextPageSize + " personer</a></div>";
        }

        return pagerLinks;
    },

    // Gets HTML with links for paging among pink hits.
    getPinkPaging: function (pinkTable, header) {
        var pagerLinks = "";
        var nextPageNo = parseInt(header.currentPage) + 1;
        var prevPageNo = parseInt(header.currentPage) - 1;
        var who = MapSearch.getWhoValue();
        var where = MapSearch.getWhereValue();

        // set the offset variable to the offset caused by the number of hits on the first page.
        if (header.currentPage == 1) {
            MapSearch.offset = header.noOfPinkHitsShown - KartPrio.noOfKartPrioHits;
        }

        var nextPageSize = (header.noOfPinkTotalRegionHits - header.noOfPinkHitsShown < header.subPageSearchLimit) ? header.noOfPinkTotalRegionHits - header.noOfPinkHitsShown : header.subPageSearchLimit;
        var searchArea = header.wasRegionSearch ? MapSearchArea.region : MapSearchArea.global;

        if (header.currentPage > 2) {
            if (MapSearch.currentBranches.length > 0)
                pagerLinks += "<div class='hitlistpager'><a href=\"javascript:MapSearch.searchBranches('" + MapSearch.currentBranches + "', " + prevPageNo + ");\" style='color:blue' id='pagePrev'>Föregående " + header.subPageSearchLimit + " företag</a></div>";
            else if (MapSearch.currentLogoExpoVkiid.length > 0)
                pagerLinks += "<div class='hitlistpager'><a href=\"javascript:MapSearch.getLogoExpo('" + MapSearch.currentLogoExpoVkiid + "', '" + MapSearch.currentLogoExpoProdId + "', " + prevPageNo + ")\" style='color:blue' id='pagePrev'>Föregående " + header.subPageSearchLimit + " företag</a></div>";
            else
                pagerLinks += "<div class='hitlistpager'><a href=\"javascript:MapSearch.search('" + who + "', '" + where + "', MapSearchBook.pink, " + prevPageNo + ", " + MapSearch.offset + ", " + searchArea + ", " + header.level + ");\" style='color:blue' id='pagePrev'>Föregående " + header.subPageSearchLimit + " företag</a></div>";
        }
        else if (header.currentPage == 2) {
            if (MapSearch.currentBranches.length > 0)
                pagerLinks += "<div class='hitlistpager'><a href=\"javascript:MapSearch.searchBranches('" + MapSearch.currentBranches + "', 1)\" style='color:blue' id='pagePrev'>Föregående företag</a></div>"
            else if (MapSearch.currentLogoExpoVkiid.length > 0)
                pagerLinks += "<div class='hitlistpager'><a href=\"javascript:MapSearch.getLogoExpo('" + MapSearch.currentLogoExpoVkiid + "', '" + MapSearch.currentLogoExpoProdId + "',1)\" style='color:blue' id='pagePrev'>Föregående företag</a></div>";
            else
                pagerLinks += "<div class='hitlistpager'><a href=\"javascript:MapSearch.search('" + who + "', '" + where + "', MapSearch.pageOneBook, 1, 0, " + searchArea + ", " + header.level + ")\" style='color:blue' id='pagePrev'>Föregående företag</a></div>"
        }

        if (header.noOfPinkTotalRegionHits > header.noOfPinkHitsShown) {
            if (MapSearch.currentBranches.length > 0)
                pagerLinks += "<div class='hitlistpager'><a href=\"javascript:MapSearch.searchBranches('" + MapSearch.currentBranches + "', " + nextPageNo + ");\" style='color:blue' id='pageNext'>Nästa " + nextPageSize + " företag</a></div>";
            else if (MapSearch.currentLogoExpoVkiid.length > 0)
                pagerLinks += "<div class='hitlistpager'><a href=\"javascript:MapSearch.getLogoExpo('" + MapSearch.currentLogoExpoVkiid + "', '" + MapSearch.currentLogoExpoProdId + "', " + nextPageNo + ")\" style='color:blue' id='pagePrev'>Nästa " + nextPageSize + " företag</a></div>";
            else
                pagerLinks += "<div class='hitlistpager'><a href=\"javascript:MapSearch.search('" + who + "', '" + where + "', MapSearchBook.pink, " + nextPageNo + ", " + MapSearch.offset + ", " + searchArea + ", " + header.level + ");\" style='color:blue' id='pageNext'>Nästa " + nextPageSize + " företag</a></div>";
        }

        MapSearch.currentLogoExpoVkiid = '';
        MapSearch.currentLogoExpoProdId = '';
        MapSearch.currentBranches = '';
        return pagerLinks;
    },

    // Gets HTML with links for paging among place hits.
    getPlacePaging: function (placeTable, header) {
        var pagerLinks = "";
        var nextPageNo = parseInt(header.currentPage) + 1;
        var prevPageNo = parseInt(header.currentPage) - 1;
        var where = MapSearch.getWhereValue();
        var nextPageSize = (header.noOfPlaceTotalRegionHits - header.noOfPlaceHitsShown < header.subPageSearchLimit) ? header.noOfPlaceTotalRegionHits - header.noOfPlaceHitsShown : header.subPageSearchLimit;
        var searchArea = header.wasRegionSearch ? MapSearchArea.region : MapSearchArea.global;

        if (header.currentPage > 2) {
            pagerLinks += "<div class='hitlistpager'><a href=\"javascript:MapSearch.search('', '" + where + "', MapSearchBook.none, " + prevPageNo + ", 0, " + searchArea + ", " + header.level + ");\" style='color:blue' id='pagePrev'>Föregående " + header.subPageSearchLimit + " platser</a></div>";
        }
        else if (header.currentPage == 2) {
            pagerLinks += "<div class='hitlistpager'><a href=\"javascript:MapSearch.search('', '" + where + "', MapSearchBook.none, 1, 0, " + searchArea + ", " + header.level + ")\" style='color:blue' id='pagePrev'>Föregående " + header.subPageSearchLimit + " platser</a></div>"
        }

        if (header.noOfPlaceTotalRegionHits > header.noOfPlaceHitsShown) {
            pagerLinks += "<div class='hitlistpager'><a href=\"javascript:MapSearch.search('', '" + where + "', MapSearchBook.none, " + nextPageNo + ", 0, " + searchArea + ", " + header.level + ");\" style='color:blue' id='pageNext'>Nästa " + nextPageSize + " platser</a></div>";
        }

        return pagerLinks;
    },

    writeToHitlist: function (html) {
        if (typeof html === 'string') {
            MapSearch.getHitlist().innerHTML += html;
        } else if (typeof html === 'object') {
            $(MapSearch.getHitlist()).append(html);
        }
    },

    showHitlist: function () {
        var resultAjaxContainer = document.getElementById('resultAjaxContainer');
        resultAjaxContainer.style.display = 'block';
        document.getElementById('resultAjax').style.display = 'block';
        document.getElementById('closeResultAjax').style.display = 'block';
        MapSearch.toggleTDInfo(false);
        MapSearch.positionHitlist();
    },

    positionHitlist: function () {
        var resultAjaxContainer = document.getElementById('resultAjaxContainer');
        var mapJackHeight = document.getElementById('MapJackGUI') ? document.getElementById('MapJackGUI').offsetHeight : 0;
        // Calculate correct height for hitlist when displaying hits
        if (_MapToolbarsTop) {
            var tdInfo = document.getElementById('tdInfo');
            var height;
            var offsetTop;

            if (null !== MapJack.splitter && "none" !== MapJack.splitter.style.display) {
                height = document.getElementById("mapContainer").offsetHeight;
                offsetTop = MapJack.splitter.style.top;
            } else {
                height = Math.max((document.getElementById("mapContainer").offsetHeight), document.getElementById('3DMapDiv').offsetHeight);
                offsetTop = _MapToolbarsTop.getHeight() + "px";
            }

            if (tdInfo != null && resultAjaxContainer != null) {
                tdInfo.style.height = height + 'px';
                resultAjaxContainer.style.height = height + 'px';
                tdInfo.style.top = offsetTop;
                resultAjaxContainer.style.top = offsetTop;
            }

        }
    },

    hideHitlist: function () {
        var resultAjaxContainer = document.getElementById('resultAjaxContainer');
        resultAjaxContainer.style.display = 'none';
        document.getElementById('resultAjax').style.display = 'none';
        document.getElementById('closeResultAjax').style.display = 'none';
    },

    toggleTDInfo: function (show) {
        if (MapMode.getMapMode() == 'app')
            document.getElementById('tdInfo').style.display = show ? 'block' : 'none';
    },

    getWhoValue: function () {

        if (document.getElementById('UCMC_UCSB_TextBoxWho').value != '')
            return document.getElementById('UCMC_UCSB_TextBoxWho').value;
        else
            return MapSearch.previousWho;
    },

    setWhoValue: function (who) {
        document.getElementById('UCMC_UCSB_TextBoxWho').value = who;
        MapSearch.previousWho = who;
    },

    getWhereValue: function () {
        var where = document.getElementById('UCMC_UCSB_TextBoxWhere')
        if (where.value != '')
            return where.value;
        else
            return MapSearch.previousWhere;
    },

    setWhereValue: function (where) {
        var val = document.getElementById('UCMC_UCSB_TextBoxWhere').value;
        document.getElementById('UCMC_UCSB_TextBoxWhere').value = decodeURIComponent(where);
        MapSearch.previousWhere = where;
    },

    // Fetches the hitlist div element
    getHitlist: function () {
        return document.getElementById('resultAjax');
    },

    // Gets the width of the hitlist pane. Returns 0 if the hitlist is hidden, unless forceGet is true.
    getHitlistWidth: function (forceGet) {
        var hitlist = MapSearch.getHitlist();
        var width = 0;

        if (MapSearch.resultFieldWidth == 0) {
            if (hitlist.style.display != 'block' && forceGet) {
                MapSearch.showHitlist();
                width = hitlist.offsetWidth;
                MapSearch.hideHitlist();
            }
            else
                width = hitlist.offsetWidth;

            MapSearch.resultFieldWidth = width;
        }

        return MapSearch.resultFieldWidth;
    },

    // Fetches the container div element of the hitlist
    getHitlistContainer: function () {
        return document.getElementById('resultAjaxContainer');
    },

    // Shows a tooltip on the map or satellite view with the corresponding ID
    showMapToolTip: function () {

        var id = (arguments[0] && arguments[0].data) ? arguments[0].data.hitIndex : arguments[0];

        if (MapMode.getMapMode() == 'app') {
            TDapplet.showToolTip(id);
        } else {
            var marker = MapSearch.getHitById(id);
            if (marker) {
                marker.openInfoBoxBound();
            }
        }
    },

    // Hides a tooltip on the map or satellite view with the corresponding ID
    hideMapToolTip: function () {

        var id = (arguments[0] && arguments[0].data) ? arguments[0].data.hitIndex : arguments[0];

        if (MapMode.getMapMode() == 'app') {
            TDapplet.hideToolTip(id);
        } else {
            var marker = MapSearch.getHitById(id);
            if (marker) {
                marker.closeInfoBox();
            }
        }
    },

    clearHitlist: function () {
        MapSearch.clearAllHits();
        MapSearch.hideHitlist();
        MapSearch.setWhoValue('');
        MapSearch.setWhereValue('');
        this.nrOfHits = 0;

        if (MapMode.getMapMode() == 'app')
            document.getElementById('tdInfo').style.display = show ? 'block' : 'none';
    }
}

function zoomToPlace() {
    
    var params = {};

    if (arguments[0] && arguments[0].data) {
        arguments[0].preventDefault();
        for (arg in arguments[0].data) {
            params[arg] = arguments[0].data[arg];
        }
    } else {
        params['xpos'] = arguments[0];
        params['ypos'] = arguments[1];
        params['name'] = arguments[2];
        params['streetNumber'] = arguments[3];
        params['zip'] = arguments[4];
        params['placeType'] = arguments[5];
        params['id'] = arguments[6];
        params['level'] = arguments[7];
        params['placeHitData'] = arguments[8] ? arguments[8] : null;
        params['hitIndex'] = arguments[9] ? arguments[9] : null;
        params['hitLocality'] = arguments[10] ? arguments[10] : null;
    }
    
    try {
        if (params['placeHitData'] !== null) {
            var imgHit = new PlaceHit(params['placeHitData'].value.Tables[3].Rows[params['hitIndex']]);
            if (!MapJack.isLoaded) {
                imgHit.showStreetImage();
            }
            
            // Hide the 'zoom in' element
            $('div[name|=zoomLink]').css({'visibility': 'hidden'});

            // Create the 'Se gatubild' element
            var addressId = MapSearch.getAddressId(params['name'], params['streetNumber'], "", params['hitLocality']);
            if (addressId != "" && (MapMode.getMapMode() != "app")) {
                var url = MapSearch.IMAGE_BASE_URL + addressId;
                var marker = MapSearch.markers[params['hitIndex']];
                HMapHelpers.getJSONP(url, MapSearch.callback, marker);
            }
        }

        if (MapMode.getMapMode() == 'app') {
            TDapplet.setPosition(params['xpos'], params['ypos'], Map.getResolutionFromZoomLevel(params['level']), true);
        } else if (MapJack.isLoaded) {
            var point = new HPointRT90(params['ypos'], params['xpos']);
            hittaMap.map.setZoom(MapSearch.STREETVIEW_DEFAULT_ZOOM_LEVEL, point);
            HViewer.navigateToRT90(point);
        } else {

            // If this zoom is made from a hit without a who value, we just want to zoom and show the place, and skip searching (i.e. who="", where="norsborg").
            var skipDynamicSearch = (MapSearch.getWhoValue().length == 0 && MapSearch.allowDynamicSearch == true);

            if (skipDynamicSearch) {
                MapSearch.allowDynamicSearch = false;
            }

            hittaMap.map.setZoom(10 - params['level'], new HPointRT90(params['ypos'], params['xpos']));
            MapSearch.showStreetImageByAddress(params['name'], params['streetNumber'], '', params['zip'], typeof (params['placeType'] != 'undefined') && params['placeType'] == 'address');

            if (skipDynamicSearch) {
                MapSearch.allowDynamicSearch = true;
                MapSearch.lockHits = true;
            }

            if (params['placeType'] == 'address')
                MapModeControl.placeId = params['id'];

            if (typeof (MapSearch.singleHitCallback) == 'function') {
                MapSearch.singleHitCallback();
            }
        }
    }
    catch (ex) {
    }
}

// Data structure for the header of the response.
function Header(response) {
    var row = response.value.Tables[0].Rows[0];

    this.noOfWhiteGlobalHits = row["NoOfWhiteGlobalHits"];
    this.noOfWhiteDisplayHits = row["NoOfWhiteHitsReturned"];
    this.noOfWhiteTotalRegionHits = row["NoOfWhiteRegionHits"];
    this.noOfPinkGlobalHits = row["NoOfPinkGlobalHits"];
    this.noOfPinkDisplayHits = row["NoOfPinkHitsReturned"];
    this.noOfPinkTotalRegionHits = row["NoOfPinkRegionHits"];
    this.noOfPlaceGlobalHits = row["NoOfPlaceGlobalHits"];
    this.noOfPlaceDisplayHits = row["NoOfPlaceHitsReturned"];
    this.noOfPlaceTotalRegionHits = row["NoOfPlaceRegionHits"];
    this.noOfWhiteHitsShown = row["NoOfWhiteHitsShown"];
    this.noOfPinkHitsShown = row["NoOfPinkHitsShown"];
    this.noOfPlaceHitsShown = row["NoOfPlaceHitsShown"];
    this.currentPage = row["CurrentPage"];
    this.firstPageSearchLimit = row["FirstPageSearchLimit"];
    this.subPageSearchLimit = row["SubPageSearchLimit"];
    this.pinkPoints = row["PinkPoints"];
    this.whitePoints = row["WhitePoints"];
    this.placePoints = row["PlacePoints"];
    this.zoomLevel = row["ZoomLevel"];
    this.centerX = row["CenterX"];
    this.centerY = row["CenterY"];
    this.level = row["Level"];
    this.nextLevel = row["NextLevel"];
    this.boundaryString = row["BoundaryString"];
    this.exceptionMessage = row["ExceptionMessage"];
    this.wasRegionSearch = row["WasRegionSearch"] == 'True';    // The value passed from ajax is not automatically converted to a bool.
    this.totalHits = this.noOfWhiteTotalRegionHits + this.noOfPinkTotalRegionHits + this.noOfPlaceTotalRegionHits;
}

// Data structure for a pink hit
function PinkHit(row) {
    this.vkiid = row["Vkiid"];
    this.name = row["Name"];
    this.xPos = row["Xpos"];
    this.yPos = row["Ypos"];
    this.phoneNumber = row["PhoneNumber"];
    this.mobileNumber = row["MobileNumber"];
    this.streetAddress = row["StreetAddress"];
    this.streetName = row["StreetName"];
    this.streetNumber = row["StreetNumber"];
    this.streetSuffix = row["StreetSuffix"];
    this.zipCode = row["ZipCode"];
    this.locality = row["Locality"];
    this.normalizedLocality = this.locality.charAt(0) + String(this.locality.substring(1, this.locality.length)).toLowerCase();
    this.heading = row["Heading"] != null ? new Heading(row["Heading"]) : null;
    this.productType = row["ProductType"]; // note: not used.
    this.prioImage = row["PrioImage"]; // note: not used.

    this.hitListText = this.name;

    this.toolTipContentHtml = '<div style="margin-left:3px;"><div style="width:172px; font-weight:bold;">' + this.name + '</div>';
    this.toolTipContentHtml += this.phoneNumber.length != 0 ? '<div style="clear:both;">' + this.phoneNumber + '</div>' : '';
    this.toolTipContentHtml += this.mobileNumber.length != 0 ? '<div style="clear:both;">' + this.mobileNumber + '</div>' : '';
    this.toolTipContentHtml += this.streetAddress.length != 0 ? '<div style="clear:both;">' + this.streetAddress + '</div>' : '';
    this.toolTipContentHtml += this.zipCode.length != 0 ? this.zipCode : '';
    this.toolTipContentHtml += this.locality.length != 0 ? ' ' + this.locality : '';

    this.toolTipContentApp = this.name;
    this.toolTipContentApp += this.phoneNumber.length != 0 ? '\\\\' + this.phoneNumber : '';
    this.toolTipContentApp += this.mobileNumber.length != 0 ? '\\\\' + this.mobileNumber : '';
    this.toolTipContentApp += this.streetAddress.length != 0 ? '\\\\' + this.streetAddress : '';
    this.toolTipContentApp += this.zipCode.length != 0 ? '\\\\' + this.zipCode : '';
    this.toolTipContentApp += this.locality.length != 0 ? ' ' + this.locality : '';
    this.toolTipContentApp += '</div>';
    this.type = 'PinkHit';

    this.showStreetImage = function () { showStreetImage(this.streetName, this.streetNumber, this.streetSuffix, this.zipCode, false); };
}
/*
function getHeadings(headingString) {
    var stringParts = headingString.split(';');
    var result[] = {};
    var id; var name;
    for (i = 0; i < stringParts.length; i++) {
        if (i % 2 == 0)
            id = stringParts[i];
        else {
            name = stringParts[i];
            result.add(new Heading(id, name));
        }
    }
}*/

function Heading(headingString) {
    this.id = headingString.split(';')[0];
    this.name = headingString.split(';')[1];
}
// Data structure for a white hit
function WhiteHit(row)
{
    this.vkiid = row["Vkiid"];
    this.firstName = row["FirstName"];
    this.middleName = row["MiddleName"];
    this.lastName = row["LastName"];
    this.xPos = row["Xpos"];
    this.yPos = row["Ypos"];
    this.phoneNumber = row["FixedPhone"];
    this.mobileNumber = row["MobilePhone"];
    this.streetAddress = row["StreetAddress"];
    this.streetName = row["StreetName"];
    this.streetNumber = row["StreetNumber"];
    this.streetSuffix = row["StreetSuffix"];
    this.zipCode = row["ZipCode"];
    this.locality = row["Locality"];  
    
    this.formattedName = '';
    if (this.firstName != null)
        this.formattedName += this.firstName;        
    if (this.middleName != null)     
        this.formattedName += (this.formattedName.length > 0) ? " " + this.middleName : this.middleName;        
    if (this.lastName != null)		            
        this.formattedName += (this.formattedName.length > 0) ? " " + this.lastName : this.lastName;
        
    this.hitListText = this.formattedName;
    this.toolTipContentHtml = '<div style="margin-left:3px;"><b>' + this.formattedName + '</b><br>' + (this.phoneNumber ? 'Telefon: ' + this.phoneNumber + '<br>' : '') + (this.mobileNumber ? 'Mobil: ' + this.mobileNumber + '<br>' : '') + this.streetAddress + '<br>' + this.zipCode + " " + this.locality + '</div>';
    this.toolTipContentApp = this.formattedName + '\\\\' + this.streetAddress + '\\\\' + this.zipCode + ' ' + this.locality;
    this.type = 'WhiteHit';
    
    this.showStreetImage = function() { showStreetImage(this.streetName, this.streetNumber, this.streetSuffix, this.zipCode, false); };
}

// Data structure for a place hit
function PlaceHit(row) {
    
    this.id = row["ID"];
    this.name = row["Name"];
    this.xPos = parseInt(row["Xpos"]);
    this.yPos = parseInt(row["Ypos"]);
    this.xPos2 = parseInt(row["Xpos2"]);
    this.yPos2 = parseInt(row["Ypos2"]);
    this.xPosMid = isNaN(this.xPos2) ? this.xPos : (this.xPos + (this.xPos2 - this.xPos) / 2);
    this.yPosMid = isNaN(this.yPos2) ? this.yPos : (this.yPos + (this.yPos2 - this.yPos) / 2);
    this.streetNumber = row["StreetNumber"];
    this.zipCode = row["ZipCode"];
    this.locality = row["Locality"];    
    this.communityName = row["CommunityName"];
    this.placeType = row["Type"];
    this.placeTypeCode = row["PlaceType"];
    this.placeTypeName = placeTypes[this.placeTypeCode];
    

    this.city = this.locality ? this.locality : this.communityName ? this.communityName : '';    
    this.fullName = this.name + (this.streetNumber ? ' ' + this.streetNumber : '') + '<br />' + (this.zipCode ? ' ' + this.zipCode : '') + ((this.city && this.city != this.name) ? ' ' + this.city : '');
    var placeSearch = this.name + (this.streetNumber ? ' ' + this.streetNumber : '') + (this.zipCode ? ' ' + this.zipCode : '') + ((this.city && this.city != this.name) ? ' ' + this.city : '');     
    this.hitLink = "ViewDetailsPlace.aspx?vad=&var=" + MapSearch.getWhereValue() + (this.placeType == 'place' ? "&PlaceId=" : "&StreetNumberId=") + this.id;       
        
    this.hitListText = this.name + (this.streetNumber ? ' ' + this.streetNumber : '') + ((this.city && this.city != this.name) ? ', ' + this.city : '');
    this.hitLinkChoice = 'javascript:MapSearch.search(\'' + MapSearch.getWhoValue() + '\', \'' + placeSearch + '\')';
    this.toolTipContentHtml = '<div class="place_hit_wrapper">' + this.fullName + "<br />(" + this.placeTypeName + ")</div>";
    this.toolTipContentHtmlChoice = '<b>' + this.fullName + '</b><br><a href="' + this.hitLinkChoice + '">Välj</a>';
    this.toolTipContentApp = this.fullName;
    this.type = 'PlaceHit';

    this.showStreetImage = function() { showStreetImage(this.name, this.streetNumber, '', this.zipCode, this.placeType == "address"); };    

}


var placeTypes = {

    ADRESS: "Adress",
    ANLTX: "Anläggning",
    BADPLATS: "Badplats",
    BEBTX: "Bebyggelse",
    BEBTÄTTX: "Tätort",
    GLACIÄRTX: "Glaciär",
    KOMMUN: "Kommun",
    KTRAFIK: "Buss/Tåg",
    KULTURTX: "Kultur",
    KYRKATX: "Kyrka",
    LÄN: "Län",
    NATTX: "Natur",
    POSTNR: "Postnr",
    POSTORT: "Postort",
    RESTRTX: "Nationalpark",
    SANKTX: "Sankmark",
    STADSDEL: "Stadsdel",
    TERRTX: "Terräng",
    TRAKTTX: "Bebyggelse",
    VATTDELTX: "Vatten",
    VATTDRTX: "Vatten",
    VATTTX: "Vatten",
    MALL: "Köpcentra"
};


function Address(streetName, streetNumber, streetSuffix, zipCode) {
    this.streetName = streetName;
    this.streetNumber = streetNumber;
    this.streetSuffix = streetSuffix;
    this.zipCode = zipCode;    
    this.showStreetImage = function () { showStreetImage(this.streetName, this.streetNumber, this.streetSuffix, this.zipCode, false); };
}

function showStreetImage(address, addressNo, literal, zip, displayWalkLink) {

    try {
        var div = document.getElementById('largeMapStreetImage');
        if (div)
        {
            div.style.top = _MapToolbarsTop.getHeight() + 94 + 'px';  // + 76 för nedskjutning pga popup meny
            var ds = AjaxMethods.GetStreet(address, addressNo, literal, zip).value;
            if (ds != null && typeof(ds) == "object" && ds.Tables != null && ds.Tables.length > 0 && ds.Tables[0].Rows[0].thumb != '')
            {            
                div.style.display = 'block';
                var html = '<div id=\'imgdiv2\' name=\'imgdiv2\'><div><p>';
                
                if (displayWalkLink)
                    html += '<a class="toplinks" href="javascript:void(0);" onclick="MapSearch.showAllStreetImages();">Fler bilder</a><span class="bullet">&#149;</span>';
                
                html += '<a class=toplinks href="javascript:MapSearch.hideStreetImage();">Stäng</a></p><img src="'+ds.Tables[0].Rows[0].thumb+'" width=130 height=173 alt="" title="" border=0><p><img class=noIE src="Images/MapPoint_NoNumber.gif" width=10 height=10 border=0> ' + /*ds.Tables[0].Rows[0].street*/ address + ' ' + ds.Tables[0].Rows[0].streetno + ' ' + ds.Tables[0].Rows[0].litera + '</p></div></div>';                        
                
                div.innerHTML = html;
            } else {
                // Remove image when a different location on the hitlist is clicked. 
                $('#largeMapStreetImage').remove();
            }
        }
    } catch(ex) { }
}

