var CONTENT_URL = "http://content.turbine.com/";
var GOOGLE_MAP_CONTENT_URL = "http://content.turbine.com/sites/google_map/";

/**
 * Map Object Selection
 * 
 * Select what things you want on the map (landmarks, quest givers, etc.) and
 * have the points fetched via AJAX and then displayed on the map.
 */
// Define the function
function TurbineGMapObjectSelection ( ) {
}

// Extend GControl
TurbineGMapObjectSelection.prototype = new GControl();

function TurbineWhatsAroundMe() {
	  var selectionType = $(this).val();
	  if( '' == selectionType) {
		selectionType = currentTypeSelection;
	  }
	  var mapContainer = map.getContainer();
	  var widgetId = mapContainer.getAttribute('widget');

	  if("" != selectionType) {
		// Save the character marker
		var characterMarker = '';
		if(markers['characterPosition']) {
		  characterMarker = markers['characterPosition'];
		}
		
		// Clear the current overlays
	    map.clearOverlays();

	    // Restore the character marker
	    if('' != characterMarker) {
          map.addOverlay(characterMarker);
	    }

	    // Send an AJAX call to fetch new points
      var search_term = '';
      var ajax_params = {
            action:       'ajax'
            , rs:         'efLotroInteractiveMap'
            , name:       encodeURIComponent(search_term)
            , territory:  territoryId
            , centerLat:  currentCenterLat
            , centerLng:  currentCenterLng
            , qst:        ( 'qst' == selectionType ) ? 1 : 0
            , mst:        ( 'mst' == selectionType ) ? 1 : 0
            , lmk:        ( 'lmk' == selectionType ) ? 1 : 0
            , bard:       ( 'bard' == selectionType ) ? 1 : 0
            , cls:        ( 'cls' == selectionType ) ? 1 : 0
            , ia:         ( 'ia' == selectionType ) ? 1 : 0
            , vk:         ( 'vk' == selectionType ) ? 1 : 0
            , sm:         ( 'sm' == selectionType ) ? 1 : 0
            , ven:        ( 'ven' == selectionType ) ? 1 : 0
            , crft:       ( 'crft' == selectionType ) ? 1 : 0
            , au:         ( 'au' == selectionType ) ? 1 : 0
            , other:      ( 'other' == selectionType ) ? 1 : 0
            , all:        1 // Tells the system to filter results based on the other flags above
      };

      $.ajax({
          type: 'GET',
          url: 'ajaxwidget.xml?w[i]=' + widgetId,
          data: ajax_params,
          error: function(XMLHttpRequest, textStatus, errorThrown) { alert(textStatus); alert(errorThrown); },
          success:
              function(data, textStatus) {
                var polygonCaptions = [];
                var resultCount = ($(data).find('locations').attr('count') > 0) ? $(data).find('locations').attr('count') + ' results' : 'No results found' ;

                $(data).find('marker').each( function() {
                    var mapIcon = GME_DEFAULT_ICON;
                    switch($(this).attr('type')) {
                      case 'landmark': mapIcon = POI_ICON; break;
                      case 'bard': mapIcon = BARD_ICON; break;
                      case 'class_trainer': mapIcon = CLASSTRAIN_ICON; break;
                      case 'craft_trainer': mapIcon = CRAFTTRAIN_ICON; break;
                      case 'forge': mapIcon = FORGE_ICON; break;
                      case 'stable': mapIcon = STABLE_ICON; break;
                      case 'vendor': mapIcon = VENDOR_ICON; break;
                      case 'vault': mapIcon = VAULT_ICON; break;
                      case 'auction': mapIcon = AUCTION_ICON; break;
                      case 'other_npc': mapIcon = OTHERNPC_ICON; break;
                      case 'quest_giver': mapIcon = QUEST_ICON; break;
                      case 'monster': mapIcon = MONSTER_ICON; break;
                    }
                    var marker = createMarker($(this).attr('id'), new GLatLng($(this).attr('lat'), $(this).attr('lng')), {'icon':mapIcon});
                    marker.id = $(this).attr('id');
                    marker.caption = $(this).text();
                    markers[$(this).attr('id')] = marker;
                    map.addOverlay(marker);
                  }
                );
                $(data).find('polyline').each( function() {
                    var polyPoints = [];
                    $(this).find('point').each( function() { polyPoints.push(new GLatLng($(this).attr('lat'), $(this).attr('lng'))); } );
                    var marker = new GPolygon( polyPoints, $(this).attr('line_color'), $(this).attr('line_weight'), $(this).attr('line_opacity'), $(this).attr('fill_color'), $(this).attr('fill_weight') );
                    marker.id = $(this).attr('id');
                    polygons[$(this).attr('id')] = marker;
                    map.addOverlay(marker);
                    if(!polygonCaptions[$(this).attr('id')]) {
                      $('#results').append($(this).find('caption').text() + '<div><img onclick="highlightPolygon(\'' + $(this).attr('id') + '\');" src="{GMAP_CONTENT_URL}google_map/open_map.gif" /> <span class="imap_highlight" onclick="openMarker(\'' + $(this).attr('id') + '\');">Highlight on map</span></div><hr />');
                      polygonCaptions[$(this).attr('id')] = true;
                    }
              	}
                );

                map.setZoom(parseInt($(data).find('locations').attr('zoom')));
              },
          dataType: 'xml'
      });
	  }
  }

