

var mapview_periodic_period = 50;
 
	function get_image_url(iid, facility, prefix)
	{
		var ret;
		if (iid == null || iid == 0) { 
			ret =  "http://img.mogue.jp/img/sample/16.gif";
		} else {
			var mod = iid % 65536;
			var m1 = mod % 256;
			var m2 = Math.floor(mod / 256);
			var n1 = m1.toString(16);
			var n2 = m2.toString(16);

			n1 = (n1.length == 1) ? "0" + n1 : n1;
			n2 = (n2.length == 1) ? "0" + n2 : n2;

			var uri = "http://img.mogue.jp/img/u/" +
				n2 + "/" + n1 + "/" + facility + "/" + prefix + iid + ".jpg";

				ret =  uri;
		}
		return ret;
	}
//function declare_ChecklistNode()
//{
	YAHOO.widget.ChecklistNode = function(oData, oParent, expanded, checked) {
		var i = 0;
		if (oParent) { 
			this.init(oData, oParent, expanded);
			this.setUpLabel(oData);
			this.checked = checked;
		}
	};

	YAHOO.widget.ChecklistNode.prototype = new YAHOO.widget.TextNode();

	YAHOO.widget.ChecklistNode.prototype.checked = false;

	YAHOO.widget.ChecklistNode.prototype.setCheckState = function(state) { 
		this.checkState = state;
		this.checked = (state > 0);
	};

	/*
	YAHOO.widget.ChecklistNode.prototype.check = function() { 
		this.setCheckState(2);
		this.updateCheckHtml();
		this.updateParent();
	};
	*/

	function toggle_children(tree, index)
	{
		if (map)
			map.closeInfoWindow();
		YAHOO.widget.TreeView.getNode(tree,index).toggle();
	}

	// Overrides YAHOO.widget.TextNode
	YAHOO.widget.ChecklistNode.prototype.getNodeHtml = function() { 

		if (this.depth == 0) {
			var childnode_key = ( ( this.data.itemtype == "event" ) ? "events" : "locations" );

			
			var childnode_count = 0;
			if ( this.__related != null )
				childnode_count = (this.__related[childnode_key].keys()).length;
			

			var hashkey = this.__related.key;

			var checked_propname = "checked";

			var input = [ "input", {
							type: "checkbox",
							name: "cbid-" + this.labelElId,
							id:   "cbid-" + this.labelElId,
							onclick:
								"toggle_children('" + this.tree.id + "','" +   this.index + "')"
						} ];
			if ( this.tree.__checkbox_states[hashkey] )
				input[1].checked = "checked";

			str = createHtmlString(
				["div", {
					id: this.getToggleElId(),
					childNode: [
						input,
						[ "label", {
							"for":   "cbid-" + this.labelElId,
							"class": "l treenodeheader",
							childNode: [
								["text", this.__sortkey ]
							]
						} ],
						[ "span", {
							"class": "num",
							childNode: [
								[ "text", "(" + childnode_count + ")"]
							]
						} ]
					]
				}]
				
			);
		} else {
			// render tree's leaves.
			var imageurl;
			if (this.data.ref)
				imageurl = get_image_url(this.data.ref.iid, this.data.itemtype, "c");
			else
				imageurl = get_image_url(0, this.data.itemtype, "c");
				
			str = createHtmlString(
				["div", {
					id: this.getToggleElId(),
					"class": "treenodeleaf",
					childNode: [
						[ "a", {
							href:		"javascript:void(0);",
							onclick:	"mv.openinfo(" + this.data.uniqid + ");",
							title:		this.data.label,
							onmouseover:	"mv.over(" + this.data.uniqid + ");",
							onmouseout:		"mv.out (" + this.data.uniqid + ");",
							childNode: [
								["img", {
									src:	imageurl,
									width:	16,
									height:	16,
									alt:	this.data.label,
									"class":	"icon"
								} ],
								["text", this.data.label ]
							]
						} ],
						[ "span", {
							"class": "newwindow",
							childNode: [
								[ "a", {
									href:	"/" + this.data.itemtype + "/" + this.data.uniqid + "/",
									target:		"_blank",
									onmouseover:	"mv.over(" + this.data.uniqid + ");",
									onmouseout:		"mv.out (" + this.data.uniqid + ");",
									childNode: [
										[ "img", {
											src: "http://img.mogue.jp/img/icon/16/newwindow.gif",
											alt: "新しいウィンドウで開く",
											"class": "icon"
										} ]
									]
								} ]
							]
						} ]
					]
				}]
				
			);
		}
		return str;
	};


