var baseUrl = detectBaseUrl();

function detectBaseUrl() {
	var href = location.href;
	var urls = ["http://newsgraphy.com", "http://localhost:8080/newsgraphy"];
	for (var i = 0; i < urls.length; i++) {
		if (href.indexOf(urls[i]) == 0) {
			return urls[i];
		}
	}
	return urls[0];
}

var map = null;
var datePicker = null;
var searchOverlay = null;
var labelOverlay = null;

var SPAN_DAY = "day";
var SPAN_WEEK = "week";
var SPAN_MONTH = "month";
var SPAN_YEAR = "year";

var currentSpan = null;
var currentDate = null;
var currentQuery = "";

var markers = [];
var markerOpeners = [null, null];

Ext.onReady(function() {
	initializeControls();
	initializePlane();
});

var release = function() {
	if (GUnload) {
		try {
			GUnload();
		} catch(e) {
		}
	}
};

var initializeGMap = function(span, date) {
	if (!GBrowserIsCompatible()) {
		return;
	}

	currentSpan = span;
	currentDate = date;

	var minZoom = 2;
	var maxZoom = 6;

	var normalLayer = new GTileLayer(new GCopyrightCollection(), minZoom, maxZoom);
	var featureLayer = new GTileLayer(new GCopyrightCollection(), minZoom, maxZoom);
	var dateLayer = new GTileLayer(new GCopyrightCollection(), minZoom, maxZoom);
	normalLayer.getTileUrl = tileNormalUrlResolver;
	featureLayer.getTileUrl = tileFeatureUrlResolver;
	dateLayer.getTileUrl = tileDateUrlResolver;

	var searchOverlayLayer = new GTileLayer(new GCopyrightCollection(), minZoom, maxZoom);
	searchOverlayLayer.getTileUrl = searchOverlayUrlResolver;
	searchOverlayLayer.isPng = function() { return true; }

	var labelOverlayLayer = new GTileLayer(new GCopyrightCollection(), minZoom, maxZoom);
	labelOverlayLayer.getTileUrl = labelOverlayUrlResolver;
	labelOverlayLayer.isPng = function() { return true; }

	var normalType = new GMapType([normalLayer], G_NORMAL_MAP.getProjection(), "分野");
	var featureType = new GMapType([featureLayer], G_NORMAL_MAP.getProjection(), "人・場所・組織");
	var dateType = new GMapType([dateLayer], G_NORMAL_MAP.getProjection(), "日付");

	map = new GMap2($("#map").get(0), {
		mapTypes : [normalType, featureType, dateType]
	});
	map.addControl(new GLargeMapControl());
	map.addControl(new GOverviewMapControl());
	map.addControl(new GMapTypeControl());

	map.disableDoubleClickZoom();
	map.enableContinuousZoom();
	map.enableScrollWheelZoom();
	map.setCenter(new GLatLng(0, 0), 3);

	searchOverlay = new GTileLayerOverlay(searchOverlayLayer);
	map.addOverlay(searchOverlay);

	labelOverlay = new GTileLayerOverlay(labelOverlayLayer);
	map.addOverlay(labelOverlay);

	GEvent.addListener(map, "click", function(overlay, point) {
		hitTest(point, "lookup", updateView);
	});
};

var hitTest = function(point, action, callback) {
	var zoom = map.getZoom();
	if (!isMapAvailable(getCurrentSpan(), zoom)) {
		return;
	}
	if (!point) {
		return;
	}
	var bounds = map.getBounds();
	var proj = G_NORMAL_MAP.getProjection();
	var p = proj.fromLatLngToPixel(point, zoom);
	var url = baseUrl + "/info/" + action;
	url += "?" + createCommonParams(zoom, p.x, p.y);
	$.getJSON(url, {}, function(json) {
		if (callback) {
			callback(json);
		}
	});
};

var initializePlane = function() {
	// var url = baseUrl + "/info/init?zoom=3";
	var url = baseUrl + "/info/init?zoom=3&span=year&date=20081231";
	$.getJSON(url, {}, function(json) {
		datePicker.setSelectedDates(stringToDate(json.today));
		initializeGMap(json.span, json.date);
		updateView(json);
	});
};