// Initialize the control
TurbineGMapObjectSelection.prototype.initialize = function(map) {
  var container = document.createElement("div");
  
  var selection = document.createElement("select");
  selection.setAttribute("name", "tgmObjSelect");

  var noOption = document.createElement("option");
  noOption.setAttribute("value", "");
  noOption.appendChild(document.createTextNode("-- Select --"));

  var questGiver = document.createElement("option");
  questGiver.setAttribute("value", "qst");
  questGiver.appendChild(document.createTextNode("Quest Giver"));

  var landmark = document.createElement("option");
  landmark.setAttribute("value", "lmk");
  landmark.appendChild(document.createTextNode("Landmark"));

  var bard = document.createElement("option");
  bard.setAttribute("value", "bard");
  bard.appendChild(document.createTextNode("Bard"));

  var classTrainer = document.createElement("option");
  classTrainer.setAttribute("value", "cls");
  classTrainer.appendChild(document.createTextNode("Class Trainer"));

  var forge = document.createElement("option");
  forge.setAttribute("value", "ia");
  forge.appendChild(document.createTextNode("Forge-/Relic-master"));

  var vault = document.createElement("option");
  vault.setAttribute("value", "vk");
  vault.appendChild(document.createTextNode("Vault Keeper"));

  var stable = document.createElement("option");
  stable.setAttribute("value", "sm");
  stable.appendChild(document.createTextNode("Stable-master"));

  var vendor = document.createElement("option");
  vendor.setAttribute("value", "ven");
  vendor.appendChild(document.createTextNode("Vendor"));

  var craft = document.createElement("option");
  craft.setAttribute("value", "crft");
  craft.appendChild(document.createTextNode("Craft Trainer"));

  var auction = document.createElement("option");
  auction.setAttribute("value", "au");
  auction.appendChild(document.createTextNode("Auctioneer"));

  selection.appendChild(noOption);
  selection.appendChild(questGiver);
  selection.appendChild(landmark);
  selection.appendChild(bard);
  selection.appendChild(classTrainer);
  selection.appendChild(forge);
  selection.appendChild(vault);
  selection.appendChild(stable);
  selection.appendChild(vendor);
  selection.appendChild(craft);
  selection.appendChild(auction);
  
  container.appendChild(selection);
  
  GEvent.addDomListener(selection, "change", TurbineWhatsAroundMe );

  map.getContainer().appendChild(container);
  
  return container;
}

// Position the control
TurbineGMapObjectSelection.prototype.getDefaultPosition = function() {
  return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(70, 1));
}

/**
 * Expand/Contract
 * 
 * These are a custom Google Map controls that will expand or contract
 * the size of the div containing the map.
 */
function ExpandMapDivControl() {
}

ExpandMapDivControl.prototype = new GControl();