//} declare_ChecklistNode();

function declare_overlay_manipulater() {

	function overlay_manipulater(mv)
	{
		this.parent_mapview  = mv;
		this.visible_locations = [];
	}

	overlay_manipulater.prototype.marker_display = function (marker, b)
	{
		if (marker) {
			if (b) {
				map.addOverlay(marker);
			} else {
				map.removeOverlay(marker);
			}
		} else {
			//TRACE("marker is null");
		}
	};
/**
 * 
 * @param locations_all		object to store marker property. because toshow is temporally list.
 * @param toshow			Hash to be visible. 
 * @return
 **/
	overlay_manipulater.prototype.refresh_marker_visibility = function (locations_all, toshow)
	{
		var transition = {};

		// hidden current visible markers.
		this.visible_locations.each( function (i) {
			var k = i.key;
			var v = i.value;
			//this.marker_display(v.marker, false);
			transition[k] = -1;
		}.bind(this) );

		
		toshow.each ( function (i, j) {
			var k = i.key;
			var v = i.value;
				
			if ( transition[k] ) {
				transition[k] = 0;
			} else {
				transition[k] = 1;
			}
		} );

		var e = new each_periodic( mapview_periodic_period, $H(transition), function (v, k) {
			if ( v == 0)
				return;
			

			var pos = locations_all[k];
			if ( v == -1 ) {
				// hide.
				this.marker_display(pos.marker, false);
			} else {
				if ( pos.marker ) {
					this.marker_display(pos.marker, true);
				} else {
					var marker = this.create_marker_new(pos);
					pos.marker = marker;

					// store marker to make invisible next invokation.
					toshow[k].marker = marker;
					
					map.addOverlay(marker);
				}
			}
		}.bind(this) ); 

		this.visible_locations = toshow;
	}

	//create marker and set tooltip.
	overlay_manipulater.prototype.create_marker_new = function (item)
	{
		var text = item.name;
		var point = new GPoint(item.lon, item.lat);

		var opts = {
			icon: get_marker_icon(),
			title: item.name
		};

		var marker = new GMarker(point, opts) ;

		//marker.set_tooltip_text( text );
		
		GEvent.addListener(marker, "click", function () {
			try{
				this.openInfoWindow(marker, item);
			}catch(e){
				trace(e);
			}
		}.bind(this) );


		GEvent.addListener(marker, "mouseover", function () {
			marker.alter_marker();
			marker.show_tooltip(true);
		} );
		GEvent.addListener(marker, "mouseout", function () {
			marker.alter_marker();
			marker.show_tooltip(false);
		} );


		return marker;
	};

/**
 * format HTML of the openInfoWindowHtml().
 * @param
 * @return
 **/
	overlay_manipulater.prototype.openInfoWindow = function (marker, item)
	{
		var itemtype = mv.itemtype;
		var item_specific_description ;

		if (item.epoch) {
			var date = format_date_string(item.epoch, "ja");
			var time = format_time_string(item.epoch);
			var dl_children = [
						[ "dt", {
							"class": itemtype + " l",
							childNode: [
								[ "a", {
									href: "/" + itemtype + "/" + item.uniqid + "/",
									target: "_top",
									title: item.name,
									childNode: [
										[ "text", item.name]
									]
								} ],
								[ "a", {
									href: "/" + itemtype + "/" + item.uniqid + "/",
									target: "_blank",
									"class": "newwindow",
									title: item.name,
									childNode: [
										[ "img", {
											src: "http://img.mogue.jp/img/icon/16/newwindow.gif",
											"class": "icon",
											alt: "新しいウィンドウで開く"
										} ]
									]
								} ]
							]
						} ]
				];

			var content = [];
			if ( item.iid ) {
				content.push(
					[ "img", {
						"class": "pict",
						src:	get_image_url(item.iid, itemtype, "m")
					} ]
				);
			}

			if (itemtype == "event") {
				dl_children.push (
						[ "dd", {
							"class": "date",
							childNode: [
								[ "a", {
									href: "/" + itemtype + "/" + item.uniqid + "/ical.ics",
									childNode: [
										[ "img", {
											src: "http://img.mogue.jp/img/bg/icon/ical.gif",
											"class": "icon",
											alt: item.name + "のiCalendar"
										} ]
									]
								} ],
								[ "text", date + " " + time + " ~" ]
							]
						} ],
						[ "dd", {
							"class": "location",
							childNode: [
								[ "a", {
									href: "/location/" + item.locid + "/",
									target: "_top",
									title: item.locationname,
									childNode: [
										[ "text", item.locationname ]
									]
								} ]
							]
						} ]
				);
			} else if (itemtype == "location") {
				dl_children.push (
						[ "dd", {
							"class": "address",
							childNode: [
								[ "a", {
									href: "/" + itemtype + "/" + item.uniqid + "/vcard.vcf",
									title: item.name + "のvCrad",
									childNode: [
										[ "img", {
											src: "http://img.mogue.jp/img/bg/icon/vcard.gif",
											"class": "icon",
											alt: item.name + "のvCard"
										} ]
									]
								} ],
								[ "text", item.address ]
							]
						} ]
				);
			}

			content.push( [ "text", ( (item.description) ? item.description : "" )  + " " ] );
			
			dl_children.push(
					[ "dd", {
						"class": "text",
						childNode: content
					} ]
			);

/*
			if (itemtype == "event") {
				dl_children.push(
							[ "dd", {
								"class": "location",
								childNode: [
									[ "a", {
										href: "/location/" + item.locid + "/",
										target: "_top",
										title: item.locationname,
										childNode: [
											[ "text", item.locationname ]
										]
									} ]
								]
							} ]
				);
			}
*/
			item_specific_description = [ "dl", {
				"class": "marker",
				childNode: dl_children
			} ];

		}
		var info_elements = createHtmlString( item_specific_description );
/*		
		window.info_elements = info_elements;
		
		//marker.openInfoWindowHtml( info_elements[0].innerHTML );
		var parent_div = document.createElement('div');
		parent_div.appendChild(info_elements);
*/
		marker.openInfoWindowHtml( info_elements );
		window.t = info_elements;


	};
	
	window.overlay_manipulater = overlay_manipulater;
} declare_overlay_manipulater();

