﻿/* Copyright (c) Hoseasons Holidays Limited
 * Author: Chris O'Brien
 * Date: 16 October 2008
 */

/// <summary>
/// Make sure global namespace Hos for all hoseasons JavaScript is defined.
/// </summary>
if (typeof Hos == 'undefined') {
Hos = {};
}

/// <summary>
/// Maxi map.
/// </summary>
Hos.MaxiMap = {

  MAP_CANVAS_ID: "map_canvas",
  MAPTYPE_FREETYPE: 0,
  MAPTYPE_REGION: 1,
  MAPTYPE_ALTERNATIVES: 2,
  MAPTYPE_PSEUDOREGION: 3,
  map: null,
  mapType: 0,
  startingpoint: "",
  localSearch: null,
  freeTypeLocation: null,
  freeTypeLat: 54.313919,
  freeTypeLong: -2.23218,
  freeTypeFoundInHosDB: false,
  count: 0,
  regionName: "",
  zoom: 12,
  viewOnMapZoom: 12,
  regionLat: 54.313919,
  regionLong: -2.23218,
  productTypeCode: 0,
  distance: 20,
  isParkMode: true,
  _minZoom: 6,
  _maxZoom: 17,

  /// <summary>
  /// Array<UKParkSite>
  /// UKParkSite = { marker: GMarker, lng: number, lat: number, name: string, image: string,
  ///        distance: number, siteCode: string, place: string, county: string, priceRange: string,
  ///        introText: string, minPrice: string, uniqueSellingPoint: string,  parks: Array<UKPark> }
  /// UKPark = { name:  string, maxSleepCount: number, accommodationCode: string, minPrice: string, accommodationType: string,
  ///        isInShortlist: boolean }
  /// </summary>
  markersData: [],
  overlays: [],

  /// <summary>
  /// This should be called when you want to display the map for the first time i.e. when the page loads or when the tab containing
  /// the map is shown for the first time. NOTE: Do no not call multiple times otherwise there will be repeated items in the search
  /// results.
  /// </summary>
  mapLoad: function() {
    //try { Throbber.beginRequest(); } catch (error) { alert(Error); }
    if (GBrowserIsCompatible()) {
      Hos.MaxiMap.localSearch = new GlocalSearch();
      Hos.MaxiMap.map = new GMap2(document.getElementById(this.MAP_CANVAS_ID));
      GEvent.addListener(Hos.MaxiMap.map, "load", Hos.MaxiMap.addLoadingReport);
      Hos.MaxiMap.map.enableScrollWheelZoom();
      Hos.MaxiMap.map.addControl(new GMapTypeControl());
      Hos.MaxiMap.map.addControl(new GLargeMapControl());
      Hos.MaxiMap.map.addControl(new GScaleControl());
      G_PHYSICAL_MAP.getMinimumResolution = function() { return Hos.MaxiMap._minZoom };
      G_NORMAL_MAP.getMinimumResolution = function() { return Hos.MaxiMap._minZoom };
      G_SATELLITE_MAP.getMinimumResolution = function() { return Hos.MaxiMap._minZoom };
      G_HYBRID_MAP.getMinimumResolution = function() { return Hos.MaxiMap._minZoom };

      G_PHYSICAL_MAP.getMaximumResolution = function() { return Hos.MaxiMap._maxZoom };
      G_NORMAL_MAP.getMaximumResolution = function() { return Hos.MaxiMap._maxZoom };
      G_SATELLITE_MAP.getMaximumResolution = function() { return Hos.MaxiMap._maxZoom };
      G_HYBRID_MAP.getMaximumResolution = function() { return Hos.MaxiMap._maxZoom };

      switch (parseInt(Hos.MaxiMap.mapType)) {
        case Hos.MaxiMap.MAPTYPE_FREETYPE:
          if(Hos.MaxiMap.freeTypeFoundInHosDB) {
            Hos.MaxiMap.startingpoint = new GLatLng(Hos.MaxiMap.freeTypeLat, Hos.MaxiMap.freeTypeLong);
            Hos.MaxiMap.map.setCenter(Hos.MaxiMap.startingpoint, parseInt(Hos.MaxiMap.zoom));
            Hos.MaxiMap.map.addOverlay(new GMarker(Hos.MaxiMap.startingpoint, Hos.MaxiMap.GetCentreIcon()));
            Hos.MaxiMap.CallSuccess(Hos.MaxiMap.markersData);
          } else {
            Hos.MaxiMap.usePointFromPostcode(Hos.MaxiMap.freeTypeLocation, Hos.MaxiMap.PlaceMarkerAtPoint);
          }
          break;

        case Hos.MaxiMap.MAPTYPE_REGION:
        case Hos.MaxiMap.MAPTYPE_ALTERNATIVES:
        case Hos.MaxiMap.MAPTYPE_PSEUDOREGION:
          Hos.MaxiMap.PlotPointOnMap();
          break;

        default:
          Hos.MaxiMap.startingpoint = new GLatLng(54.313919, -2.23218);
          Hos.MaxiMap.map.setCenter(Hos.MaxiMap.startingpoint, parseInt(Hos.MaxiMap.zoom));
          break;
      }
      scrollTo(0, 180);
    }
    GEvent.addListener(Hos.MaxiMap.map, "zoomend", Hos.MaxiMap.mapOnZoomEnd);
    GEvent.addListener(Hos.MaxiMap.map, "dragend", Hos.MaxiMap.mapOnDragEnd);
  },

  addLoadingReport: function() {
    // Text to display 
    var loadingText = 'Loading Map...';

    // Create a new element 
    var info = document.createElement('div');
    info.appendChild(document.createTextNode(loadingText));

    // Add an id to the element, in case you want to access it later 
    info.setAttribute('id', 'mapLoading');

    // Alternatively, you could apply the styles through a CSS stylesheet, using the #mapLoading selector 
    info.style.position = 'relative';
    info.style.padding = '2em';
    info.style.fontWeight = 'bold';
    info.style.fontSize = '12px';
    info.style.color = '#000';

    // Insert into map container
    this.getContainer().insertBefore(info, this.getContainer().firstChild);
  },

  PlotPointOnMap: function() {
    Hos.MaxiMap.startingpoint = new GLatLng(Hos.MaxiMap.regionLat, Hos.MaxiMap.regionLong);
    Hos.MaxiMap.map.setCenter(Hos.MaxiMap.startingpoint, parseInt(Hos.MaxiMap.zoom));
    Hos.MaxiMap.CallSuccess(Hos.MaxiMap.markersData);
  },

  setmapcenter: function() {
    Hos.MaxiMap.map.setCenter(Hos.MaxiMap.startingpoint, parseInt(Hos.MaxiMap.zoom));
  },

  usePointFromPostcode: function(pCode, callbackFunction) {
    Hos.MaxiMap.localSearch.setSearchCompleteCallback(null, function() {
      var resultLat = 54.313919;
      var resultLng = -2.23218;
      if (Hos.MaxiMap.localSearch.results[0]) {
        resultLat = Hos.MaxiMap.localSearch.results[0].lat;
        resultLng = Hos.MaxiMap.localSearch.results[0].lng;
      }
      if (!Hos.MaxiMap.localSearch.results[0] || resultLat < 48.5083 || resultLat > 60.0 || resultLng < -8.63 || resultLng > 2.0) {
        resultLat = 54.313919;
        resultLng = -2.23218;
        try {
          document.getElementById('noResultsMessage').style.display = 'block';
        } catch (Error) {};
        try { document.getElementById("staticThrobberDiv").style.display = 'none'; } catch (Error) { }
        return;
      }
      
      var point = new GLatLng(resultLat, resultLng);
      var marker = new GMarker(point, Hos.MaxiMap.GetCentreIcon());
      Hos.MaxiMap.map.setCenter(point, parseInt(Hos.MaxiMap.zoom));
      Hos.MaxiMap.map.addOverlay(marker);
      Hos.MaxiMap.startingpoint = point;
      callbackFunction(resultLat, resultLng);
    });
    Hos.MaxiMap.localSearch.execute(pCode + ", UK");
  },

  GetCentreIcon: function() {
    var icon = new GIcon();
    icon.image = Hos.MaxiMap.isParkMode ? "../../Images/UKPark/GoogleMapIcons/CenterMarker.png" : "../../Images/Lodge/GoogleMapIcons/CenterMarker.png";
    icon.iconAnchor = new GPoint(16, 16);
    icon.infoWindowAnchor = new GPoint(16, 0);
    icon.iconSize = new GSize(54, 44);
    return icon;
  },

  GetSelectedIcon: function() {
    var icon = new GIcon();
    icon.image = Hos.MaxiMap.isParkMode ? "../../Images/UKPark/GoogleMapIcons/complexSelected.png" : "../../Images/Lodge/GoogleMapIcons/complexSelected.png";
    icon.iconAnchor = new GPoint(11, 47);
    icon.infoWindowAnchor = new GPoint(16, 0);
    icon.iconSize = new GSize(64, 53);
    return icon;
  },

  GetParkIcon: function() {
    var icon = new GIcon();
    icon.image = Hos.MaxiMap.isParkMode ? "../../Images/UKPark/GoogleMapIcons/Complex.png" : "../../Images/Lodge/GoogleMapIcons/Complex.png";
    icon.iconAnchor = new GPoint(11, 47);
    icon.infoWindowAnchor = new GPoint(16, 0);
    icon.iconSize = new GSize(64, 53);
    return icon;
  },

  GetParkClusterIcon: function(number) {
    //Icons only go upto 15.
    if (number > 15) {
      number = 15;
    }
    var icon = new GIcon();
    icon.image = Hos.MaxiMap.isParkMode ? "../../Images/UKPark/GoogleMapIcons/ComplexCluster" + number + ".png" : "../../Images/Lodge/GoogleMapIcons/ComplexCluster" + number + ".png";
    icon.iconAnchor = new GPoint(11, 47);
    icon.infoWindowAnchor = new GPoint(16, 0);
    icon.iconSize = new GSize(64, 53);
    return icon;
  },

  createMarkerClickHandler: function(marker, uKParkSite) {
    return function() {
      scrollTo(0, 180);
      try {
        if (!marker.overlayOn) {
          Hos.MaxiMap.map.addOverlay(marker);
          marker.overlayOn = true;
          Hos.MaxiMap.map.setCenter(marker.getLatLng(), Hos.MaxiMap.viewOnMapZoom);
        }
        marker.openInfoWindowHtml(
          '<table id="balloon">\
            <tr>\
              <td>\
                <a id="balloonTitle" href="../UKPark/ProductDetailPage.aspx?ISDLNK=1&amp;SCODE=' + uKParkSite.siteCode + '&ACODE=' + uKParkSite.parks[0].accommodationCode + '&ISPKMD=' + Hos.MaxiMap.isParkMode + '\
                  ">' + uKParkSite.name + '</a>\
                <br/>\
                <span id="weeklyPriceFrom">Weekly prices <br> starting from </span>\
                <span id="minPrice">' + uKParkSite.minPrice + '</span>\
                <p id="introText">' + uKParkSite.introText + '</p>\
              </td>\
              <td>\
                <a href="../UKPark/ProductDetailPage.aspx?ISDLNK=1&amp;SCODE=' + uKParkSite.siteCode + '&ACODE=' + uKParkSite.parks[0].accommodationCode + '&ISPKMD=' + Hos.MaxiMap.isParkMode + '\
                   "><img id="searchResultImage"\ src="' + uKParkSite.image + '"></a>\
              </td>\
            </tr>\
            <tr >\
              <td>\
                <div id="viewComplex">\
                  <a href="../UKPark/ProductDetailPage.aspx?ISDLNK=1&amp;SCODE=' + uKParkSite.siteCode + '&ACODE=' + uKParkSite.parks[0].accommodationCode + '&ISPKMD=' + Hos.MaxiMap.isParkMode + '">Read more>></a>\
                </div>\
              </td>\
            </tr>\
          </table>'
        );
      }
      catch (Error) {
      }
      return false;
    };
  },

  createClusterMarkerClickHandler: function(marker) {
    return function() {
      Hos.MaxiMap.map.setCenter(marker.getLatLng());
      Hos.MaxiMap.map.zoomIn();
      return false;
    };
  },

  mapOnZoomEnd: function(oldZoom, newZoom) {
    Hos.MaxiMap.zoom = newZoom;
    Hos.MaxiMap.drawOverlays();
  },

  mapOnDragEnd: function() {
    Hos.MaxiMap.drawOverlays();
  },

  PlaceMarkerAtPoint: function(lat, lng) {
    PageMethods.DefaultRadialSearch(lat, lng, Hos.MaxiMap.distance, Hos.MaxiMap.isParkMode, Hos.MaxiMap.CallSuccess);
  },

  CallSuccess: function(res) {
    Hos.MaxiMap.markersData = eval(res);
    if (!Hos.MaxiMap.markersData) {
      Hos.MaxiMap.markersData = [];
    }

    for (var i = 0; i < Hos.MaxiMap.markersData.length; i++) {

      var selected = false;
      var latitude = parseFloat(Hos.MaxiMap.markersData[i].lat);
      var longitude = parseFloat(Hos.MaxiMap.markersData[i].lng);
      if (i == 0 && parseInt(Hos.MaxiMap.mapType) == Hos.MaxiMap.MAPTYPE_ALTERNATIVES) {
        selected = true;
      }
      Hos.MaxiMap.markersData[i].marker = Hos.MaxiMap.createMarker(selected, Hos.MaxiMap.markersData[i]);
    }
    Hos.MaxiMap.drawOverlays(); //Uses Hos.MaxiMap.markersData
    Hos.MaxiMap.createListItems(); // Uses Hos.MaxiMap.markersData

    document.getElementById("searchResultCount").innerHTML = "(" + Hos.MaxiMap.count + ")";
    if (parseInt(Hos.MaxiMap.mapType) == Hos.MaxiMap.MAPTYPE_FREETYPE) {
      document.getElementById("Text").innerHTML = 'Showing ' + Hos.MaxiMap.count + ' results for the term ' + Hos.MaxiMap.freeTypeLocation + ' with in ' + Hos.MaxiMap.distance + ' miles.';
    }
    else if (parseInt(Hos.MaxiMap.mapType) == Hos.MaxiMap.MAPTYPE_REGION || parseInt(Hos.MaxiMap.mapType) == Hos.MaxiMap.MAPTYPE_PSEUDOREGION) {
      document.getElementById("Text").innerHTML = 'Showing ' + Hos.MaxiMap.count + ' results for ' + Hos.MaxiMap.regionName;
    }
    else if (parseInt(Hos.MaxiMap.mapType) == Hos.MaxiMap.MAPTYPE_ALTERNATIVES) {
      document.getElementById("Text").innerHTML = 'Showing ' + parseInt(Hos.MaxiMap.count - 1) + ' alternate results for the site ' +
        Hos.MaxiMap.markersData[0].name + ' with in ' + Hos.MaxiMap.distance + ' miles.';
    }
    try { document.getElementById("staticThrobberDiv").style.display = 'none'; } catch (Error) { }
  },

  drawOverlays: function() {

    //Clear overlays
    for (var k = 0; k < Hos.MaxiMap.overlays.length; k++) {
      Hos.MaxiMap.overlays[k].overlayOn = false;
      Hos.MaxiMap.map.removeOverlay(Hos.MaxiMap.overlays[k]);
    }
    Hos.MaxiMap.overlays = [];

    try {
      var latitude = 0.0;
      var longitude = 0.0;

      //Divide map into grid.
      var gLatLngBounds = Hos.MaxiMap.map.getBounds();
      var southWest = gLatLngBounds.getSouthWest();
      var northEast = gLatLngBounds.getNorthEast();
      var zoom = Hos.MaxiMap.map.getZoom();

      if (zoom == Hos.MaxiMap._maxZoom) { // Do not cluster when zoomed in this close.
        for (var k = 0; k < Hos.MaxiMap.markersData.length; k++) {
          //Does fall in map area.
          if (Hos.MaxiMap.markersData[k].lng > southWest.lng() && Hos.MaxiMap.markersData[k].lng < northEast.lng() &&
            Hos.MaxiMap.markersData[k].lat > southWest.lat() && Hos.MaxiMap.markersData[k].lat < northEast.lat()) {
            Hos.MaxiMap.drawSingleOverlay(Hos.MaxiMap.markersData[k]);
          }
        }
      }
      else {

        //20x20 Grid. Each object in the grid will have the following properties when this method finishes { lngSW: 0.0, latSW: 0.0, lngNE: 0.0, latNE: 0.0, markerData: [] }
        var grid = [
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}],
        [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}]
        ];

        var fltGridWidth = parseFloat(grid[0].length);
        var fltGridHeight = parseFloat(grid.length);
        for (var y = grid.length - 1; y >= 0; y--) {
          for (var x = 0; x < grid[y].length; x++) {
            //Set bounds of grid cell.
            var cell = { latSW: 0.0, lngSW: 0.0, latNE: 0.0, lngNE: 0.0, markerData: [] };
            cell.lngSW = southWest.lng() + (x / fltGridWidth) * (northEast.lng() - southWest.lng());
            cell.latSW = southWest.lat() + (y / fltGridHeight) * (northEast.lat() - southWest.lat());
            cell.lngNE = southWest.lng() + ((x + 1) / fltGridWidth) * (northEast.lng() - southWest.lng());
            cell.latNE = southWest.lat() + ((y + 1) / fltGridHeight) * (northEast.lat() - southWest.lat());

            //Find all markers that fall in this grid cell.
            for (var k = 0; k < Hos.MaxiMap.markersData.length; k++) {
              //Does marker intersect cell.
              if (Hos.MaxiMap.markersData[k].lng > cell.lngSW && Hos.MaxiMap.markersData[k].lng < cell.lngNE &&
                Hos.MaxiMap.markersData[k].lat > cell.latSW && Hos.MaxiMap.markersData[k].lat < cell.latNE) {
                cell.markerData.push(Hos.MaxiMap.markersData[k]);
              }
            }

            //Put marker on map.
            if (cell.markerData.length == 0) { //Do not plot anything
            } else if (cell.markerData.length == 1) { //Plot the single park, not need to show cluster marker.
              Hos.MaxiMap.drawSingleOverlay(cell.markerData[0]);
            } else {
              //Draw cluster marker in middle of grid. This could be changed to weight the position to the park locations
              //but could suffer a performance hit and also markers could be place near the edge of the grid.
              Hos.MaxiMap.drawClusterMarker(cell.latSW + (cell.latNE - cell.latSW) / 2, cell.lngSW + (cell.lngNE - cell.lngSW) / 2, cell.markerData.length);
            }

            grid[(grid.length - 1) - y][x] = cell;
          }
        }
      }
    } catch (Error) {
    }
  },

  drawSingleOverlay: function(markerData) {
    try {
      Hos.MaxiMap.map.addOverlay(markerData.marker);
      markerData.marker.overlayOn = true;
      Hos.MaxiMap.overlays.push(markerData.marker);
    } catch (Error) {
    }
  },

  drawClusterMarker: function(lat, lng, count) {
    var point = new GLatLng(lat, lng);
    var marker;
    marker = new GMarker(point, Hos.MaxiMap.GetParkClusterIcon(count));
    var handler = Hos.MaxiMap.createClusterMarkerClickHandler(marker);
    GEvent.addListener(marker, "click", handler);
    Hos.MaxiMap.map.addOverlay(marker);
    marker.overlayOn = true;
    Hos.MaxiMap.overlays.push(marker);
  },

  createMarker: function(selected, uKParkSite) {
    var point = new GLatLng(uKParkSite.lat, uKParkSite.lng);
    var tempCount = Hos.MaxiMap.count + 1;
    var marker;
    if (selected) {
      marker = new GMarker(point, Hos.MaxiMap.GetSelectedIcon());
    } else {
      marker = new GMarker(point, Hos.MaxiMap.GetParkIcon());
    }
    var handler = Hos.MaxiMap.createMarkerClickHandler(marker, uKParkSite);
    GEvent.addListener(marker, "click", handler);
    return marker;
  },

  createListItems: function() {
    var isComplex = false;

    for (var k = 0; k < Hos.MaxiMap.markersData.length; k++) {
      var cssClass;
      var tempCount = Hos.MaxiMap.count + 1;
      var mileFromText;
      var listItem = document.createElement('li');
      var itm = document.getElementById('sidebar-list');
      var markerData = Hos.MaxiMap.markersData[k];

      Hos.MaxiMap.markersData[k].distance = Math.round(parseFloat(Hos.MaxiMap.markersData[k].distance) * 100) / 100;

      if (Hos.MaxiMap.count == 0 && Hos.MaxiMap.mapType == Hos.MaxiMap.MAPTYPE_ALTERNATIVES) {
        cssClass = 'selectedResult';
      }
      else {
        cssClass = 'Result';
      }

      if (parseInt(Hos.MaxiMap.mapType) == Hos.MaxiMap.MAPTYPE_REGION || parseInt(Hos.MaxiMap.mapType) == Hos.MaxiMap.MAPTYPE_PSEUDOREGION) {
        listItem.innerHTML = Hos.MaxiMap.createListItemInnerHTML(Hos.MaxiMap.mapType, cssClass, "", markerData);
      }
      else {
        if (Hos.MaxiMap.freeTypeLocation.length == 0) {
          mileFromText = "selected site";
        }
        else {
          mileFromText = Hos.MaxiMap.freeTypeLocation;
        }
        listItem.innerHTML = Hos.MaxiMap.createListItemInnerHTML(Hos.MaxiMap.mapType, cssClass, mileFromText, markerData);
      }

      var handler = Hos.MaxiMap.createMarkerClickHandler(markerData.marker, markerData);
      listItem.getElementsByTagName('a')[1].onclick = handler;
      Hos.MaxiMap.pagingEl.addItemToList(listItem);
      Hos.MaxiMap.count++;
    }
  },

  createListItemInnerHTML: function(mapType, cssClass, mileFromText, markerData) {
    var innerHTML = "";
    innerHTML =
      '<div class="siteContainer">\
        <table  width="100%" class="' + cssClass + '">\
          <tr>\
            <td >\
              <div class="googleResultImg"><img src=' + markerData.image + ' /></div>\
            </td>\
            <td align="left" width="400" class="addressDetails">\
              <h3><a href="../UKPark/ProductDetailPage.aspx?ISDLNK=1&amp;SCODE=' + markerData.siteCode + '&ACODE=' + markerData.parks[0].accommodationCode + '&ISPKMD=' + Hos.MaxiMap.isParkMode + '">' + markerData.name + '</a></h3>\
              <h4>' + markerData.place + ', ' + markerData.county + '</h4>\
              <span id="viewOnMapBtn"><a onclick="try{Throbber.beginRequest();}catch(error){}" href="javascript:void(0)" >View on map</a></span>'

              + ((mapType == Hos.MaxiMap.MAPTYPE_REGION || mapType == Hos.MaxiMap.MAPTYPE_PSEUDOREGION) ? '' :
                '<h4>Distance: ' + markerData.distance + ' miles from ' + mileFromText + '</h4>') +

            '</td>\
            <td width="200">\
              ' + markerData.uniqueSellingPoint + '\
            </td>\
            <td width="150">\
              <table border="0" width="120" >\
	              <tr align="center" >\
		              <td><span id="lblWeeklyPrice">Weekly Price Range</span></td>\
	              </tr>\
	              <tr>\
		              <td align="center"><span id="pricesFrom">\
                    <span id="lblPricesFrom">' + markerData.priceRange + '</span>\
                    </span>\
                  </td>\
	              </tr>\
              </table>\
              <div id="viewComplexBtn">\
                <a href="../UKPark/ProductDetailPage.aspx?ISDLNK=1&amp;SCODE=' + markerData.siteCode + '&ACODE=' + markerData.parks[0].accommodationCode + '&TIDPDUKPARK=parkInfo&ISPKMD=' + Hos.MaxiMap.isParkMode + '" >View ' + (Hos.MaxiMap.isParkMode ? 'Park' : 'Lodge') + ' Info</a>\
              </div>\
            </td>\
          </tr>\
        </table>\
        <table  class="accommodationList" id="' + markerData.siteCode + '_collapsible">\
          <tr >\
          	<th>Accommodation Name:</th>\
			      <th>Sleeps:</th>\
			      <th>Type:</th>\
			      <th>Code:</th>\
			      <th>Prices From:</th>\
			      <th></th>\
			    </tr>' +
			    (function() { //Loop through markerData.parks and create a new table row for each.
			      var trHTML = '';
			      for (var k = 0; k < markerData.parks.length; k++) {
			        trHTML +=
			        ((k == 3) ? '<tr ><td colspan="7"><a class="viewMoreAccommodations" id="' + markerData.siteCode + '_collapsibleBtn" href="#" onclick="Hos.MaxiMap._toggleExpandTable(\'' + markerData.siteCode + '\');return false">View more accommodations</a></td></tr>' : '') +
			        '<tr class="accommodationRow" ' + (k > 2 ? 'style="display: none"' : '') + '>\
                <td><h5><a href="../UKPark/ProductDetailPage.aspx?ISDLNK=1&amp;SCODE=' + markerData.siteCode + '&ACODE=' + markerData.parks[k].accommodationCode + '&TIDPDUKPARK=accommodationInfo">' + markerData.parks[k].name + '</a></h5>\
                <span>'
                + (markerData.parks[k].isInShortlist ? '<a id="shortListBtn_' + markerData.parks[k].accommodationCode + '" href="javascript:void(0);" class="removeFromShortlistBtn" onclick="Hos.MaxiMap.removeFromShortlistBtnClick(\'' + markerData.parks[k].accommodationCode + '\')">From My Shortlist</a>' :
                  '<a id="shortListBtn_' + markerData.parks[k].accommodationCode + '" href="javascript:void(0);" class="addToShortlistBtn" onclick="Hos.MaxiMap.addToShortlistBtnClick(\'' + markerData.parks[k].accommodationCode + '\')">To My Shortlist</a>')
                + '</span>\
                </td>\
                <td>' + markerData.parks[k].maxSleepCount + '</td>\
                <td>' + markerData.parks[k].accommodationType + '</td>\
                <td>' + markerData.parks[k].accommodationCode + '</td>\
                <td><b>' + markerData.parks[k].minPrice + '</b></td>\
                <td>\
                  <div id="availabilityCalendar">\
                    <table id="AvailabilityCalendar"  >\
                      <tr>\
                        <td id="availabilityCalendar2" colspan="4">\
                          <span id="availabilityCalendarBtn"><a id="hrefcottageProdDet" href="../../WebPages/Shared/AvailabilityPopup.aspx?ACODE=' + markerData.parks[k].accommodationCode + '&PCODE=306"\
                            onclick="return hs.htmlExpand(this, { contentId: \'highslide-html\', objectType: \'iframe\', objectWidth: 760, objectHeight: 390} )">\
                            View Availability</a></span>\
                        </td>\
                      </tr>\
                    </table>\
                  </div>\
                </td>\
                <td><a class="viewBtn" href="../UKPark/ProductDetailPage.aspx?ISDLNK=1&amp;SCODE=' + markerData.siteCode + '&ACODE=' + markerData.parks[k].accommodationCode + '&TIDPDUKPARK=accommodationInfo&ISPKMD=' + Hos.MaxiMap.isParkMode + '" >View</a></td>\
              </tr>';
			      }
			      return trHTML;
			    })()
        + '</table>\
      </div>';
    return innerHTML;
  },

  _toggleExpandTable: function(siteCode) {
    var table = document.getElementById(siteCode + '_collapsible');
    var btn = document.getElementById(siteCode + '_collapsibleBtn');
    var expand = table.rows[5].style.display == 'none';
    btn.innerHTML = expand ? 'View Less Accommodations' : 'View more accommodations';
    for (var k = 5; k < table.rows.length; k++) {
      table.rows[k].style.display = expand ? table.rows[0].style.display : 'none';
    }
  },

  addToShortlistBtnClick: function(accommodationCode) {
    try { Throbber.beginRequest(); } catch (error) { } //Show throbber.
    var sender = document.getElementById("shortListBtn_" + accommodationCode);
    PageMethods.addToShortlistBtn_Click(accommodationCode, function(shortlistTotal) {
      sender.parentNode.innerHTML = '<a id="shortListBtn_' + accommodationCode + '" href="javascript:void(0);" class="removeFromShortlistBtn" onclick="Hos.MaxiMap.removeFromShortlistBtnClick(\'' + accommodationCode + '\')">From My Shortlist</a>';
      try { Throbber.endRequest(); } catch (error) { } //Hide throbber.
      try { //Update shortlist tab
        updateShortlistTotal(shortlistTotal);
        updateShortlist = true;
      } catch (Error) { }
    });
    return false;
  },

  removeFromShortlistBtnClick: function(accommodationCode) {
    try { Throbber.beginRequest(); } catch (error) { } //Show throbber.
    var sender = document.getElementById("shortListBtn_" + accommodationCode);
    var ShortlistTotal = PageMethods.removeFromShortlistBtn_Click(accommodationCode, function(shortlistTotal) {
      sender.parentNode.innerHTML = '<a id="shortListBtn_' + accommodationCode + '" href="javascript:void(0);" class="addToShortlistBtn" onclick="Hos.MaxiMap.addToShortlistBtnClick(\'' + accommodationCode + '\')">To My Shortlist</a>';
      try { Throbber.endRequest(); } catch (error) { } //Hide throbber.
      try { //Update shortlist tab
        updateShortlistTotal(shortlistTotal);
        updateShortlist = true;
      } catch (Error) { }
    });
    return false;
  },

  pagingEl: (function() {
    var MaxItemsPerPage = 10;
    var pages = [];
    var topNumbersDiv = document.createElement("DIV");
    var bottomNumbersDiv = document.createElement("DIV");
    var topPageOfSpan = document.createElement("SPAN"); //e.g. Page 1 of 2
    var bottomPageOfSpan = document.createElement("SPAN"); //e.g. Page 1 of 2
    var topPreviousA = document.createElement("A");
    var bottomPreviousA = document.createElement("A");
    var topNextA = document.createElement("A");
    var bottomNextA = document.createElement("A");
    var addedDivsToSidebarList = false;
    var currentPageIndex = 0; //Zero based e.g. Page 1 has a currentPageIndex equal to 0.
    pages[0] = {
      el: document.createElement("DIV"),
      count: 0,
      topNumberA: null,
      bottomNumberA: null
    };

    //Set CSS Classes
    topNumbersDiv.className = "maxiMapPageNumbersTop";
    bottomNumbersDiv.className = "maxiMapPageNumbersBottom";
    topPageOfSpan.className = "maxiMapPageNumbersPageOf";
    bottomPageOfSpan.className = "maxiMapPageNumbersPageOf";
    topPreviousA.className = "maxiMapPageNumbersPrevious";
    bottomPreviousA.className = "maxiMapPageNumbersPrevious";
    topNextA.className = "maxiMapPageNumbersNext";
    bottomNextA.className = "maxiMapPageNumbersNext";

    //Structure DOM and add event handlers for top page numbers.
    topPreviousA.appendChild(document.createTextNode("<< Previous"));
    topPreviousA.href = "#";
    var previousAOnClick = function() {
      try { Throbber.beginRequest(); } catch (error) { } // Show throbber
      setTimeout(function() { //Delay put in because so the user can see that somthing is going on when they click.
        if (currentPageIndex > 0) {
          pages[currentPageIndex].el.style.display = 'none';
          pages[currentPageIndex].topNumberA.className = "maxiMapPageNumbersNumber";
          pages[currentPageIndex].bottomNumberA.className = "maxiMapPageNumbersNumber";
          currentPageIndex--;
          pages[currentPageIndex].el.style.display = 'block';
          pages[currentPageIndex].topNumberA.className = "maxiMapPageNumbersNumberSelected";
          pages[currentPageIndex].bottomNumberA.className = "maxiMapPageNumbersNumberSelected";
          topPageOfSpan.innerHTML = "Page " + (currentPageIndex + 1) + " of " + pages.length + " ";
          bottomPageOfSpan.innerHTML = "Page " + (currentPageIndex + 1) + " of " + pages.length + " ";
        }
        try { Throbber.endRequest(); } catch (error) { } // Hide throbber.
      }, 300);
      return false;
    };
    topPreviousA.onclick = previousAOnClick;
    topNextA.appendChild(document.createTextNode("Next >>"));
    topNextA.href = "#";
    var nextAOnClick = function() {
      try { Throbber.beginRequest(); } catch (error) { } // Show throbber
      setTimeout(function() { //Delay put in because so the user can see that somthing is going on when they click.
        if (currentPageIndex + 1 < pages.length) {
          pages[currentPageIndex].el.style.display = 'none';
          pages[currentPageIndex].topNumberA.className = "maxiMapPageNumbersNumber";
          pages[currentPageIndex].bottomNumberA.className = "maxiMapPageNumbersNumber";
          currentPageIndex++;
          pages[currentPageIndex].el.style.display = 'block';
          pages[currentPageIndex].topNumberA.className = "maxiMapPageNumbersNumberSelected";
          pages[currentPageIndex].bottomNumberA.className = "maxiMapPageNumbersNumberSelected";
          topPageOfSpan.innerHTML = "Page " + (currentPageIndex + 1) + " of " + pages.length + " ";
          bottomPageOfSpan.innerHTML = "Page " + (currentPageIndex + 1) + " of " + pages.length + " ";
        }
        try { Throbber.endRequest(); } catch (error) { } // Hide throbber.
      }, 300);
      return false;
    };
    topNextA.onclick = nextAOnClick;
    topNumbersDiv.appendChild(topPageOfSpan);
    topNumbersDiv.appendChild(document.createTextNode(" "));
    topNumbersDiv.appendChild(topPreviousA);
    topNumbersDiv.appendChild(document.createTextNode(" "));
    topNumbersDiv.appendChild(topNextA);

    //Structure DOM and add event handlers for top page numbers.
    bottomPreviousA.appendChild(document.createTextNode("<< Previous"));
    bottomPreviousA.href = "#";
    bottomPreviousA.onclick = previousAOnClick;
    bottomNextA.appendChild(document.createTextNode("Next >>"));
    bottomNextA.href = "#";
    bottomNextA.onclick = nextAOnClick;
    bottomNumbersDiv.appendChild(bottomPageOfSpan);
    bottomNumbersDiv.appendChild(document.createTextNode(" "));
    bottomNumbersDiv.appendChild(bottomPreviousA);
    bottomNumbersDiv.appendChild(document.createTextNode(" "));
    bottomNumbersDiv.appendChild(bottomNextA);

    function addPageNumber(number) {
      document.getElementById('sidebar-list').insertBefore(pages[number - 1].el, bottomNumbersDiv);
      var topNumberEl = document.createElement("A");
      var bottomNumberEl = document.createElement("A");
      if (number == 1) {
        topNumberEl.className = "maxiMapPageNumbersNumberSelected";
        bottomNumberEl.className = "maxiMapPageNumbersNumberSelected";
      }
      else {
        topNumberEl.className = "maxiMapPageNumbersNumber";
        bottomNumberEl.className = "maxiMapPageNumbersNumber";
      }
      pages[number - 1].topNumberA = topNumberEl;
      pages[number - 1].bottomNumberA = bottomNumberEl;
      topNumberEl.appendChild(document.createTextNode(number));
      bottomNumberEl.appendChild(document.createTextNode(number));
      topNumberEl.href = "#";
      bottomNumberEl.href = "#";
      topNumberEl.pageIndex = number - 1;
      bottomNumberEl.pageIndex = number - 1;
      var numberOnClick = function() {
        var sender = this;
        try { Throbber.beginRequest(); } catch (error) { } // Show throbber
        setTimeout(function() { //Delay put in because so the user can see that somthing is going on when they click.
          pages[currentPageIndex].el.style.display = 'none';
          pages[currentPageIndex].topNumberA.className = "maxiMapPageNumbersNumber";
          pages[currentPageIndex].bottomNumberA.className = "maxiMapPageNumbersNumber";
          pages[sender.pageIndex].el.style.display = 'block';
          pages[sender.pageIndex].topNumberA.className = "maxiMapPageNumbersNumberSelected";
          pages[sender.pageIndex].bottomNumberA.className = "maxiMapPageNumbersNumberSelected";
          currentPageIndex = sender.pageIndex;
          topPageOfSpan.innerHTML = "Page " + (currentPageIndex + 1) + " of " + pages.length + " ";
          bottomPageOfSpan.innerHTML = "Page " + (currentPageIndex + 1) + " of " + pages.length + " ";
          try { Throbber.endRequest(); } catch (error) { } // Hide throbber.
        }, 300);
        return false;
      };
      topNumberEl.onclick = numberOnClick;
      bottomNumberEl.onclick = numberOnClick;
      topNumbersDiv.insertBefore(topNumberEl, topNextA);
      bottomNumbersDiv.insertBefore(bottomNumberEl, bottomNextA);
      topNumbersDiv.insertBefore(document.createTextNode(" "), topNextA);
      bottomNumbersDiv.insertBefore(document.createTextNode(" "), bottomNextA);
      topPageOfSpan.innerHTML = "Page " + (currentPageIndex + 1) + " of " + pages.length + " ";
      bottomPageOfSpan.innerHTML = "Page " + (currentPageIndex + 1) + " of " + pages.length + " ";
    }

    return {
      addItemToList: function(listItem) {
        if (!addedDivsToSidebarList) { //Make sure it is run on page onload rather than script loaded.
          document.getElementById('sidebar-list').appendChild(topNumbersDiv);
          document.getElementById('sidebar-list').appendChild(pages[0].el); //Add first page
          document.getElementById('sidebar-list').appendChild(bottomNumbersDiv);
          addPageNumber(1);
          addedDivsToSidebarList = true;
        }
        //Add item to last page
        if (pages[pages.length - 1].count < MaxItemsPerPage) {
          pages[pages.length - 1].el.appendChild(listItem);
          pages[pages.length - 1].count++;
        }
        else { //Create a new page and add it to that.
          pages[pages.length] = {
            el: document.createElement("DIV"),
            count: 1,
            topNumberA: null,
            bottomNumberA: null
          };
          pages[pages.length - 1].el.appendChild(listItem);
          pages[pages.length - 1].el.style.display = 'none';
          addPageNumber(pages.length);
        }
      }
    }
  } ())
};
