<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs title="Server-Stored Favorites" 
	description="Mapping Tourfilter Concerts"
	author="Your Name Goes Here"
	author_email="Your Email Goes Here"
	height="450">
	<Require feature="sharedmap" />
	<Require feature="dynamic-height" />
  <Require feature="setprefs" />  
</ModulePrefs>
<UserPref name="favorites" datatype="hidden" default_value="{}" />

<Content type="html">

<![CDATA[

<style type="text/css">
<!--

body {
	color:#000000;
	font-family:Sans-Serif;
	font-size:14px;
	font-weight:normal;
	line-height:1.35em;
}

body a {
	color:#333;
}

#header {
	background-color:#EE5555;
	color:#EAEAEA;
	padding:7px;
	margin:0 0 10px 0;
	font-size:1.5em;
	font-weight:bold;
}

#info {
	font-size:10px;
	padding-bottom: 5px;
}

#info a {
	color:#333
}

.date {
	background-color:#ccc;
	padding: 1px 0 1px 5px;
	margin:4px 0 4px 0;
	font-size:10px;
	font-weight:bold;
	text-transform:uppercase;
	color:#666666;
}

.listing a {
	color:#990000;
	margin-left:5px;
}

.venue {
	color:#999;
	margin-left:5px;
}

.status {
	color:#999;
	font-size: 10px;
}