ExpandMapDivControl.prototype.initialize = function(map) {
	var container = document.createElement("div");

	var expandDiv = document.createElement("div");
	var expandImg = document.createElement("img");
	expandImg.setAttribute('src', 'http://content.turbine.com/sites/google_map/hide_results.gif');
	expandImg.setAttribute('title', 'Expand map');

	var contractDiv = document.createElement("div");
	var contractImg = document.createElement("img");
	contractImg.setAttribute('src', 'http://content.turbine.com/sites/google_map/show_results.gif');
	contractImg.setAttribute('title', 'Shrink map');

	var mapContainer = map.getContainer();

	this.setButtonStyle_(expandDiv);
	container.appendChild(expandDiv);
	expandDiv.appendChild(expandImg);
	expandDiv.setAttribute('class','gcExpand');

	GEvent.addDomListener(expandDiv, "click",
      function() {
		$('.gcExpand,.gcContract').toggle();
        $(mapContainer).data('orig_dims', {width: $(mapContainer).width(), height: $(mapContainer).height()});
        $(mapContainer).animate({width: "730px", height: "487px"}, function() {map.checkResize(); map.returnToSavedPosition(); $(mapContainer).closest("div.officialinset").css("float", "none"); $(".gcExpand,.gcContract").css("margin-right", "9px"); $("div#menumtctl").css("right", "34px");});
      } );

    this.setButtonStyle_(contractDiv);
	container.appendChild(contractDiv);
	contractDiv.appendChild(contractImg);
	contractDiv.setAttribute('class','gcContract');

	GEvent.addDomListener(contractDiv, "click",
      function() {
		$('.gcExpand,.gcContract').toggle();
        $(mapContainer).animate({width: $(mapContainer).data('orig_dims').width, height: $(mapContainer).data('orig_dims').height}, function() {map.checkResize(); map.returnToSavedPosition(); $(mapContainer).closest("div.officialinset").css("float", "right"); $(".gcExpand,.gcContract").css("margin-right", ""); $("div#menumtctl").css("right", "25px");});
      } );
	
	mapContainer.appendChild(container);
    $('.gcContract').hide();

	return container;
}

ExpandMapDivControl.prototype.getDefaultPosition = function() {
	return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(1, 1));
}

//Sets the proper CSS for the given button element.
ExpandMapDivControl.prototype.setButtonStyle_ = function(button) {
  button.style.padding = "2px";
  button.style.marginBottom = "3px";
  button.style.textAlign = "center";
  button.style.cursor = "pointer";
}

/**
 * LabelOverlay
 *
 * This is a custom Google Map overlay that is drawn as a simple text label on
 * the map.
 *
 *
 *
 * Creates a new LabelOverlay with the specified center, text label, and color.
 *
 * @param pCenter GlatLng - the center of the label
 * @param pLabel string - the text label
 * @param pColor string - the hex code for the color (include the '#')
 * @param pFontSize - the size of the font (in px)
 **/
function LabelOverlay ( pCenter, pLabel, pColor, pFontSize ) {
  this.mCenter = pCenter;
  this.mLabel = pLabel;
  this.mColor = pColor || "#fffa73";
  this.mWidth = 200;
  this.mFontSize = parseInt( pFontSize || 12 );
  this.mHeight = this.mFontSize + 4;
}

// set the prototype to the GOverlay class
LabelOverlay.prototype = new GOverlay( );

/**
 * Initialize the custom overlay
 *
 * @param pMap GMap2 - the map this overlay is on
 **/
LabelOverlay.prototype.initialize = function ( pMap ) {

  // create the div representing the label
  var div = document.createElement( 'div' );
  div.style.position = 'absolute';
  div.style.overflow = 'visible';
  div.style.textAlign = 'center';
  div.style.fontWeight = 'bold';
  div.style.whiteSpace = 'nowrap';
  div.style.width = this.mWidth + 'px';
  div.style.height = this.mHeight + 'px';

  pMap.getPane( G_MAP_MARKER_PANE ).appendChild( div );

  this.mMap = pMap;
  this.mDiv = div;
}

/**
 * Removes the overlay from the map.
 **/
LabelOverlay.prototype.remove = function ( ) {
  this.mDiv.parentNode.removeChild( this.mDiv );
}

/**
 * Copies the label to a new label
 **/
LabelOverlay.prototype.copy = function ( ) {
  return new LabelOverlay( this.mCenter, this.mLabel, this.mColor );
}

