var map;
var rootCategoryIds = new Array();
var categoryIcons = new Hash();
var productMarkers = new Hash();
var categoryMarkerGroups = new Hash();
var popupHtml;
var categoryJson;
var productJson;

if (typeof zoom == 'undefined') {
	zoom = 4;
}
if (typeof centerLat == 'undefined') {
	centerLat = -27.804398;
}
if (typeof centerLong == 'undefined') {
	centerLong = 133.775136;
}

if (typeof minZoom == 'undefined') {
	minZoom = zoom;
}

// enforce minZoom
G_NORMAL_MAP.getMinimumResolution = function () { return minZoom };

//---------------------------------------
// Data loading and initialization
//---------------------------------------

function map_init() {

	if (GBrowserIsCompatible() && productDataKey && categoryDataKey) {
		
		map = new GMap2(document.getElementById("map_canvas"));
		map.addControl(new GLargeMapControl());
		map.setCenter(new GLatLng(centerLat, centerLong), zoom);
		map.enableScrollWheelZoom();
		GEvent.addListener(map, "click", mapClickListener);
		GEvent.addListener(map, "mousemove", fixMapControlTitle);		

		// load category data
		loadJs(getSpreadsheetUrl(categoryDataKey, "loadCategories"));

		// load popup template
		if (typeof popupUrl != 'undefined') {
		
			var popupRequest = GXmlHttp.create();
			popupRequest.open("GET", popupUrl, true);
			popupRequest.onreadystatechange = function() {

				if (popupRequest.readyState == 4) {

					popupHtml = popupRequest.responseText;

				}

			}
			popupRequest.send(null);

		}
	
	}

}

function getSpreadsheetUrl(key, callback) {

	return "http://spreadsheets.google.com/feeds/list/" + key 
		+ "/od6/public/values?alt=json-in-script&callback=" + callback;

}

function fixMapControlTitle() {

	var mapEl = document.getElementById("map_canvas");
	var divChildren = mapEl.getElementsByTagName("DIV");

	for (var i = 0; i < divChildren.length; i++) {

		if (divChildren[i].title == 'Return to the last result') {
			divChildren[i].title = 'Center Map on Goulburn';
		}
		
	} 
	
	GEvent.clearListeners(map, "mousemove");		

}

function loadCategories(categoryJson) {

	for (var i = 0; i < categoryJson.feed.entry.length; i++) {

		var iconObj = null;
		var image = categoryJson.feed.entry[i].gsx$iconimage.$t;
		var catid = categoryJson.feed.entry[i].gsx$id.$t;
		var parentid = categoryJson.feed.entry[i].gsx$parentid.$t;

		if (image != "" && catid != "") {

			var width = categoryJson.feed.entry[i].gsx$iconwidth.$t;
			var height = categoryJson.feed.entry[i].gsx$iconheight.$t;

			iconObj = new GIcon(G_DEFAULT_ICON);
			iconObj.image = image;

			if (width != "" && height != "") {

				iconObj.iconSize = new GSize(width, height);
				iconObj.shadowSize = new GSize(Math.floor(width*1.6), height);

			}

		}

		if (parentid != "") {

			var parent = categoryIcons.getItem(parentid);
	
			if (parent != null) {

				if (parent.children == null) {
					parent.children = new Array();
				}

				parent.children.push(catid);

			}

		} else {

			rootCategoryIds.push(catid);

		}

		categoryIcons.setItem(catid, {
			icon: iconObj,
			name: categoryJson.feed.entry[i].gsx$name.$t,
			parentid: parentid,
			viewtext: categoryJson.feed.entry[i].gsx$viewtext.$t,
			titletext: categoryJson.feed.entry[i].gsx$titletext.$t
		}); 

	}

	loadJs(getSpreadsheetUrl(productDataKey, "loadProducts"));


}

function loadProducts(productJson) {

	for (var i = 0; i < productJson.feed.entry.length; i++) {

		var point = getPoint(productJson.feed.entry[i]);	
		if (point != null) {
			var icon = getIcon(productJson.feed.entry[i]);
			var name = productJson.feed.entry[i].gsx$name.$t;
			var marker = new GMarker(point, { title: name , icon: icon });
			marker.json = productJson.feed.entry[i];
			addToCategories(marker);
			var id = productJson.feed.entry[i].gsx$id.$t;
			productMarkers.setItem(id, marker);
			// gmarkers.push(marker);
		}

	}

	drawMarkers();
	drawCheckboxes();

}