function mapview(panes, elm_busy)
{
	var use_intersect = false;
	var self = this;
		
	var markerlistid	= panes[0];
	var taglistid		= panes[1];
	var arealistid		= panes[2];
	var datelistid		= panes[3];

	this.pane_drawn = [];

	this.tree = $H();
	this.page = 1;

	this.active_pane = null;
	this.parsed = null;

	this.events	= $H();
	this.points	= $H();	// key is locid.
	this.tags	= $H();
	this.areas	= $H();
	this.dates	= $H();

	this.itemtype	= null;
	this.last_query_word	= null;
		
	function trigger_event(obj, name) { if (obj) GEvent.trigger(obj, name); return false; }
	this.over		= function (i) { return trigger_event(self.points[i].marker, "mouseover"); };
	this.out		= function (i) { return trigger_event(self.points[i].marker, "mouseout"); };
	this.openinfo	= function (i) { return trigger_event(self.points[i].marker, "click"); };

	this.om = new overlay_manipulater(this);

	this.zoom = function (i)
	{
	try{
		var item = self.points[i];
		var pc = new GLatLng(item.lat, item.lon);
		var maptype = map.getCurrentMapType();
		map.setCenter( pc );

		//this.om.marker_display(item.marker, true);
		GEvent.trigger(item.marker, "click");
	}catch(e) {
		TRACE(e);
	}
		return false;

	};
	this.focusmarker = function (i)
	{
		var item = self.points[i];
		var pc = new GPoint(item.lon, item.lat);
		map.panTo( pc );
	};
	
	this.toggle_pane = function (id)
	{
		var current_active = self.active_pane;

		for (var i = 0; i < panes.length ; i++ ) {
			var pane = panes[i];
			if ( pane == id ) {
				// already active. do nothing.
				if (current_active == i)
					continue;
					
				self.active_pane = i;

				Element.show( pane );
				
				Element.addClassName( "tab_" + pane, "active");
				if ( self.parsed != null ) {
					self.draw_pane_content(i);
				}
			} else {
				Element.removeClassName("tab_" + pane, "active");
				Element.hide( pane );
			}
		}
		
		if (map)
			map.closeInfoWindow();
		
		if (current_active != null) {
			Element.removeClassName("tab_" + panes[current_active], "active");
			Element.hide( $( panes[current_active] ) );

			self.update_map_marker_visiblility();
		}

	}

	function onException(req, e)
	{
		if (document.all) {
			trace(e.number + ": " + e.description);
		} else {
			TRACE(e);
		}
	}

/**
 * construct  tree nodes and leaves.
 * @param id			treeview container element id?
 * @param fullhash		all of loaded tag hash.
 *						each key of the hash is the tid of the tag.
 * @param partial_hash	hash of tags that is loaded by the latest request.
 * @param labelcallback	function that returns label text of the tree node.
 * @return
 **/
	function construct_tree(id, hash, hashsuffix, labelcallback)
	{
		var fullhash = self[hashsuffix];
		var partial_hash = hash[hashsuffix];
		
		var tree;
		if ( self.tree[id] ) {
			tree = self.tree[id];
		} else {
			tree = new YAHOO.widget.TreeView(id);
			self.tree[id] = tree;
			tree.__label_hash = [];
			tree.__checkbox_states = $H();

			self.add_onExpand_handler(tree, function (hashid) {
				var parent_hash = self.tags[hashid];
				//self.toggle_treenode(parent_hash, "tag");
			} );
		}

		var root = tree.getRoot();

		fullhash.each ( function (p, i) {
			var v = p.value;
			var key = p.key;
			var nodelabel = v.text;

			var label = labelcallback(key, v);

			var parent_node;

			var treenode = tree.__label_hash[label];
			if ( treenode && typeof (treenode) != 'function' ) {
				parent_node = tree.__label_hash[label];
				parent_node.childrenRendered = false;
			} else {
				var obj = {
					itemtype:	self.itemtype,
					uniqid:		v.uniqid,
					label:		label
				};
				if (v.uniqid)
					obj.ref = v[ self.itemtype + "s"][v.uniqid];

				parent_node = new YAHOO.widget.ChecklistNode(obj, root, false);

				parent_node.__related = v;
				parent_node.__sortkey = label;

				tree.__label_hash[label] = parent_node;
			}

			parent_node.setDynamicLoad(
				
				function (node, onCompleteCallback) {
					var it = ( (hashsuffix == "dates") ?
								node.__related.events : node.__related.locations );

					if (node.__children == null)
						node.__children = [];
					
					it.each(
						function (q, j) {
							var name = q.value.name;
							var subitem_key = q.key;

							if ( node.__children[subitem_key] != null )
								return;
							
							var obj = {
								itemtype:	self.itemtype,
								uniqid:		subitem_key,
								label:		name
							};
							if (subitem_key)
								obj.ref = v[ self.itemtype + "s"][subitem_key];

							var child = new YAHOO.widget.ChecklistNode(obj, node, false);

							node.__children[ subitem_key ] = true;
						}
					);
					onCompleteCallback();
				}
			);
		} );

		tree.__datasource = fullhash;

		return tree;
	}
/**
 *
 * @param tree					yahoo tree control.
 * @param sort_treeview_nodes	callback function defines sort order of the leaves.
 * @return
 **/
	function sort_treeview_nodes(tree, sort_callback_function)
	{
		//sort.
		var a = tree.getRoot().children;
		var b = a.sort( sort_callback_function);

		var prev = null;
		for (var i = 0; i < b.length; i++) {
			var n = b[i];

			n.previousSibling = prev;
			n.nextSibling = null;

			if (prev)
				prev.nextSibling = n;

			prev = n;
		}
		tree.getRoot().children = b;
	}

/**
 * 引数に与えられたハッシュのうち、すべてに共通して含まれているものを返します。
 * @return
 **/
	function intersect()
	{
		var common = $H();

		if (!arguments || arguments.length == 0)
			return null;

		if (arguments.length == 1)
			return arguments[0];
		
		var testvalue = arguments.length;
		for (var i = 0; i < arguments.length; i++) {
			var a = arguments[i];
			if ( ( a.keys()).length == 0)
				testvalue--;

			a.each ( function (j, k) {
				common[j.key] = (common[j.key]) ? common[j.key] + 1 : 1;
			} );

		}
		var ids = common.findAll ( function (j, k) {
			return (j.value == testvalue);	
		});

		var points = ids.collect( function (j, k) {
			return self.points[ j.key ];
		} );
		return $H(points);
	}

	this.add_onExpand_handler = function (tree, handler)
	{
		self.is_cond_and = false;
		function on_change_node_state(node, b)
		{
			//var cond = self.is_cond_and;
			try{
				node.tree.__checkbox_states[ node.__related.key ] = b;
					
				if (use_intersect) {
					var c1 = self.get_checked_node_points( self.tree[ taglistid  ] );
					var c2 = self.get_checked_node_points( self.tree[ arealistid ] );
					var c3 = self.get_checked_node_points( self.tree[ datelistid ] );
					var checked = intersect(c1, c2, c3);
				} else {
					var checked = self.get_checked_node_points();
				}

				self.recenter_and_zoom_to_points( checked );
				self.om.refresh_marker_visibility(self.points, checked);
			} catch(e) {
				TRACE(e);
			}
			
		}

		tree.onCollapse = function(node) {
			on_change_node_state(node, false);
		};
		//var current_expanded_node = null;
		// add event handlers to the tree nodes and leaves.
		tree.onExpand = function(node) {
			on_change_node_state(node, true);
		};
	}

	function refresh_datetree(id, hash, hashsuffix)
	{
		var tree = refresh_tree(id, hash, hashsuffix, function (j, k) {
			return j;
		} );

		return tree;
	}



	function refresh_tree(id, hash, hashsuffix, fn)
	{
		var labelcallback = fn;
		if (labelcallback == null) {
			labelcallback = function (k, v) { return v.text; }
		}
		var tree = construct_tree(id, hash, hashsuffix, labelcallback);
		
		var g = -1;
		var l = 1;
		if (hashsuffix == "dates") {
			g = 1;
			l = -1;
		}
		sort_treeview_nodes(tree,
			function (a, b) {
				if (a.__sortkey == b.__sortkey) return 0;
				if (a.__sortkey < b.__sortkey) return g;
				if (a.__sortkey > b.__sortkey) return l;
			}
		);
		tree.draw();

		return tree;
	}

	
/**
 * renders most left pane.
 * @param
 * @return
 **/
	this.update_pointlist = function (newpoints)
	{
		var list = $(markerlistid);
		var html = "";

		var e = new each_periodic( mapview_periodic_period, newpoints, function (it) {
			var item = it;

			var elements = createElement(
				[ "li", {
					childNode: [
						[ "span", {
							childNode: [
								[ "a", {
									href:			"javascript:void(0);",
									className:		"treenode",
									onclick:		function() { return self.zoom(item.uniqid); },
									onmouseover:	function() { return self.over(item.uniqid); },
									onmouseout:		function() { return self.out (item.uniqid); },
									childNode: [
										["img", {
											src:	get_image_url(item.iid, self.itemtype, "c"),
											alt:	item.name,
											width: 16,
											height: 16,
											className:	"icon"
										} ],
										["text", item.name ]
									]
								} ]
							]
						} ],
						[ "span", {
							className: "newwindow",
							childNode: [
								[ "a", {
									href:			"/" + self.itemtype + "/" + item.uniqid + "/", 
									target:			"_blank",
									onmouseover:	function() { return self.over(item.uniqid); },
									onmouseout:		function() { return self.out (item.uniqid); },
									childNode: [
										[ "img", {
											src: "http://img.mogue.jp/img/icon/16/newwindow.gif",
											alt: "新しいウィンドウで開く",
											className: "icon"
										} ]
									]
								} ]
							]
						} ]
					]
				} ]
			);

			list.appendChild(elements);
		} );

	};



	this.recenter_and_zoom_to_points = function (points)
	{
		var bounds = get_spanning_bounds(points);

		if ( bounds == null ) {
			return false;
		}
		
		var lng = (bounds.getSouthWest().x + bounds.getNorthEast().x) / 2 ;
		var lat = (bounds.getSouthWest().y + bounds.getNorthEast().y) / 2 ;


		if (map == null) {
			gmap_init(lat, lng, -2, points);
		}

		{
			var map_center = new GLatLng(lat, lng);
			
			var zoomlevel = map.getBoundsZoomLevel(bounds);
			zoomlevel -= 1; //make root for footer.
			
			// must update lat/lon before changing map zoom.
			// because on changing zoom, 'zom' event handler is invoked and 
			// recenter map to lat/lon. call setCenter() without updating,
			// event handler centers to previous lat/lon.
			window.lat = lat;
			window.lon = lng;

			if (map.getZoom() == zoomlevel)
				map.panTo(map_center);
			else
				map.setCenter(map_center, zoomlevel);
			//map.saveMapState();
			//map.setCenter(map_center, zoomlevel);
		}

		return true;
	}

	this.toggle_datelist = function (hashid)
	{
		map.closeInfoWindow();
		self.recenter_and_zoom_to_points( parent_hash.locations );
		//map.saveMapState();

		self.points.each( function (k, i) {
			var key = k.key;
			var value = k.value;

			// point belongs expanded node?
			if ( parent_hash.locations[ value.locid ] ) {
				self.marker_display(self.points[key].marker, true);
			} else {
				self.marker_display(self.points[key].marker, false);
			}
			
		} );

	};


	this.show_all_markers = function (b)
	{
		for (var i = 0; i < self.points.length; i++) {
			self.points[i].marker.display(b);
		}
	}

// http://mogue.jp/api/search?_search&q=%8C%F6%89%80&t=location

	var search_results = {};
	this.sr = search_results;
	var search_type;
	this.show_search_result = function (query_word, page)
	{
		if ( search_results[query_word] == null || search_results[query_word][page] == null) {
			self.load_search_result (search_type, query_word);
			return;
		}
		//self.show_all_markers(false);
		//self.points = {};
		//self.tags = {};

		//self.parse_response(query_word, page, search_results[query_word][page]);
	};

/**
 * merge resplonse into self.points and returns newly arrived points.
 * @param
 * @return	{points: newpoints, tags: newtags, dates: newdates, events: newevents};
 **/
	this.parse_response = function (res)
	{

		var newpoints = $H();
		var newtags = $H();
		var newareas = $H();
		var newdates = $H();
		var newevents = $H();

		for (var i = 0; res.item && i < res.item.length; i++) {
			var item = res.item[i];

			window.item = item;
			//重複チェックしつつpointsに追加
			var points_key = item.uniqid;
			if ( self.points[points_key] != null ) {
				// do nothing.
				continue;
			}

			// 場所の情報がなかったら捨てる。
			if ( item.lat == "" || item.lon == "" )
				continue;

			self.points[points_key] = item;
			self.points[points_key].tid = item.tid;
				
			newpoints[points_key] = item;
			newpoints[points_key].tid = item.tid;
			
			var locations_key = item.uniqid;

			// parse and construct tag tree hash.
			function anony_tree_node_construct(ar, fullhash, added_new)
			{
				// parsing api/search format xml.
				// this block designed for api/search result.

				for (var n = 0; n < ar.length; n++) {
					var attr = ar[n];
					var key = attr.attrid;

					if ( ! fullhash[key] ) {
						fullhash[key] = $H();
						fullhash[key].locations = $H();
						fullhash[key].events = $H();
					}
					fullhash[key].key = key;
					fullhash[key].text = attr.attrname;
					fullhash[key].locations[points_key] = item;
					if (self.itemtype == 'event')
						fullhash[key].events[points_key] = item;
					
					if ( ! added_new[key] ) {
						added_new[key] = $H();
						added_new[key].locations = $H();
						added_new[key].events = $H();
					}
					added_new[key].key = key;
					added_new[key].text = attr.attrname;
					added_new[key].locations[points_key] = item;
					if (self.itemtype == 'event')
						added_new[key].events[points_key] = item;
				}
				return added_new;
			}
			
			//var added_new = newtags;
			var root = self.tags;
			if ( item.tags ) {
				var tags = anony_tree_node_construct(item.tags, self.tags, newtags);
			}
			if ( item.areas ) {
				var areas = anony_tree_node_construct(item.areas, self.areas, newareas);
			}

			// parse and construct itemtype specific trees.
			if (self.itemtype == 'event') {
				var t = localtime(item.epoch);
				var date = format_date_string(t);

				var key = item.uniqid;

				if ( ! newdates[date] ) {
					newdates[date] = {};
					newdates[date].locations = $H();
					newdates[date].events = $H();
				}

				
				newdates[date].key = date;
				newdates[date].day = t.getDay();
				newdates[date].locations[ item.locid ] = item;
				newdates[date].events[ item.uniqid ] = item;

				if ( ! self.dates[date] ) {
					self.dates[date] = {};
					self.dates[date].locations = $H();
					self.dates[date].events = $H();
				}
				self.dates[date].key = date;
				self.dates[date].day = t.getDay();
				self.dates[date].locations[ item.locid ] = item;
				self.dates[date].events[ item.uniqid ] = item;
				
				if ( ! self.events[item.uniqid] ) {
					self.events[ item.uniqid ] = {};
				}

				self.events[ item.uniqid ] = item;

				newevents[ item.uniqid ] = item;
			}

		}

		return {points: newpoints, tags: newtags, dates: newdates, events: newevents, areas: newareas};
	};

	this.refresh_search_result_navigation = function(pages, page, query_word)
	{
		var nav = $('search_result_navigation');

		var search_result_navigation_param = [
		];
 		
		for (var i = page; i <= pages; i++) {
			var elements = createElement(
				[ "span", {
					childNode: [
						[ "a", {
							target:			"_top",
							href:		function () { void(i); },
							onclick:	function () { mv.show_search_result(query_word, i); },
							style:	{
								padding: "4px"
							},
							childNode: [
								["text", i]
							]
						} ]
					]
				} ]
			);
			//var elements = search_result_navigation_param.collect( createElement );

			nav.appendChild( elements );
		}
	};

	this.current_shown_tree = function ()
	{
		var paneid = panes[ self.active_pane ];
		return  self.tree[ paneid ];
	}
	
	this.get_checked_node_points = function (tree, is_cond_and)
	{
		try{

			if (tree == null) {
				tree = self.current_shown_tree();
				if (tree == null) {
					TRACE("tree is null.");
					return;
				}
			}
			
			var hash = $H();
			if (is_cond_and) {
			} else {
				var points = $H();

				window.treex = tree;
				tree.__checkbox_states.each (
					function (i, j) {
						var k = i.key;
						var v = i.value;
						if (v == false)
							return;

						if ( i.key == 0)
							return;
						
						var t = tree.__datasource[ k ];
						t.locations.each ( 
							function (n, m) {
								points[ n.value.uniqid ] = (n.value);
							}
						);

					}
				);
				hash = points;
			}
		} catch(e) {
			TRACE(e);
		}
		return hash;
	}

	this.invalidate_panes = function ()
	{
		self.pane_drawn = [];
	}

	this.draw_pane_content = function (pane_index)
	{
		if ( self.pane_drawn[pane_index] )
			return;
		
		if (self.parsed == null)
			return;

		if ( pane_index == 0 ) {
			self.update_pointlist(self.parsed.points);
		} else if ( pane_index == 1 ) {
			refresh_tree(taglistid, self.parsed, "tags");
		} else if ( pane_index == 2 ) {
			refresh_tree(arealistid, self.parsed, "areas");
		} else if ( pane_index == 3 ) {
			if ( self.itemtype == 'event' ) {
				refresh_datetree( datelistid, self.parsed, "dates");
			}
		}
		self.pane_drawn[ pane_index ] = true;
	}

	this.last_called_load_method = null;
	this.last_called_load_arguments = null;

	this.load_next = function ()
	{
		self.page++;

		var args = self.last_called_load_arguments;
		self.last_called_load_method.apply( self, args );
	};

	// load fav marked items.
	// lat, lon, and name and description?
	// see api/listfav for more details.
	this.fav_loaded = false;
	this.loaded_pages = [];

	function load_api_common(request_url, cmd, itemtype, params)
	{
		if (self.loaded_pages[ self.page ] )
			return;

		function onComplete(req)
		{
			var res;

			if (params.output != 'json' ) {
				var dom = req.responseXML.documentElement;
				res = xml2js(dom);
			} else {
				res = eval(req.responseText);
			}

			var parsed = self.parse_response(res);
			self.parsed = parsed;
			self.hitcount = res.hitcount;

			{
				window.res = res;
				self.invalidate_panes();
				self.draw_pane_content( self.active_pane );
				
				self.update_map_marker_visiblility( parsed.newpoints );

				self.loaded_pages[ self.page ] = true;

				self.update_navigation_html(res);

				Element.removeClassName($(elm_busy), 'busy');
			}
		}

		self.itemtype = itemtype;

		var pars = cmd + "=cmd" + "&" + ( $H( params ) .collect( function (a, b) {
									return a.key + "=" + encodeURIComponent(a.value)
								}) ) . join("&");

		Element.addClassName($(elm_busy), 'busy');
		var aj = new Ajax.Request( request_url, {
										method: 'post',
										parameters: pars,
										onComplete: onComplete,
										onException: onException
									} );
	}

	this.load_fav = function (entity_type, uniqid, itemtype)
	{
		var params = {
				uniqid:		uniqid,
				ownertype:	entity_type,
				type:		itemtype,
				page:		self.page,
				output:		'json',
				rand:		Math.floor(Math.random() * 65536)
		};
		load_api_common('/api/listfav', "_recents", itemtype, params);
		self.last_called_load_method = self.load_fav;
		//self.last_called_load_arguments = arguments;
		var args = new Array;
		for (var i = 0; i < arguments.length; i++) { args[i] = ( arguments[i] ); }
		self.last_called_load_arguments = args;
	};

	this.load_tag = function (uniqid, itemtype)
	{
		var params = {
				uniqid:		uniqid,
				type:		itemtype,
				page:		self.page,
				rand:		Math.floor(Math.random() * 65536)
		};
		load_api_common('/api/listtag', "_recents", itemtype, params);
		self.last_called_load_method = self.load_tag;
		var args = new Array;
		for (var i = 0; i < arguments.length; i++) { args[i] = ( arguments[i] ); }
		self.last_called_load_arguments = args;
	};
	this.load_near = function (locid, lat, lon, extent, itemtype)
	{
		var params = {
			locid:		locid,
			type:		itemtype,
			page:		self.page,
			rand:		Math.floor(Math.random() * 65536)
		};
		load_api_common('/api/findnear', "_find", itemtype, params);
		self.last_called_load_method = self.load_near;
		var args = new Array;
		for (var i = 0; i < arguments.length; i++) { args[i] = ( arguments[i] ); }
		self.last_called_load_arguments = args;
	};

	this.load_rect = function (x1, y1, x2, y2, itemtype, aid)
	{
		var params = {
		//	lat:		lat,
		//	lon:		lon,
			x1:		x1,
			y1:		y1,
			x2:		x2,
			y2:		y2,
			type:		itemtype,
			page:		self.page,
			rand:		Math.floor(Math.random() * 65536)
		};
		if (aid != null)
			params.aid = aid;

		load_api_common('/api/findnear', "_find", itemtype, params);
		self.last_called_load_method = self.load_rect;
		var args = new Array;
		for (var i = 0; i < arguments.length; i++) { args[i] = ( arguments[i] ); }
		self.last_called_load_arguments = args;
	};

	this.update_map_marker_visiblility = function (newpoints) 
	{
		var checked;

		if ( self.active_pane == 0)
			checked = $H( self.points );
		else
			checked = self.get_checked_node_points();
		
		self.recenter_and_zoom_to_points( checked );
		self.om.refresh_marker_visibility(self.points, checked);
	}

	/**
	 * stop loading icon and show/hide navigation html.
	 * @param
	 * @return
	 **/
	this.update_navigation_html = function(res)
	{
		// update html.
		if ( (res.page) < (res.pages) ) {
			Element.show('next_result');
		} else {
			Element.hide('next_result');
		}


		if (res.hitcount == 0) {
			Element.hide("search_result_position_nav");
			Element.show("search_result_not_found");
		} else {
			Element.show("search_result_position_nav");
			Element.hide("search_result_not_found");
			$("search_result_hitcount").innerHTML = res.hitcount;
		}
		Element.show( "search_result" );
		
		//$('page_total').innerHTML = res.pages;
		//$('page_current').innerHTML = res.page;
		var count = res.page * res.ipp;

		var next_available = (count < res.hitcount);
		if ( ! next_available) {
			Element.hide( 'next_result' );
			count = res.hitcount;
		}
			
		$('shown_count').innerHTML = count;
		
		var next_count = res.ipp;
		if ( count + res.ipp  > res.hitcount )
			next_count = res.hitcount - count;
		$('next_result_ipp').innerHTML = next_count;

		Element.removeClassName($(elm_busy), 'busy');
	}

	this.load_search_result = function (itemtype, query_word, selected_area)
	{
		var params = {
				query:		query_word,
				type:		itemtype,
				page:		self.page,
				withtag:	1,
				witharea:	1,
				withimage:	1,
				output:		'json',
				rand:		Math.floor(Math.random() * 65536)
		};
		if (selected_area != null)
			params.aid = selected_area;

		load_api_common('/api/search', "_search", itemtype, params);
		self.last_called_load_method = self.load_search_result;
		//self.last_called_load_arguments = arguments;
		var args = new Array;
		for (var i = 0; i < arguments.length; i++) { args[i] = ( arguments[i] ); }
		self.last_called_load_arguments = args;

	};

}