/**
 * Redraws the label.
 *
 * @param pForce boolean - whether or not to force redrawing
 **/
LabelOverlay.prototype.redraw = function ( pForce ) {

  // We only need to redraw if the coordinate system has changed
  if( !pForce ) {
    return;
  }

  this.mDiv.style.height = this.mHeight + 'px';

  // set the text and color
  this.mDiv.innerHTML = '<span style="font-size: ' + this.mFontSize + 'px; text-shadow: #273014 5px 5px 5px; filter: Shadow(Color=#273014, Direction=135, Strength=5);">' + this.mLabel + '</span>';
  this.mDiv.style.color = this.mColor;

  // recalculate the center of the label
  var c1 = this.mMap.fromLatLngToDivPixel( this.mCenter );

  // position the div based on the calculated center
  this.mDiv.style.left = ( c1.x - this.mWidth / 2 ) + 'px';
  this.mDiv.style.top = ( c1.y - this.mHeight / 2 ) + 'px';
}

/**
 * Makes this label draggable.
 **/
LabelOverlay.prototype.makeDraggable = function ( ) {

  // create a new draggable object for the div
  this.mDragObject = new GDraggableObject( this.mDiv );
  this.mDragObject.mParent = this;

  // listen for the dragstart and set the left/top  
  GEvent.addListener( this.mDragObject, 'dragstart', function ( ) {
    this.mParent.left = this.left;
    this.mParent.top = this.top;
  });

  // listen for the dragend and redraw the label
  GEvent.addListener( this.mDragObject, 'dragend', function ( ) {
    var newpixels = new GPoint( this.left + this.mParent.mWidth / 2, this.top + this.mParent.mHeight / 2 );
    this.mParent.mCenter = this.mParent.mMap.fromDivPixelToLatLng( newpixels );
    this.mParent.redraw( true );
    GEvent.trigger( this.mParent, 'dragend', this.mParent.mCenter );
  });

}

/**
 * Changes the text label.
 *
 * @param pLabel string - the new label
 **/
LabelOverlay.prototype.setLabel = function ( pLabel ) {
  this.mLabel = pLabel;
  this.redraw( true );
}

/**
 * Changes the color of the label.
 *
 * @param pColor string - the new color hex code (include the '#')
 **/
LabelOverlay.prototype.setColor = function ( pColor ) {
  this.mColor = pColor;
  this.redraw( true );
}

/**
 * Changes the color of the label.
 *
 * @param pColor string - the new color hex code (include the '#')
 **/
LabelOverlay.prototype.setFontSize = function ( pFontSize ) {
  this.mFontSize = parseInt( pFontSize );
  this.mHeight = this.mFontSize + 4;
  this.redraw( true );
}


/**
 * EuclideanProjection
 *
 * This class does transformation between latitude/longitude coordinates to a
 * flat x/y coordinate system.  It contains a set of discreet flat image height
 * and width values for each zoom level to determine the pixel locations of a
 * given coordinate.
 *
 *
 *
 * Creates a new EuclideanProjection with width and height values matching the
 * LOTRO game map image set.
 *
 * @param pMaxZoom int - the maximum zoom level
 **/
function EuclideanProjection ( a ) {

  // remember the max zoom
  this.maxZoom = a;

  // the list of zoom values we've calculated data for
  this.calculatedZooms = [];

  // arrays of overall map widths and heights for the LOTRO world map
  this.mapWidths = [548,1096,2192,4384,8768,17536,35072,70144];
  this.mapHeights = [276,552,1104,2208,4416,8832,17664,35328];

  // arrays containing the amount of shift from center of the visible image from
  // the possible full 256x256 landblock images
  // Each lower value is previous value / 2
  // e.g., -9600 / 2 = -4800
  this.mapShiftsX = [-75,-150,-300,-600,-1200,-2400,-4800,-9600];
  this.mapShiftsY = [-17,-33,-66,-131,-262,-524,-1047,-2093];

  // these are the sizes of the images at different zooms that would encompass
  // the entire 256 landblock grid
  this.mapExtents = [512,1024,2048,4096,8192,16384,32768,65536];

  // arrays containing the number of tiles in the x and y direction for each
  // zoom level as GPoint objects
  this.tileBounds = [];

  // array containing points that hold the x/y padding on the edge of the
  // visible image for each zoom level
  this.padding = [];

}