a.star, a.nostar {
  display: block;
  width: 15px;
  height: 15px;
  float: left;
  background: url(http://sandbox.mikepurvis.com/maps/mapplets/stars.png) top left no-repeat;
}

a.star {
  background-position: top right;
}

-->
</style>

<div id="header">Tourfilter</div>

<p>
<select onchange="loadCity(this.options[this.selectedIndex].value);">
  <option value="">-- Select a City --</option>
  <option value="albuquerque">Albuquerque</option>
  <option value="asheville">Asheville</option>
  <option value="atlanta">Atlanta</option>
  <option value="austin">Austin</option>
  <option value="baltimore">Baltimore</option>
  <option value="boulder">Boulder</option>
  <option value="buffalo">Buffalo</option>
  <option value="boston">Boston</option>
  <option value="cincinnati">Cincinnati</option>
  <option value="cleveland">Cleveland</option>
  <option value="columbus">Columbus</option>
  <option value="chicago">Chicago</option>
  <option value="dallas">Dallas</option>
  <option value="denver">Denver</option>
  <option value="dublin">Dublin</option>
  <option value="dc">Washington DC</option>
  <option value="detroit">Detroit</option>
  <option value="elpaso">El Paso</option>
  <option value="fargo">Fargo</option>
  <option value="greensboro">Greensboro</option>
  <option value="houston">Houston</option>
  <option value="honolulu">Honolulu</option>
  <option value="indianapolis">Indianapolis</option>
  <option value="jacksonville">Jacksonville</option>
  <option value="kansas city">Kansas City</option>
  <option value="london">London</option>
  <option value="losangeles">Los Angeles</option>
  <option value="lasvegas">Las Vegas</option>
  <option value="louisville">Louisville</option>
  <option value="melbourne">Melbourne</option>
  <option value="madison">Madison</option>
  <option value="memphis">Memphis</option>
  <option value="miami">Miami</option>
  <option value="milwaukee">Milwaukee</option>
  <option value="nashville">Nashville</option>
  <option value="neworleans">New Orleans</option>
  <option value="newyork">New York</option>
  <option value="oklahomacity">Oklahoma City</option>
  <option value="omaha">Omaha</option>
  <option value="orlando">Orlando</option>
  <option value="phoenix">Phoenix</option>
  <option value="pittsburgh">Pittsburgh</option>
  <option value="philadelphia">Philadelphia</option>
  <option value="portland">Portland</option>
  <option value="providence">Providence</option>
  <option value="raleighdurham">Raleigh-Durham</option>
  <option value="rochester">Rochester</option>
  <option value="seattle">Seattle</option>
  <option value="stlouis">St. Louis</option>
  <option value="sanantonio">San Antonio</option>
  <option value="sandiego">San Diego</option>
  <option value="sf">San Francisco</option>
  <option value="toronto">Toronto</option>
  <option value="tucson">Tucson</option>
  <option value="tulsa">Tulsa</option>
  <option value="twincities">Twin Cities</option>
  <option value="vancouver">Vancouver</option>
  <option value="virginiabeach">Virginia Beach</option>
  <option value="wichita">Wichita</option>
</select>
<a href="#" onclick="loadFavorites();">show all starred</a>
</p>

<div id="info">Event Info by <a href="http://tourfilter.com" target='_blank'>tourftiler.com</a> and 
<a href="http://eventful.com" target='_blank'>Eventful.com</a></div>

<div class="status">Status: <span id="status">Nothing loaded yet. Select from the city list above.</span></div>

<p id="content"></p>

<script>

var map = new GMap2();

_IG_FetchContent("http://sandbox.mikepurvis.com/maps/mapplets/json2.js", function (script) {
  eval(script);
});

var prefs = new _IG_Prefs();
var favoritesText = prefs.getString("favorites");
var favorites = eval(favoritesText);

// List of cities being fetched.
var numFetches = 0;

var mode = 0;
var MODE_SINGLE_CITY = 1;
var MODE_FAVORITES_ONLY = 2;

// Temporary hack while the prefs engine is broken.
if (!favorites) {
  favorites = {}; //{"asheville":{"parliment funkadelic":["5/6"],"george clinton":["5/6"],"junior brown":["5/9"]},"atlanta":{"missy higgins":["5/6"],"mason jennings":["5/6"]}};
}

// array of all gigs on the map.
var gigs = [];
var bounds = null;

// gigs numbers keyed to dates, to interleave different cities.
var gigsByDate = {};

function handleFetchContent (response, city) {
	// make sure that we fetched valid XML data
	if (response == null || typeof(response) != "object" || response.firstChild == null) {
		_gel("status").innerHTML = "Failed to load valid XML data";
		return;
	}

	// parse the concert data from the response
	var concertData = response.getElementsByTagName("marker");

	for (var i = 0; i < concertData.length; i++) {
		var concert = concertData[i];

		var point = new GLatLng(concert.getAttribute("lat"), concert.getAttribute("lng"));
		var gig = {
		  'city': city,
		  'band': concert.getAttribute("band"),
		  'date': concert.getAttribute("date"),
		  'venue': concert.getAttribute("venue")
		};
		
		if (mode == MODE_FAVORITES_ONLY && !isFavorite(gig)) {
		  // If this is a non-favorite and we're in the favorites view, skip it.
		  continue;
		}
		
		// create a marker.
		bounds.extend(point);
		gig.marker = createMarker(point, gig);
		
		// add gig to the array.
		var gigIndex = gigs.push(gig) - 1;
		
		// add the id the pool representing this date.
		if (!gigsByDate[gig.date]) {
		  gigsByDate[gig.date] = [];
		}
		gigsByDate[gig.date].push(gigIndex);
	}
	
	// If this was the final request, move to the final processing.
	if (--numFetches < 1) {
	  allFetchesComplete();
	}
}

function allFetchesComplete() {
  var displayHtml = "";
  
  // Capture all the dates we have and sort them.
var sortedDates = [];
for (var date in gigsByDate) {
    sortedDates.push(date);
}
sortedDates.sort(dateComparator);

for (var dateIndex = 0; dateIndex < sortedDates.length; dateIndex++) {
    var date = sortedDates[dateIndex];
    displayHtml += "<div class='date'>" + date + "</div>";
  
    for (var gigDateIndex = 0; gigDateIndex < gigsByDate[date].length; gigDateIndex++) {
        var gigIndex = gigsByDate[date][gigDateIndex];
        var gig = gigs[gigIndex];
        
        map.addOverlay(gig.marker);
        
        var starText = isFavorite(gig) ? "star" : "nostar";
        displayHtml += "<div class='listing'>";
        displayHtml += " <a href='#' id='star-" + gigIndex + "' onclick='toggleFavorite(" + gigIndex + ")' class='" + starText + "'></a>";
        displayHtml += " <a href='#' onclick='clickMarker(" + gigIndex + ")'>" + gig.band + "</a>";
        displayHtml += " <span class='venue'>" + gig.venue + "</span>";
        displayHtml += "</div>";
    }
}
   
  _gel("status").innerHTML = "Done loading concert data...now rendering the map";


	// find the proper zoom level for the bounds
	// and center the map so that all of the markers are visible
	map.getBoundsZoomLevelAsync(bounds, function(level) {
		map.setCenter(bounds.getCenter());
		map.setZoom(level);
    
		// don't render the list until we've centered the map
		_gel("content").innerHTML = displayHtml;
		_gel("status").innerHTML = "Done loading concert data";
		
	  // resize the mapplet window height
	  _IG_AdjustIFrameHeight();  
	});
}


function loadCity(city) {
	// make sure a city has been selected
	if (city == "")
		return;

	// update the status field and clear out anything we have in 'content'
	_gel("status").innerHTML = "loading...";
	_gel("content").innerHTML = "";
	
  // Remove any old stuff
	cleanupMarkers();
	
	numFetches = 1;
  mode = MODE_SINGLE_CITY;
	var url = "http://sandbox.mikepurvis.com/maps/mapplets/cities/xml/" + city + ".xml"; 

	// fetch the XML data from the url
	_IG_FetchXmlContent(url, _IG_Callback(handleFetchContent, city));
	return false;
} 

function loadFavorites() {
	// update the status field and clear out anything we have in 'content'
	_gel("status").innerHTML = "loading...";
	_gel("content").innerHTML = "";
	
  // Remove any old stuff
	cleanupMarkers();
	
	numFetches = 0;
  mode = MODE_FAVORITES_ONLY;

  // To load all the favorites, we need to grab any cities that we have favorites in.
  for(city in favorites) {
    numFetches++;
  	var url = "http://sandbox.mikepurvis.com/maps/mapplets/cities/xml/" + city + ".xml"; 	
  	_IG_FetchXmlContent(url, _IG_Callback(handleFetchContent, city));    
  }
  return false;
}

function createMarker(point, gig) {

	// create link back to Tourfilter that will go in the info window
	var tourfilter_url = "http://tourfilter.com/" + gig.city + "/" + encodeURIComponent(gig.band);

	// create the marker and add the onclick event listener
	var marker = new GMarker(point, {title: gig.band + " - " + gig.venue});
	GEvent.addListener(marker, "click", function() {

		// band
		var html = "<div>";
		html += " <span style='font-size: 18px; color: #900'>" + gig.band + "</span> ";
		html += "</div>";

		// venue
		html += "<div>";
		html += " <span style='font-size: 14px; color: #888'>" + gig.date + " - </span>";
		html += " <span style='margin-top: 5px; font-size: 14px; color: #888'>" + gig.venue + "</span>";
		html += "</div>";
        
		// footer       
		html += "<div style='margin-top: 5px; font-size: 10px; color: #888'>";
		html += " <a style='color: #888;' href='" + tourfilter_url + "' target='_blank'> tourfilter.com</a>"
		html += "</div>";

		marker.openInfoWindowHtml(html, {disableGoogleLinks:true});
	});

	return marker;
}

// remove all marker Event Listeners and markers from the map
function cleanupMarkers() {
	for (var i = 0; i < gigs.length; i++) {
		var marker = gigs[i].marker;
		GEvent.clearListeners(marker, "click");
	}
	
	gigs = [];
	gigsByDate = {};
	bounds = new GLatLngBounds();
	
	if (map) {
		map.clearOverlays();
  }
}

function isFavorite(gig) {
  if (!favorites[gig.city] || !favorites[gig.city][gig.band]) {
    return false;
  } 
  
  return (arraySearch(favorites[gig.city][gig.band], gig.date) != -1);
}

function addFavorite(gig) {
  if (!favorites[gig.city]) {
    favorites[gig.city] = {};
  }
  
  if (!favorites[gig.city][gig.band]) {
    favorites[gig.city][gig.band] = [];
  }
  
  favorites[gig.city][gig.band].push(gig.date);
}

// Returns true when the item was found and removed. Otherwise false.
function removeFavorite(gig) {
  if (!favorites[gig.city] || !favorites[gig.city][gig.band]) {
    return false;
  } 
  
  var position = arraySearch(favorites[gig.city][gig.band], gig.date);
  
  if (position != -1) {
    favorites[gig.city][gig.band].splice(position, 1);
    
    if (favorites[gig.city][gig.band].length < 1) {
      delete favorites[gig.city][gig.band];
      var deleteCity = true;
      
      for (x in favorites[gig.city]) {
        deleteCity = false;
        break;
      }
       
      if (deleteCity) {
        delete favorites[gig.city];
      }
    }
    return true;
  } else {
    return false;
  }
}

function arraySearch(array, item) {
  // Linear scan is okay in this situation, since it's only ever a few dates per
  // band in a given city.
  for (i = 0; i < array.length; i++) {
    if (array[i] == item) {
      return i;
    }
  }
  return -1;
}

function toggleFavorite(index) {
  var gig = gigs[index];
  if (removeFavorite(gig)) {
    // Remove successful.
    _gel("star-" + index).className = "nostar";
  } else {
    // Remove failed. Instead add the favorite.
    addFavorite(gig);
    _gel("star-" + index).className = "star";
  }
  
  if (JSON) { 
    var jsonText = JSON.stringify(favorites);
    prefs.set("favorites", jsonText);
  }
}

// function called when we want to simulate a marker click
function clickMarker(index) {
	GEvent.trigger(gigs[index].marker, "click");
}

function dateComparator(a, b) {
  a_split = a.split("/");
  b_split = b.split("/");
  if (a_split[0] != b_split[0]) {
    // TODO: Insert a check here to compare 12 and 1 such that 1 > 12 for wrap-around date ranges.
    return a_split[0] - b_split[0];
  } else {
    return a_split[1] - b_split[1];
  }
}

</script>
]]>
  </Content>
</Module>