function addToCategories(marker) {

	var markerCategories = new Array();

	var subcategoriesField = marker.json.gsx$subcategories.$t;

	if (subcategoriesField.length > 0) {
		
		var subcategories = subcategoriesField.split(",");

		for (var i = 0; i < subcategories.length; i++) {

			var cleanCatId = subcategories[i].replace(/^\s+|\s+$/g, '');
			addMarkerToCategory(marker, cleanCatId);

			var catObj = categoryIcons.getItem(cleanCatId);
			while (catObj != null && catObj.parentid != "") {
			
				addMarkerToCategory(marker, catObj.parentid);
				catObj = categoryIcons.getItem(catObj.parentid);

			}

		}

	}

}

function addMarkerToCategory(marker, catid) {

	var markerArray;

	if (categoryMarkerGroups.hasItem(catid)) {

		markerArray = categoryMarkerGroups.getItem(catid);

	} else {

		markerArray = new Array();

	}

	markerArray.push(marker);
	categoryMarkerGroups.setItem(catid, markerArray);

}

function getPoint(jsonEntry) {

	var lat = parseFloat(jsonEntry.gsx$lat.$t);
	var lng = parseFloat(jsonEntry.gsx$lng.$t);

	if (lat == NaN || lng == NaN) {
		return null;
	} else {
		return new GLatLng(lat, lng);
	}

}

function getIcon(jsonEntry) {

	var subcategoriesField = jsonEntry.gsx$subcategories.$t;

	if (subcategoriesField.length > 0) {

        var subcategories = subcategoriesField.split(",");
		var catid = subcategories[0].replace(/^\s+|\s+$/g, '');

		var catObj = categoryIcons.getItem(catid);
		while (catObj != null && catObj.icon == null && catObj.parentid != "") {
			catObj = categoryIcons.getItem(catObj.parentid);
		}

		if (catObj != null && catObj.icon != null) {
			return catObj.icon;
		}

    }

	return null;

}

function drawMarkers() {

	map.clearOverlays();

	var markerArray;

	if (typeof activeSubcategories == 'undefined' || 
		(activeSubcategories.length > 0 && activeSubcategories[0] == 'all')) {

		markerArray = productMarkers.items;

	} else {

		markerArray = new Array();

		for (var i = 0; i < activeSubcategories.length; i++) {
			var aMarkerArray = categoryMarkerGroups.getItem(activeSubcategories[i]);
			if (typeof aMarkerArray != 'undefined') {
				markerArray = markerArray.concat(aMarkerArray);
			}
		}		

	}

	for (var i = 0; i < markerArray.length; i++) {
		try {
			map.addOverlay(markerArray[i]);

		} catch (e) {}
	}

	if (typeof urlHandled == 'undefined') {
		handleUrlSelect();
		urlHandled = true;
	}

}

function handleUrlSelect() {

	var markerId = getUrlParam("marker");

	if (markerId != '') {

		var marker = productMarkers.getItem(markerId);
		
		if (marker != null) {

			map.addOverlay(marker);
			GEvent.trigger(map, "click", marker);

		}

	}

}

//---------------------------------------
// Create and interact with category checkboxes
//---------------------------------------

function drawCheckboxes() {

	var outEl = document.getElementById("map_categories_block");
	GEvent.addDomListener(outEl, "click", updateCategories);

	var retStr = "";
	for (var i = 0; i < rootCategoryIds.length; i++) {

		var rootCatId = rootCategoryIds[i];
		var rootCat = categoryIcons.getItem(rootCatId);

		// open form
		var formId = 'map_categories_' + rootCatId;
		retStr = retStr + "<form name='" + formId + "' id='" + formId + "'>";

		// cat title?
		if (rootCat.titletext != "") {
			retStr = retStr + "<h3>" + rootCat.titletext + "</h3>";
		}

		// view all
		var isActive = getIsActiveCat(rootCatId);
		retStr = retStr + getCheckboxStr(isActive, "map_root_category", rootCatId, rootCat.viewtext, "map_root_category");

		// subcategories
		retStr = retStr + getChildCheckboxes(isActive, rootCatId);

		// close form
		retStr = retStr + "</form> <br class='map_categories_clear' id='map_categories_clear_" + (i + 1) + "' />";

	}

	outEl.innerHTML = outEl.innerHTML + retStr;

}