var tileNormalUrlResolver = function(p, zoom) {
	return mapUrlResolver(p, 1, zoom, false);
};

var tileFeatureUrlResolver = function(p, zoom) {
	return mapUrlResolver(p, 2, zoom, false);
};

var tileDateUrlResolver = function(p, zoom) {
	return mapUrlResolver(p, 3, zoom, false);
};

var searchOverlayUrlResolver = function(p, zoom) {
	return mapUrlResolver(p, 0, zoom, true);
};

var labelOverlayUrlResolver = function(p, zoom) {
	return mapUrlResolver(p, 0, zoom, false);
};

var mapUrlResolver = function(p, type, zoom, overlay) {
	var span = getCurrentSpan();
	if (!isMapAvailable(span, zoom)) {
		return baseUrl + "/images/unavailable.png";
	}

	var proj = G_NORMAL_MAP.getProjection();
	var worldPixels = proj.getWrapWidth(zoom);
	var tilePixels = 256;
	var mapWidth = 512 * Math.pow(2, zoom - 2);
	var mapHeight = mapWidth * 3 / 4;

	var mx = (worldPixels - mapWidth) / 2;
	var my = (worldPixels - mapHeight) / 2;
	var tx = p.x * tilePixels;
	var ty = p.y * tilePixels;

	if (overlay || (mx + mapWidth > tx && mx < tx + tilePixels && my + mapHeight > ty
			&& my < ty + tilePixels)) {
		var url = baseUrl + (overlay ? "/overlay" : "/tile");
		url += "?" + createCommonParams(zoom, p.x, p.y);
		if (overlay) {
			url += "&from=" + getCurrentFocusFromDate();
			url += "&to=" + getCurrentFocusToDate();
			// avoid GTileLayer image URL encoding problem
			url += "&query=" + encodeURIComponent(getCurrentQuery()).replace(/%/g, "_");
		} else {
			url += "&type=" + type;
		}
		return url;
	} else {
		if (p.x % 2 == 0 && p.y % 2 == 0) {
			// return baseUrl + "/images/ocean-text.gif";
			return baseUrl + "/images/ocean.gif";
		} else {
			return baseUrl + "/images/ocean.gif";
		}
	}
};

var refreshView = function() {
	var from = formatDate(stringToDate(getCurrentFocusFromDate()));
	var to = formatDate(stringToDate(getCurrentFocusToDate()));
	
	if (from == to) {
		$("#date-display").html(from);
	} else {
		$("#date-display").html(from + "<span class=\"normal\">から</span><br/>"
				+ to + "<span class=\"normal\">まで</span>");
	}

	map.setCenter(map.getCenter());
};

var refreshSpan = function(large) {
	refreshView();
	var url = baseUrl + "/info/lookup";
	url += "?span=" + getCurrentSpan();
	url += "&date=" + getCurrentDate();
	url += "&zoom=" + map.getZoom();
	url += "&from=" + getCurrentFocusFromDate();
	url += "&to=" + getCurrentFocusToDate();
	url += "&large=" + (large ? "1" : "0");
	$.getJSON(url, {}, function(json) {
		updateView(json);
	});
};

var updateView = function(result) {
	currentSpan = result.span;
	currentDate = result.date;

	datePicker.setMinDate(stringToDate(result.minDate));
	datePicker.setMaxDate(stringToDate(result.tomorrow));

	clearMarkers();

	if (result.marker) {
		var opener = placeMarker(result.zoom, result.marker);
		opener();
	}
	if (result.hits) {
		showMarkerInfo(0, result, "#span-result", null, "", false, "refreshSpan(true);", "refreshSpan(false);");
	}

	refreshView();
};