// Attach it to the GProjection() class
EuclideanProjection.prototype=new GProjection();

/**
 * Gets the tile bounds for a given zoom level.
 *
 * @param zoom int - the zoom level
 *
 * @return GPoint - a point with the x and y tile bounds
 **/
EuclideanProjection.prototype.getTileBounds = function(zoom) {
  // if it's not set for this zoom, calculate it
  if( !this.tileBounds[zoom] ) {
    var boundX = Math.ceil(this.getMapWidth(zoom)/256);
    var boundY = Math.ceil(this.getMapHeight(zoom)/256);
    this.tileBounds[zoom] = new GPoint( boundX, boundY );
  }
  return this.tileBounds[zoom];
};

/**
 * Gets the map padding for the given zoom level.
 *
 * @param zoom int - the zoom level
 *
 * @return GPoint - a point with the x and y padding
 **/
EuclideanProjection.prototype.getPadding = function(zoom) {
  // if it's not set for this zoom, calculate it
  if( !this.padding[zoom] ) {
    var padX = (Math.ceil(this.mapWidths[zoom] / 256)*256 - this.mapWidths[zoom]) / 2;
    var padY = (Math.ceil(this.mapHeights[zoom] / 256)*256 - this.mapHeights[zoom]) / 2;
    this.padding[zoom] = new GPoint( padX, padY );
  }
  return this.padding[zoom];
};

/**
 * Gets the map height for the given zoom level.
 *
 * @param zoom int - the zoom level
 *
 * @return int - the map height
 **/
EuclideanProjection.prototype.getMapHeight = function(zoom) {
  // if it's not set for this zoom, extrapolate it from the known values
  if( !this.mapHeights[zoom] ) {
    var mapHeightStep = ( this.mapHeights[this.maxZoom-1] - this.mapHeights[0] ) / ( this.maxZoom - 1 );
    var exHeight = this.mapHeights[this.maxZoom-1] + ( mapHeightStep * ( zoom - this.maxZoom ) );
    this.mapHeights[zoom] = exHeight;
  }
  return this.mapHeights[zoom];
};

/**
 * Gets the map width for the given zoom level.
 *
 * @param zoom int - the zoom level
 *
 * @return int - the map width
 **/
EuclideanProjection.prototype.getMapWidth = function(zoom) {
  // if it's not set for this zoom, extrapolate it from the known values
  if( !this.mapWidths[zoom] ) {
    var mapWidthStep = ( this.mapWidths[this.maxZoom-1] - this.mapWidths[0] ) / ( this.maxZoom - 1 );
    var exWidth = this.mapWidths[this.maxZoom-1] + ( mapWidthStep * ( zoom - this.maxZoom ) );
    this.mapWidths[zoom] = exWidth;
  }
  return this.mapWidths[zoom];
};

/**
 * Gets the map extent for the given zoom level.
 *
 * @param zoom int - the zoom level
 *
 * @return int - the map extent
 **/
EuclideanProjection.prototype.getMapExtent = function(zoom) {
  // if it's not set for this zoom, extrapolate it from the known values
  if( !this.mapExtents[zoom] ) {
    var maxExtentStep = ( this.mapExtents[this.maxZoom-1] - this.mapExtents[0] ) / ( this.maxZoom - 1 );
    var exExtent = this.mapExtents[this.maxZoom-1] + ( maxExtentStep * ( zoom - this.maxZoom ) );
    this.mapExtents[zoom] = exExtent;
  }
  return this.mapExtents[zoom];
};

/**
 * Gets the map padding for the given zoom level.
 *
 * @param zoom int - the zoom level
 *
 * @return int - the map padding
 **/
EuclideanProjection.prototype.getPadding = function(zoom) {
  // if it's not set for this zoom, extrapolate it from the known values
  if( !this.padding[zoom] ) {
    var padX = (Math.ceil(this.getMapWidth(zoom) / 256)*256 - this.getMapWidth(zoom)) / 2;
    var padY = (Math.ceil(this.getMapHeight(zoom) / 256)*256 - this.getMapHeight(zoom)) / 2;
    this.padding[zoom] = new GPoint( padX, padY );
  }
  return this.padding[zoom];
};