function getChildCheckboxes(isChecked, catId) {

	var retStr = "";
	var cat = categoryIcons.getItem(catId);

	if (cat && cat.children) {

		for (var i = 0; i < cat.children.length; i++) {
			var child = categoryIcons.getItem(cat.children[i]);
			if (!isChecked) {
				// checked if parent was checked or if this one is active
				isChecked = getIsActiveCat(cat.children[i]);
			}
			retStr = retStr + getCheckboxStr(isChecked, "map_category", cat.children[i], child.name);
			retStr = retStr + getChildCheckboxes(isChecked, cat.children[i]);
		}

	}

	return retStr;

}

function getCheckboxStr(isChecked, name, value, text, classStr) {

	var idStr = name + "_" + value;

	var retStr = "<div class='map_category_item'>";
	retStr = retStr + "<input type='checkbox' ";
	retStr = retStr + "id='" + idStr + "' ";	
	if (classStr) {
		retStr = retStr + "class='" + classStr + "' ";
	}
	
	if (isChecked) {
		retStr = retStr + "checked ";
	}
	
	retStr = retStr + "name='" + name + "' ";
	retStr = retStr + "value='" + value + "' >";
	retStr = retStr + "<label for='" + idStr + "'>" + text + "</label>";
	retStr = retStr + "</div>";

	return retStr;

}

function getIsActiveCat(catid) {

	var isActive = false;
	for (var i = 0; i < activeSubcategories.length; i++) {
		if (activeSubcategories == 'all' || activeSubcategories[i] == catid) {
			isActive = true;
			break;
		}
	}
	return isActive;
	
}

function updateCategories(event) {

	var eventEl = event.srcElement;
	if (!eventEl) {
		eventEl = event.target;
	}

	// Handle "view all" checkbox syncing
	if (eventEl.name == 'map_root_category') {

		var parentForm = getParentForm(eventEl);
		var subChecks = parentForm.map_category;

		if (eventEl.checked) {
			// all under that cat should be selected
			for (var i = 0; i < subChecks.length; i++) {
				subChecks[i].checked = true;
			}
		} else {
			// all under that cat should be deselected
			for (var i = 0; i < subChecks.length; i++) {
				subChecks[i].checked = false;
			}
		}

	} else if (eventEl.name == 'map_category') {

		if (!eventEl.checked) {
		
			var parentForm = getParentForm(eventEl);
			var rootCatCheckbox = parentForm.map_root_category;

			if (rootCatCheckbox.checked) {
				rootCatCheckbox.checked = false;
			}

		}

	} else {

		return;

	}

	activeSubcategories = new Array();

	// Add all checked cat ids to array
	for (var i = 0; i < rootCategoryIds.length; i++) {

		var formName = "map_categories_" + rootCategoryIds[i];
		var subChecks = document.forms[formName].map_category;
		var rootCheck = document.forms[formName].map_root_category;

		if (rootCheck.checked) {
			activeSubcategories.push(rootCheck.value);
		}

		for (var j = 0; j < subChecks.length; j++) {
			if (subChecks[j].checked) {
				activeSubcategories.push(subChecks[j].value);
			}
		}

	}
	
	drawMarkers();

}

function getParentForm(el) {

	var parentEl = el.parentNode;
	while (parentEl.tagName.toLowerCase() != "form") {
		parentEl = parentEl.parentNode;
	}
	var formName = parentEl.name;

	return document.forms[formName];

}


//---------------------------------------
// Create and manage popups
//---------------------------------------

function mapClickListener(overlay, point) {

	if (overlay) {

		if (overlay.json) {

			map.closeInfoWindow();
			overlay.openInfoWindowHtml(parseMasks(popupHtml, overlay), getPopupOpts());
	
		}

	}

}

function getPopupOpts() {

	var width = map.getSize().width;
	width = width * .8;
	
	return { maxWidth: width }
	
}		