var placeMarker = function(zoom, info) {
	var proj = G_NORMAL_MAP.getProjection();
	var pixel = new GPoint(info.x, info.y);
	var latlng = proj.fromPixelToLatLng(pixel, zoom);

	var icon = new GIcon();
	icon.image = getMarkerUrl();
	icon.iconSize = new GSize(48, 48);
	icon.iconAnchor = new GPoint(24, 41);
	icon.infoWindowAnchor = new GPoint(24, 6);

	var marker = new GMarker(latlng, icon);
	var onclick = function() {
		addMarker(marker);
		var html = "";
		html += "<h2 class=\"marker\">";
		html += info.title;
		html += "</h2>";
		if (info.displayDate) {
			html += "<p>";
			html += info.displayDate;
			html += "</p>";
		}
		html += "<p>";
		html += "<b>PV指数:</b> " + info.pv;
		html += "</p>";
		if (info.url) {
			html += "<p>";
			html += "<a target=\"_blank\" href=\"" + info.url + "\">";
			html += "[Yahooo! トピックスを表示]";
			html += "</a>";
			html += "</p>";
		}
		if (info.allowZoomIn) {
			html += "<p>";
			html += "<a href=\"#\" onclick=\"zoomIn(); return false;\">";
			html += "[領域を拡大]";
			html += "</a>";
			html += "</p>";
		}
		marker.openInfoWindowHtml(html);
	};
	GEvent.addListener(marker, "click", onclick);
	return onclick;
};

var openTd = function(index) {
	return "<td class=\"" + (index % 2 == 0 ? "even" : "odd") + "\">";
};

var createCommonParams = function(zoom, x, y) {
	var p = "";
	p += "span=" + getCurrentSpan();
	p += "&date=" + getCurrentDate();
	p += "&zoom=" + zoom;
	p += "&x=" + x;
	p += "&y=" + y;
	return p;
};

var initializeControls = function() {
	Ext.QuickTips.init();

	datePicker = new Ext.ux.DatePickerPlus({
		renderTo: "date",
		noOfMonth: 1,
		multiSelection: true,
		useQuickTips: true,
		showToday: false,
		renderTodayButton: false,
		renderOkUndoButtons: false
	});
	datePicker.on("aftermonthclick", function() {
		highlight("#span-result-header");
		refreshSpan();
	});
	datePicker.on("afterweekclick", function() {
		highlight("#span-result-header");
		refreshSpan();
	});
	datePicker.on("afterdateclick", function() {
		highlight("#span-result-header");
		refreshSpan();
	});

	var viewport = new Ext.Viewport({
		layout: "border",
		items: [{
			contentEl: "north",
			region: "north",
			autoHeight: true,
			border: false,
			margins: "0 0 0 0"
		}, {
			contentEl: "south",
			region: "south",
			border: false,
			margins: "0 0 0 0"
		}, {
			contentEl: "west",
			region: "west",
			xtype: "panel",
			split: true,
			collapsible: true,
			border: false,
			margins: "0 0 0 0",
			cmargins: "0 0 0 0",
			width: 240,
			minSize: 240,
			maxSize: 240,
			autoScroll: true
		}, {
			contentEl: "center",
			region: "center",
			border: false,
			margins: "0 0 0 0"
		}]
	});

	viewport.doLayout();
};

var getCurrentSpan = function() {
	return currentSpan;
};

var getCurrentDate = function() {
	return currentDate;
};

var getCurrentFocusFromDate = function() {
	var d = [];
	$.each(datePicker.selectedDates, function(i, e) {
		d.push(dateToString(e));
	});
	d.sort();
	if (d.length == 0) {
		return null;
	}
	return d[0];
};

var getCurrentFocusToDate = function() {
	var d = [];
	$.each(datePicker.selectedDates, function(i, e) {
		d.push(dateToString(e));
	});
	d.sort();
	if (d.length == 0) {
		return null;
	}
	return d[d.length - 1];
};

var getCurrentQuery = function() {
	return currentQuery;
};

var isMapAvailable = function(span, zoom) {
	if (zoom < 2) {
		return false;
	}
	if (span == SPAN_DAY) {
		return zoom <= 4;
	} else if (span == SPAN_WEEK) {
		return zoom <= 5;
	} else {
		return zoom <= 7;
	}
};

var getMarkerUrl = function() {
	return baseUrl + "/images/markers/marker.png";
};

var stringToDate = function(s) {
	if (!s || s.length != 8) {
		return null;
	}
	var year = Number(s.substring(0, 4));
	var month = Number(s.substring(4, 6)) - 1;
	var day = Number(s.substring(6, 8));
	return new Date(year, month, day);
};

