$(document).ready(function () {

/*
  EGMap layers:

  3G Dual Band = Dual Band, Dual Band External Antenna, Future Dual Band
  3G Single Band = Single Band, GSM_CarKit, GSM_OnStreet  
  2G = GSM_CarKit, GSM_OnStreet
*/

  var map, optusCoverageLayers, wmsInfoLayer, markerLayer, imageFormat;
  imageFormat = 'image/gif'; // for IE 6 compatibility and no outline on overlays
  var olProjection = null;
  var coverageType = "dual";
  // 0 = turn off, 1 = show on click, 2 = show automatically or on click
  var markerMsgSupport = 1;

  // Avoid pink tiles
  OpenLayers.IMAGE_RELOAD_ATTEMPTS = 3;
  OpenLayers.Util.onImageLoadErrorColor = "transparent";
  OpenLayers.ProxyHost = mapConfig.openLayersProxy;
  OpenLayers.DOTS_PER_INCH = 90.71428571428572;
  var options = {
    units: "meters",
    resolutions: [156543.03390625, 78271.516953125, 39135.7584765625, 19567.87923828125, 9783.939619140625, 4891.9698095703125, 2445.9849047851562, 1222.9924523925781, 611.4962261962891, 305.74811309814453, 152.87405654907226, 76.43702827453613, 38.218514137268066, 19.109257068634033, 9.554628534317017, 4.777314267158508, 2.388657133579254, 1.194328566789627, 0.5971642833948135, 0.29858214169740677, 0.14929107084870338, 0.07464553542435169, 0.037322767712175846, 0.018661383856087923, 0.009330691928043961, 0.004665345964021981],
    projection: new OpenLayers.Projection('EPSG:900913'),
    maxExtent: new OpenLayers.Bounds(-2.003750834E7, -2.003750834E7, 2.003750834E7, 2.003750834E7),
    scales: [50000000, 30000000, 10000000, 5000000],
    controls: [
    new OpenLayers.Control.Navigation(), new OpenLayers.Control.PanZoomBar(), new OpenLayers.Control.ScaleLine()]
  };

  map = new OpenLayers.Map('map', options); //options
  //set up google layers with normal colour SLD
  //var gmap = new OpenLayers.Layer.Google( "Google Streets", {numZoomLevels: 20, sphericalMercator:true} );
  //set up google layers with B&W SLD
  //var stylez = [{ featureType: "all", elementType: "geometry", stylers: [{ gamma: 0.50 }, { saturation: -100 }] }]; 
  //set up google layers with colour SLD minus clashing green parkland and landscape
  var stylez = [
    { featureType: "poi.park", stylers: [{ visibility: "off" } ] },
    { featureType: "landscape", stylers: [ { visibility: "off" } ] }
  ];

  var MY_MAPTYPE_ID = 'custom';
  var styledMapOptions = {
    name: MY_MAPTYPE_ID
  };
  var myMapType = new google.maps.StyledMapType(stylez, styledMapOptions);

  var gmap = new OpenLayers.Layer.Google("Google Streets", {
    type: 'custom',
    numZoomLevels:10,
    minZoomLevel:5,
    maxZoomLevel:17,
    sphericalMercator: true,
    maxExtent: new OpenLayers.Bounds(-2.003750834E7, -2.003750834E7, 2.003750834E7, 2.003750834E7)
  });
  var markerLayer = new OpenLayers.Layer.Markers("Marker");
  map.addLayers([gmap, markerLayer]);

  map.getLayer(gmap.id).mapObject.mapTypeId = MY_MAPTYPE_ID;
  map.getLayer(gmap.id).mapObject.mapTypes.set(MY_MAPTYPE_ID, myMapType);

	map.numZoomLevels = 10;
  map.setCenter(new OpenLayers.LonLat(16399489.422513165, -3872898.7634850657), 0);

  //AddressBlaster
  // Must start with a number or letter
  // Optionally continue with a hyphen, space, number or letter
  $("input#addressblaster").regexMask(/^[0-9A-Za-z]+[\-\s0-9A-Za-z]*$/);

  $("input#addressblaster").bestupper();

  // Prompt should appear in grey text
  $("input#addressblaster").addClass("grey_text");

  // Remove prompt once clicked
  $("input#addressblaster").click(function (e) {
    if ($(this).val() === "Please enter address here") {
      $(this).removeClass("grey_text");
      $(this).val("");
      $(this).focus();
    }
  });

  //Setting up AddressBlaster. Set cache: true in production
  //TODO wrap up as jquery plugin
  $("input#addressblaster").autocomplete({
    source: function (request, response) {
      request.term = sanitizeAddressTerm(request.term);
      if (request.term.length > 1) {
        $.ajax({
          url: mapConfig.AddressBlasterServet,
          dataType: "jsonp",
          data: {
            limit: "10",
            logic: false,
            cache: true,
            query: request.term
          },
          success: function (data) {
            response($.map(data.results, function (item) {
              return {
                label: item.address,
                lat: item.lat,
                lon: item.lon,
                zoom: item.zoomLevel
              }
            }))
          }
        })
      }
    },
    // minLength: 2,
    select: function (event, ui) {
      var olProjection = zoomToCenter(ui.item.lat, ui.item.lon, ui.item.zoom);
      setTimeout(function(){  
            	addMarkerAndMsg(mapConfig.xy);
         }, 500); 
    },
    open: function () {
      $(this).removeClass("ui-corner-all").addClass("ui-corner-top");
    },
    close: function () {
      $(this).removeClass("ui-corner-top").addClass("ui-corner-all");
    }
  });


  //set up splider
  $("#slider").slider({
    range: "min",
    min: 0,
    max: 100,
    value: mapConfig.initOpacity,
    slide: function (event, ui) {
      setOverlayOpacity(ui.value);
      // To set correctly when switching networks
      mapConfig.initOpacity = ui.value;
    }
  });


  // coverage type switcher
  $("input[name='coverage-switch']").click(function () {
    //set new disclaimer
    $(".coverage-switch").removeClass("selected");
    $(this).parent().addClass("selected");
    coverageType = $(this).val();
    buildLegend(coverageType);
//    loadSeparateCoverageLayers(coverageType);
    loadCombinedCoverageLayers(coverageType);
    showDisclaimer(coverageType);
    activateTooltips();
    if (markerLayer && markerLayer.markers.length > 0) {
      var marker = markerLayer.markers[0];
      if (marker.feature && marker.feature.popup) {
        marker.feature.popup.destroy();
        setTimeout(function(){  
           addMarkerAndMsg(mapConfig.xy);  
        }, 500);        
      }
    }
  });

  $("input[name='coverage-switch'][value='dual']").trigger('click');

// One-off initialisation of those tooltips that are static in the HTML
  if ($(".tiptopright2"))
    $(".tiptopright2").tooltip({position: "top right", offset: [0, 0]});

// Reposition scalebar and copyright message
  repositionGoogleBits();


  /*---------------------------- util functions -------------------------------*/

	function repositionGoogleBits() {
		if (!$(".olLayerGoogleCopyright").css("left")) {
		  setTimeout(function(){  
				repositionGoogleBits();
		  }, 1000);
		}
		$(".olLayerGoogleCopyright").css("left", "147px");
		$(".olControlScaleLine").css("left", "72px").css("bottom", "1px");
  }
  
  function zoomToCenter(lat, lon, zoomLevel) {
		var zoomParam = map.numZoomLevels - 1;
    if (zoomLevel == "SUBURB") {
      zoomParam = map.numZoomLevels - 2;
    } else if (zoomLevel == "STATE") {
      zoomParam = 0;
    } else if (zoomLevel == "POSTCODE") {
      zoomParam = map.numZoomLevels - 2;
    }   

    olProjection = googleTransform(new OpenLayers.LonLat(lon, lat));
    map.setCenter(olProjection, zoomParam);
  }
  
  /* 
   * At the centre of the map, check coverage and add a marker with a popup coverage message
   */
  
  function addMarkerAndMsg(xy) {
  	if (markerMsgSupport == 0 || map.zoom < map.numZoomLevels - 2) {
    	setMarker(markerLayer, null, false);
    	return;
    }
    
    if (wmsInfoLayer == null)
    	return;
    
    if (!mapConfig.xy)
    	mapConfig.xy = {x:map.size.w/2, y:map.size.h/2};
    
    if (!xy)
    	xy = mapConfig.xy;
    	                  
    var config = mapConfig.coverages[coverageType];
    var layersCSV = toLayersCSV(config.layers, true);
    var url = wmsInfoLayer.getFullRequestString({
      REQUEST: "GetFeatureInfo",
      BBOX: map.getExtent().toBBOX(),
      X: xy.x,
      Y: xy.y,
      EXCEPTIONS: "application/vnd.ogc.se_xml",
      INFO_FORMAT: "application/vnd.ogc.gml",
      LAYERS: layersCSV,
      QUERY_LAYERS: layersCSV,
      WIDTH: map.size.w,
      HEIGHT: map.size.h,
      FEATURE_COUNT: 1});
    OpenLayers.loadURL(url, '', this, onXmlFeatureInfo);
  }
  
  /* 
   * Converts array of layers to comma-separated layer string
   */
  
  function toLayersCSV(layers, ascending) {
    var layersCSV = "";
    $.each(layers, function(index, layer) {
      if (ascending) {
        if (index > 0)
          layersCSV += ",";
        layersCSV += layer.layer;
      }
      else {
        if (index == 0)
          layersCSV = layer.layer;
        else
          layersCSV = layer.layer + "," + layersCSV;
      }
    });
    return layersCSV;
  }


  /*
   * Called when XML feature info ready.
   */

  function onXmlFeatureInfo(response) {
    var xml = response.responseText;
    if (response.status === 200 && response.responseText) {
      if (xml.indexOf("</gml:boundedBy></wfs:FeatureCollection>") !== -1)
        showMarkerMsg(0);
      else if (xml.indexOf("<gml:featureMember><EGMap:DualBand fid") !== -1)
        showMarkerMsg(1);
      else if (xml.indexOf("<gml:featureMember><EGMap:DualBandExtAnt fid") !== -1)
        showMarkerMsg(2);
      else if (xml.indexOf("<gml:featureMember><EGMap:DualBandFut fid") !== -1)
        showMarkerMsg(3);
      else if (xml.indexOf("<gml:featureMember><EGMap:3GNetwork fid") !== -1)
        showMarkerMsg(1);
      else if (xml.indexOf("<gml:featureMember><EGMap:2GOnStreet fid") !== -1)
        showMarkerMsg(4);
      else if (xml.indexOf("<gml:featureMember><EGMap:2GCarKit fid") !== -1)
        showMarkerMsg(5);       
      else if (window.console && console.warn)
        console.warn("Unexpected coverage");
    }
    else if (window.console && console.warn)
      console.warn(response);
  }


  function showMarkerMsg(msgIndex) {
    var label = markerMsg[msgIndex];
    if (msgIndex === 0 || msgIndex === 3) {
      var config = mapConfig.coverages[coverageType];
      label += " on the " + config.description;
    }  
    setMarker(markerLayer, label, true);    
  }
  
  /*
   *  Helper function to transform from one projection to another
   *  make sure that proj4js that is included
   */

  function projTransform(from, to, lonLat) {
    var from_projection = new OpenLayers.Projection(from);
    var to_projection = new OpenLayers.Projection(to);
    googleProj = lonLat.transform(from_projection, to_projection);

    return googleProj;
  }

  /*
   *  Helper function to transform from one projection to marcator
   */

  function googleTransform(lonLat) {
    var from_projection = new OpenLayers.Projection("EPSG:4326");
    var to_projection = new OpenLayers.Projection("EPSG:900913");
    googleProj = lonLat.transform(from_projection, to_projection);
    return googleProj;
  };


  /*
   *  Helper function to transform from one projection to marcator
   */



  /*
   *  Will prepare a list of separate layers for a given coverage type
   *  and load them into map object
   */

  function loadSeparateCoverageLayers(coverageType) {

    //drop current coverage layers first
    if (optusCoverageLayers && optusCoverageLayers.length > 0) {
      for (var i = optusCoverageLayers.length - 1; i >= 0; i--) {
        map.removeLayer(optusCoverageLayers[i]);
      }
    }

    optusCoverageLayers = [];
    var config = mapConfig.coverages[coverageType];
  
    wmsInfoLayer = new OpenLayers.Layer.WMS("Info Layer", mapConfig.wmsUrl, {
          visibility: false,
          layers: "",
          srs: 'EPSG:900913',
          tiled: true,
          transparent: true,
          format: imageFormat,
          tileSize: new OpenLayers.Size(256, 256)
        }, {
          isBaseLayer: false
        });
// Fake layer being on the map as actually adding generates unwanted GetMap
// calls for each (non-existent) tile       
    wmsInfoLayer.map = map;

    for (var i = config.layers.length - 1; i >= 0; i--) {
      var coverageLayer = new OpenLayers.Layer.WMS(config.layers[i].name, mapConfig.wmsUrl, {
        layers: config.layers[i].layer,
        srs: 'EPSG:900913',
        tiled: true,
        transparent: true,
        format: imageFormat,
        tileSize: new OpenLayers.Size(256, 256)
      }, {
        isBaseLayer: false
      });

      optusCoverageLayers.push(coverageLayer);
      map.addLayers([coverageLayer]);
    }; //for
    //move marker layer on top
    map.setLayerIndex(markerLayer, optusCoverageLayers.length + 1);

    setOverlayOpacity(mapConfig.initOpacity);
  }


  /*
   *  Will prepare a list of combined layers for a given coverage type
   *  and load them into map object
   */

  function loadCombinedCoverageLayers(coverageType) {

    var config = mapConfig.coverages[coverageType];

    try {
      if (wmsInfoLayer)
        map.removeLayer(wmsInfoLayer);
    }
    catch (e) {
      ;
    }

    var layers;
    var urlStart = window.location.href.substr(0, 10);
    if (config.groupLayer && urlStart !== "http://10." && urlStart !== "http://loc" && urlStart !== "http://jpa")
      layers = config.groupLayer;
    else 
      layers = toLayersCSV(config.layers, false);
      
    wmsInfoLayer = new OpenLayers.Layer.WMS("Overlay and Info Layer", mapConfig.wmsUrl, {
          visibility: true,
          layers: layers,
          srs: 'EPSG:900913',
          tiled: true,
          transparent: true,
          format: imageFormat,
          tileSize: new OpenLayers.Size(256, 256)
        }, {
          isBaseLayer: false
        });
    // Use combined layer for display as well as querying     
    map.addLayer(wmsInfoLayer);
    map.setLayerIndex(wmsInfoLayer, 1);

    //move marker layer on top
    map.setLayerIndex(markerLayer, 2);

    setOverlayOpacity(mapConfig.initOpacity);
  }


  function setMarker(markerLayer, label, autoShow) {
    var size = new OpenLayers.Size(21, 25);
    var offset = new OpenLayers.Pixel(-(size.w / 2), -size.h);
    var icon = new OpenLayers.Icon('images/marker-home.png', size, offset);
    var marker = new OpenLayers.Marker(olProjection, icon);

		if (markerMsgSupport > 0 && label !== null) {
      var feature = new OpenLayers.Feature(markerLayer, olProjection);
      feature.closeBox = true;
      feature.popupClass = OpenLayers.Class(OpenLayers.Popup.FramedCloud, {
        'autoSize': true,
        'isAlphaImage': false,
        'opacity': 1.0
      });
      feature.data.popupContentHTML = label;
      feature.data.overflow = "hidden";
      marker.feature = feature;

      var markerClick = function (evt) {
          if (this.popup == null) {
            this.popup = this.createPopup(this.closeBox);
            map.addPopup(this.popup);
            this.popup.show();
          } else {
            this.popup.toggle();
          }
          OpenLayers.Event.stop(evt);
        };
      marker.events.register("mousedown", feature, markerClick);
    }

    markerLayer.clearMarkers();
    markerLayer.addMarker(marker);

    if (markerMsgSupport == 2 && label !== null && autoShow)
      marker.events.triggerEvent("mousedown");
    return marker;
  }

  /*
   *  Helper function to build a legend block table
   */

  function buildLegendBlock(layerConfig) {
    var legendImage = mapConfig.wmsUrl + '?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic&LAYER=' + layerConfig.layer + '&Format=' + imageFormat;
    var helpHtml = layerConfig.name;
    if (layerConfig.nameHelp)
      helpHtml = layerConfig.nameHelp + helpHtml + "</span>";
    var legendBlock = '<td><table><tr>' + '<td class="legend-cell"><img src="' + legendImage + '" /></td>' + '<td class="legendLabel">' + helpHtml + '</td>' + ' </tr></table></td>';
    return legendBlock;
  }


  /*
   *  Helper function to build a table with layer legends
   */

  function buildLegend(coverageType) {
    $("#legend-table").empty();
    $("#legend-table").append("<table><tr></tr></table>");
    var tableTr = $("#legend-table table tr");
    var helpHtml = "<b>" + mapConfig.coverages[coverageType].description + "</b>";
    if (mapConfig.coverages[coverageType].descriptionHelp)
      helpHtml = mapConfig.coverages[coverageType].descriptionHelp + helpHtml + "</span>";
    $("#coverage-descriptor").html(helpHtml);
    var layers = mapConfig.coverages[coverageType].layers;
    for (var i = 0; i < layers.length; i++) {
      tableTr.append(buildLegendBlock(layers[i]));
    };
  }


  /* Switch between the 3 disclaimers */

  function showDisclaimer(network) {
    if (network === "twoG") {
      $("#disclaimer3GDual").hide("fast");
      $("#disclaimer3GSingle").hide("fast");
      $("#disclaimer2G").show("slow");
    } else if (network === "threeG") {
      $("#disclaimer2G").hide("fast");
      $("#disclaimer3GDual").hide("fast");
      $("#disclaimer3GSingle").show("slow");
    } else // dual
    {
      $("#disclaimer2G").hide("fast");
      $("#disclaimer3GSingle").hide("fast");
      $("#disclaimer3GDual").show("slow");
    }
  }


  /* Replace standard browser tooltips with precise, multiline ones */

  function activateTooltips() {
    if ($(".tiptopright")) $(".tiptopright").tooltip({
      position: "top right",
      offset: [0, 0]
    });
    if ($(".tiptopcenter")) $(".tiptopcenter").tooltip({
      position: "top center",
      offset: [0, 0]
    });
    if ($(".tiptopleft")) $(".tiptopleft").tooltip({
      position: "top center",
      offset: [0, -160]
    }); 
    if ($(".tiptopright1a"))
      $(".tiptopright1a").tooltip({position: "top right", offset: [0, -160]});
  }
  

  /* Placeholder for old menu function */
 
  function ie5PrimaryNavFix(link) {}


  function setOverlayOpacity(opacityPercent) {
    if ($.browser.msie) {
      ieSetOpacity("olTileImage", /GetLegendGraphic/g, opacityPercent);
      $(".legend-cell").css('opacity', 1);
    } else {
      var opacityRatio = opacityPercent / 100.0;
      if (optusCoverageLayers) {
        for (var i = optusCoverageLayers.length - 1; i >= 0; i--) {
          optusCoverageLayers[i].setOpacity(opacityRatio);
        }
      }
      else
        wmsInfoLayer.setOpacity(opacityRatio);
      $(".legend-cell").css('opacity', opacityRatio);
    }
  }


  /* Only IE 9 natively supports opacity, so this workaround, from
     http://msdn.microsoft.com/en-us/library/ms532969.aspx, is required */
    
  function ieSetOpacity(searchClass, imgSrcPattern, opacityPercent) {
    if ($.browser.msie) {
      var i, image;
      for (i in document.images) {
        try {
          image = document.images[i];
          if (image.src) {
            var imgSrc = image.src;
            if (image.className === searchClass || imgSrc.match(imgSrcPattern)) {
                image.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=" + opacityPercent + ")";
            }
          }
        }
        catch (e) {
        }
      }
    }
  }


  /* 
   * Extra check to remove commas and full stops, as the jQuery mask doesn't work on IE,
   * and ignore excessive length
   */ 
  function sanitizeAddressTerm(term) {
    if (!term)
      return "";
    term = term.replace(/\,/g, " ").replace(/\./g, " ");
    if (term.length > 255)
      term = term.substring(0,255);
    return term;
  }
  
});