/**
 * Gets the map shift for the given zoom level.
 *
 * @param zoom int - the zoom level
 *
 * @return Point - the map shift
 **/
EuclideanProjection.prototype.getShift = function(zoom) {
  // if it's not set for this zoom, extrapolate it from the known values
  if( !this.mapShiftsX[zoom] || !this.mapShiftsY[zoom] ) {
    var shiftXStep = ( this.mapShiftsX[this.maxZoom-1] - this.mapShiftsX[0] ) / ( this.maxZoom - 1 );
    var shiftYStep = ( this.mapShiftsY[this.maxZoom-1] - this.mapShiftsY[0] ) / ( this.maxZoom - 1 );

    var exShiftX = this.mapShiftsX[this.maxZoom-1] + ( shiftXStep * ( zoom - this.maxZoom ) );
    var exShiftY = this.mapShiftsY[this.maxZoom-1] + ( shiftYStep * ( zoom - this.maxZoom ) );

    this.mapShiftsX[zoom] = exShiftX;
    this.mapShiftsY[zoom] = exShiftY;
  }
  return new GPoint( this.mapShiftsX[zoom], this.mapShiftsY[zoom] );
};

/**
 * Converts latitude/longitude coordinates to pixel x/y coordinates within the
 * given tileset.
 *
 * @param pCoord GLatLng - the latitude/longitude object
 * @param pZoom int - the zoom level to get the pixel coordinate for
 *
 * @return GPoint - a point with the pixel x and y coordinate
 **/
EuclideanProjection.prototype.fromLatLngToPixel=function(a,b){
  var c = Math.round(this.getMapExtent(b)/2 + a.lng()*this.getMapExtent(b)/360);
  var d = Math.round(this.getMapExtent(b)/2 + (-2 * a.lat()) * this.getMapExtent(b) / 360);
  c = c - (this.getMapExtent(b) - this.getMapWidth(b))/2;
  d = d - (this.getMapExtent(b) - this.getMapHeight(b))/2;

  c += this.getPadding(b).x;
  d += this.getPadding(b).y;

  c += this.getShift(b).x;
  d += this.getShift(b).y;

  return new GPoint(c,d);
};

/**
 * Converts a pixel x/y coordinate within a tileset to a latitude/longitude
 * value.
 *
 * @param pCoord GPoint - the x/y point to get lat/lng for
 * @param pZoom int - the zoom level
 * @param pUnbounded boolean - whether or not to wrap coordinates at the edge
 *   of the map (i.e. 181 degrees becomes -179 degrees)
 **/
EuclideanProjection.prototype.fromPixelToLatLng=function(a,b,c){
  a.x -= this.getShift(b).x;
  a.y -= this.getShift(b).y;

  a.x -= this.getPadding(b).x;
  a.y -= this.getPadding(b).y;

  a.x += (this.getMapExtent(b) - this.getMapWidth(b))/2;
  a.y += (this.getMapExtent(b) - this.getMapHeight(b))/2;

  var d = (a.x - this.getMapExtent(b)/2) * 360 / this.getMapExtent(b);
  var e = (a.y - this.getMapExtent(b)/2) * 360 / this.getMapExtent(b) / -2;
  return new GLatLng(e,d,c);
};

/**
 * Checks to see if a given tile coordinate is within the range of the map.
 * NOTE: The coordinate passed in is not a pixel coordinate.  Rather, it is
 * the coordinate of the tile itself.
 *
 * This is used by Google Maps to determine whether or not to display a tile.
 * If true is returned, the tile is displayed.  If false is returned, the tile is
 * not displayed.  This is used to control wrapping of the tile images.
 *
 * @param pCoord GPoint - the x/y tile coordinate to check
 * @param pZoom int - the zoom level to check
 * @param pTileSize int - the size of a tile
 *
 * @return boolean - true if the tile is in range, false otherwise
 **/
EuclideanProjection.prototype.tileCheckRange=function(a,b,c){
  if (a.y<0||a.y>=this.getTileBounds(b).y) {
    return false;
  }
  if(a.x<0||a.x>=this.getTileBounds(b).x){
    return false;
  }
  return true
}