var dateToString = function(date) {
	if (!date) {
		return "";
	}
	var s = "";
	var y = date.getYear();
	s += y > 1900 ? y : (1900 + y);
	var m = date.getMonth() + 1;
	s += m < 10 ? ("0" + m) : m;
	var d = date.getDate();
	s += d < 10 ? ("0" + d) : d;
	return s;
};

var formatDate = function(date) {
	if (!date) {
		return "-";
	}
	var s = "";
	var y = date.getYear();
	s += y > 1900 ? y : (1900 + y);
	s += "年";
	var m = date.getMonth() + 1;
	s += m;
	s += "月";
	var d = date.getDate();
	s += d;
	s += "日";
	return s;
};

var highlight = function(elem) {
	$(elem).effect("highlight", { color: "#FFFF00" }, 700);
};

var search = function(large, keep, disableHighlight) {
	if (!keep) {
		currentQuery = $("#query").get(0).value;
	}

	var url = baseUrl + "/info/search";
	url += "?span=" + getCurrentSpan();
	url += "&date=" + getCurrentDate();
	url += "&zoom=" + map.getZoom();
	url += "&query=" + encodeURIComponent(getCurrentQuery());
	url += "&large=" + (large ? "1" : "0");

	$.getJSON(url, {}, function(json) {
		showMarkerInfo(1, json, "#search-result", disableHighlight ? "" : "#search-result-header",
				currentQuery.length == 0 ?
						"キーワードを入力してください" : "キーワードを含む記事が見つかりませんでした。キーワードを変更して再度検索してください",
				true, "searchLarge();", "searchSmall();");
	});

	refreshView();
};

var searchLarge = function() {
	search(true, true, true);
};

var searchSmall = function() {
	search();
};

var showMarkerInfo = function(index, info, htmlEl, headerEl, emptyMessage, move, largeScript, smallScript) {
	clearMarkers();
	var html = "";
	var hits = info.hits;
	if (hits.length > 0) {
		markerOpeners[index] = [];
		$.each(hits, function(i, e) {
			var opener = placeMarker(info.zoom, e);
			markerOpeners[index].push(opener);

			html += "<div class=\"" + (i % 2 == 0 ? "even" : "odd") + "\">";
			html += (i + 1) + "位 ";
			html += "<a href=\"#\" class=\"pointer\" onclick=\"openMarker(" + index + ", " + i + "); return false;\">";
			html += e.title;
			html += "</a>";
			html += "</div>";
		});
		if (info.hitsShrunk) {
			html += "<div class=\"more\">";
			html += "<a href=\"#\" onclick=\"" + largeScript + " return false;\">[もっと見る]</a>";
			html += "</div>";
		} else if (info.hitsLarge) {
			html += "<div class=\"more\">";
			html += "<a href=\"#\" onclick=\"" + smallScript + " return false;\">[元に戻す]</a>";
			html += "</div>";
		}
	} else {
		html += "<p class=\"tooltip\">" + emptyMessage + "</p>";
	}
	
	$(htmlEl).html(html);
	if (headerEl) {
		highlight(headerEl);
	}

	if (move && hits.length > 0) {
		openMarker(index, 0);
	}
};

var openMarker = function(typeIndex, markerIndex) {
	var openers = markerOpeners[typeIndex];
	if (openers && markerIndex >= 0 && markerIndex < openers.length) {
		openers[markerIndex]();
	}
};

var clearSearch = function() {
	$("#query").get(0).value = "";
	search();
};

var addMarker = function(marker) {
	var found = false;
	$.each(markers, function(i, e) {
		if (e == marker) {
			found = true;
		}
	});
	if (!found) {
		markers.push(marker);
	}
	map.addOverlay(marker);
};

var clearMarkers = function() {
	$.each(markers, function(i, e) {
		map.removeOverlay(e);
	});
	markers = [];
};

var zoomIn = function() {
	map.setZoom(map.getZoom() + 1);
	clearMarkers();
};

var showAnimation = function() {
	$("#center").html("<iframe src=\"swf/newsgraphy.html\" width=\"100%\" height=\"100%\" frameborder=\"0\"></iframe>");
	$("#west").html("<p style=\"margin: 8px;\">このアニメーション機能は、現在アルファ版です。正式版の公開まで、しばらくお待ちください。</p>");
	$("#extra").html("<a href=\"./\">[通常の地図に戻る]</a>");
};