function parseMasks(htmlStr, point) {

	var parsedStr = removeComments(htmlStr);
	parsedStr = parseMask(parsedStr, "Id", point.json.gsx$id.$t);
	parsedStr = parseMask(parsedStr, "Name", point.json.gsx$name.$t);
	parsedStr = parseMask(parsedStr, "Address", point.json.gsx$address.$t);
	parsedStr = parseMask(parsedStr, "Telephone", point.json.gsx$telephone.$t);
	parsedStr = parseMask(parsedStr, "Image", point.json.gsx$image.$t);
	parsedStr = parseMask(parsedStr, "MoreInfo", point.json.gsx$linktomoreinfo.$t);
	parsedStr = parsedStr.replace(/<ToHere>/g, getToDirLink(point));
	parsedStr = parsedStr.replace(/<FromHere>/g, getFromDirLink(point));
	return parsedStr;

}

function removeComments(htmlStr) {

	var commentRegexp = new RegExp("<!--(.|[\\n\\r])*-->", "gi");
	return htmlStr.replace(commentRegexp, '');

}

function parseMask(htmlStr, mask, value) {

	var parsedStr = htmlStr;
	var maskRegexp = new RegExp("<" + mask + ">", "gi");

	if (value != null && value != '') {

		// replace mask with value
		parsedStr = parsedStr.replace(maskRegexp, value);
	
		// find any "IfNoMask" blocks and remove them
		var ifNoBlockRegexp = new RegExp("<IfNo" + mask + ">(.|[\\n\\r])*</IfNo" + mask + ">", "gi");
		parsedStr = parsedStr.replace(ifNoBlockRegexp, '');

		// remove "<IfMask>" and "</IfMask>"
		var ifRegexp = new RegExp("</?If" + mask + ">", "gi");
		parsedStr = parsedStr.replace(ifRegexp, '');

	} else {

		// replace mask with blank
		parsedStr = parsedStr.replace(maskRegexp, '');

		// find any "IfMask" blocks and remove them
		var ifBlockRegexp = new RegExp("<If" + mask + ">(.|[\\n\\r])*</If" + mask + ">", "gi");
		parsedStr = parsedStr.replace(ifBlockRegexp, '');

		// remove "<IfNoMask>" and "</IfNoMask"
		var ifNoRegexp = new RegExp("</?IfNo" + mask + ">", "gi");
		parsedStr = parsedStr.replace(ifNoRegexp, '');

	}

	return parsedStr;

}

function getToDirLink(point) {

	return "http://maps.google.com/maps?q=to+" + point.getLatLng().lat() + "," + point.getLatLng().lng();

}

function getFromDirLink(point) {

	return "http://maps.google.com/maps?q=from+" + point.getLatLng().lat() + "," + point.getLatLng().lng();

}

//---------------------------------------
// Utility functions and classes
//---------------------------------------

function loadJs(src) {

	var docHead = document.getElementsByTagName('head').item(0);
	var newJS = document.createElement('script');
	newJS.setAttribute('language','javascript');
	newJS.setAttribute('type','text/javascript');
	newJS.setAttribute('src',src);
	docHead.appendChild(newJS);

}

function getUrlParam(name) {

	var query = window.location.search.substring(1);

	var vars = query.split("&");

	for (var i = 0; i < vars.length; i++) {
		var pair = vars[i].split("=");
		if(pair[0]==name) {
			return pair[1];
		}
	}

	return "";

}

function Hash() {

	this.length = 0;
	this.items = new Array();
	for (var i = 0; i < arguments.length; i += 2) {
		if (typeof(arguments[i + 1]) != 'undefined') {
			this.items[arguments[i]] = arguments[i + 1];
			this.length++;
		}
	}
   
	this.removeItem = function(in_key) {
		var tmp_value;
		if (typeof(this.items[in_key]) != 'undefined') {
			this.length--;
			var tmp_value = this.items[in_key];
			delete this.items[in_key];
		}
	   
		return tmp_value;
	}

	this.getItem = function(in_key) {
		return this.items[in_key];
	}

	this.setItem = function(in_key, in_value) {
		if (typeof(in_value) != 'undefined') {
			if (typeof(this.items[in_key]) == 'undefined') {
				this.length++;
			}

			this.items[in_key] = in_value;
		}
	   
		return in_value;
	}

	this.hasItem = function(in_key) {
		return typeof(this.items[in_key]) != 'undefined';
	}

}

//---------------------------------------
// Load the map
//---------------------------------------

GEvent.addDomListener(window, "load", map_init);
GEvent.addDomListener(window, "unload", GUnload);