/**
 * This function gets the pixel width of the map.  This is used to control
 * wrapping of markers on the map.
 *
 * @param pZoom int - the zoom level
 *
 * @return int - the wrap width of the map
 **/
EuclideanProjection.prototype.getWrapWidth=function(zoom) {
  return this.getTileBounds(zoom).x*256*8;
}

/** Terrain tile layer */
// Create a new tile layer with the Turbine copyright
var tilelayers1 = [new GTileLayer( new GCopyrightCollection( "" ), 0, 7 )];
tilelayers1[0].getCopyright = function ( a, b ) {
  return { prefix:"", copyrightTexts:[""] };
};

// override the getTileUrl function to return the proper tile image based on the
// coordinate
// a = tile coords
// b = zoom level
tilelayers1[0].getTileUrl = function ( a, b ) {
  var subDir = "";
  if(b == 7) { subDir = "-" + a.x.toString().charAt(0);}
  return GOOGLE_MAP_CONTENT_URL + "lotro/tiles/"+b+subDir+"/me_"+b+"_"+a.x+"x"+a.y+".png";
};

// override the isPng function to always return true (all of our tiles are pngs)
tilelayers1[0].isPng = function ( ) {
  return true;
};

/** Parchment tile layer */
// Create a new tile layer with the Turbine copyright
var tilelayers2 = [new GTileLayer( new GCopyrightCollection( "" ), 0, 7 )];
tilelayers2[0].getCopyright = function ( a, b ) {
  return { prefix:"", copyrightTexts:[""] };
};

// override the getTileUrl function to return the proper tile image based on the
// coordinate
tilelayers2[0].getTileUrl = function ( a, b ) {
  if(b == 7) { var subDir = "-" + a.x.toString().charAt(0); return GOOGLE_MAP_CONTENT_URL + "lotro/tiles/"+b+subDir+"/me_"+b+"_"+a.x+"x"+a.y+".png"; }
  return GOOGLE_MAP_CONTENT_URL + "lotro/tiles/parchment/"+b+"/me_"+b+"_"+a.x+"x"+a.y+".png";
};

// override the isPng function to always return true (all of our tiles are pngs)
tilelayers2[0].isPng = function ( ) {
  return true;
};

// create new GMapType(s) with the tile layer(s) and EuclideanProjection
var G_GAME_MAP = new GMapType( tilelayers1, new EuclideanProjection( 8 ), "Terrain", { errorMessage:"No Data Available", textColor:"white" } );
var G_PARCHMENT_MAP = new GMapType( tilelayers2, new EuclideanProjection( 8 ), "Parchment", { errorMessage:"No Data Available", textColor:"white" } );

// a generic function for canceling the propagation of the wheel event
function wheelevent(e) { 
  if (!e) e = window.event; 
  if (e.preventDefault) e.preventDefault(); 
  e.returnValue = false; 
}

// Setup the various marker icons
var GME_DEFAULT_ICON = G_DEFAULT_ICON;

var AUCTION_ICON = new GIcon(G_DEFAULT_ICON,"http://content.turbine.com/sites/google_map/lotro/pins/pin_auctionhouse.png");
AUCTION_ICON.iconSize = new GSize(32,39);
AUCTION_ICON.shadowSize = new GSize(0,0);

var BARD_ICON = new GIcon(G_DEFAULT_ICON,"http://content.turbine.com/sites/google_map/lotro/pins/pin_bard.png");
BARD_ICON.iconSize = new GSize(32,39);
BARD_ICON.shadowSize = new GSize(0,0);

var CRAFTTRAIN_ICON = new GIcon(G_DEFAULT_ICON,"http://content.turbine.com/sites/google_map/lotro/pins/pin_crafttrainer.png");
CRAFTTRAIN_ICON.iconSize = new GSize(32,39);
CRAFTTRAIN_ICON.shadowSize = new GSize(0,0);

var FORGE_ICON = new GIcon(G_DEFAULT_ICON,"http://content.turbine.com/sites/google_map/lotro/pins/pin_forge.png");
FORGE_ICON.iconSize = new GSize(32,39);
FORGE_ICON.shadowSize = new GSize(0,0);

var MONSTER_ICON = new GIcon(G_DEFAULT_ICON,"http://content.turbine.com/sites/google_map/lotro/pins/pin_monster.png");
MONSTER_ICON.iconSize = new GSize(32,39);
MONSTER_ICON.shadowSize = new GSize(0,0);

var OTHERNPC_ICON = new GIcon(G_DEFAULT_ICON,"http://content.turbine.com/sites/google_map/lotro/pins/pin_othernpc.png");
OTHERNPC_ICON.iconSize = new GSize(32,39);
OTHERNPC_ICON.shadowSize = new GSize(0,0);

var POI_ICON = new GIcon(G_DEFAULT_ICON,"http://content.turbine.com/sites/google_map/lotro/pins/pin_poi.png");
POI_ICON.iconSize = new GSize(32,39);
POI_ICON.shadowSize = new GSize(0,0);

var QUEST_ICON = new GIcon(G_DEFAULT_ICON,"http://content.turbine.com/sites/google_map/lotro/pins/pin_quest.png");
QUEST_ICON.iconSize = new GSize(32,39);
QUEST_ICON.shadowSize = new GSize(0,0);

var STABLE_ICON = new GIcon(G_DEFAULT_ICON,"http://content.turbine.com/sites/google_map/lotro/pins/pin_stable.png");
STABLE_ICON.iconSize = new GSize(32,39);
STABLE_ICON.shadowSize = new GSize(0,0);

var CLASSTRAIN_ICON = new GIcon(G_DEFAULT_ICON,"http://content.turbine.com/sites/google_map/lotro/pins/pin_trainer.png");
CLASSTRAIN_ICON.iconSize = new GSize(32,39);
CLASSTRAIN_ICON.shadowSize = new GSize(0,0);

var VAULT_ICON = new GIcon(G_DEFAULT_ICON,"http://content.turbine.com/sites/google_map/lotro/pins/pin_vault.png");
VAULT_ICON.iconSize = new GSize(32,39);
VAULT_ICON.shadowSize = new GSize(0,0);

var VENDOR_ICON = new GIcon(G_DEFAULT_ICON,"http://content.turbine.com/sites/google_map/lotro/pins/pin_vendor.png");
VENDOR_ICON.iconSize = new GSize(32,39);
VENDOR_ICON.shadowSize = new GSize(0,0);

var INTERACT_ICON = new GIcon(G_DEFAULT_ICON,"http://content.turbine.com/sites/google_map/lotro/pins/pin_interact.png");
INTERACT_ICON.iconSize = new GSize(32,39);
INTERACT_ICON.shadowSize = new GSize(0,0);

// Various map setup bits and bobs
var map;
var firstMap = null;
var markers = Array( );
var polygons = Array( );
var currentRow = null;

function infoWindowClosed ( ) {
  if(currentRow) {
    var row = document.getElementById(currentRow);
    row.className = row.className.replace( " rowOn", "" );
    currentRow = null;
  }
}

function highlightSearchRow (id) {
  if(currentRow) {
    var row = document.getElementById( currentRow );
    row.className = row.className.replace( " rowOn", "" );
    currentRow = null;
  }
  
  var row = document.getElementById( "row_" + id );
  if(row) {
    row.className += " rowOn";
    currentRow = "row_" + id;
  }
}

function highlightPolygon (id) {
  var polygon = polygons[id];
  if( polygon ) {
    map.setZoom(6);
    map.panTo(polygon.getVertex(0));
  }
}

function openMarker (id) {
  var marker = markers[id];
  if(marker) {
    if(marker.tabs) {
      marker.openInfoWindowTabsHtml(marker.tabs);
    } else if(marker.caption) {
      marker.openInfoWindowHtml(marker.caption);
    }
  }
  
  highlightSearchRow(id);
}

function createMarker (id, point, options) {
  var marker = new GMarker(point, options);
  marker.id = id;
  markers[id] = marker;
  GEvent.addListener(marker, "click",
    function( ) {
      marker.openInfoWindowHtml(marker.caption);
      highlightSearchRow(marker.id);
    }
  );
  
  return marker;
}

function addLoadEvent (func) {
  var oldonload = window.onload;
  if(typeof oldonload == "function") {
    window.onload = function( ) { oldonload( ); func( ); };
  } else {
    window.onload = func;
  }
}

window.unload = GUnload; 

