dojo.require("dojo.cookie");
dojo.require("dojo.fx");
dojo.require("dojo.html");

var LG = LG || {};
LG.openNode = null;
LG.selectNode = function(link, childUlId, lat, lon, zoomLevel){
  if(LG.openNode){
    LG.openNode.link.innerHTML = "+";
    if(LG.openNode.childUlId != childUlId)
      Effect.toggle(LG.openNode, 'appear', { duration: 0.1 });
  }

  Effect.toggle(childUlId, 'appear', { duration: 0.3 });

  if(LG.openNode && LG.openNode.childUlId != childUlId){
    link.innerHTML = "-";
    LG.openNode = {childUlId:childUlId, link:link};
  }else
    LG.openNode = null;

  //globalJsMap needs to be resized and re-pointed
  var center = new GLatLng(lat, lon);
  window.setTimeout(function(){
		      globalJsMap.panTo(center);
		      globalJsMap.setZoom(zoomLevel);
		    }, 10);

  globalJsMap.clearOverlays();
  globalJsMap.addOverlay(new GMarker(center));

  return false;
};

LG.addOneTimeListener = function(src, eventName, callback){
    var l = GEvent.addListener(src, eventName, function(){
	GEvent.removeListener(l);
	callback.apply(this, arguments);
    });
};

LG.smoothReplaceDom = function(node, url, getContent){
    var duration = 500;
    //hide the existing stuff
    var hiding = dojo.fadeOut({
	node:node,
	duration:duration
    });
    hiding.play();

    //pull content from the server, show it in the pane
    dojo.xhrGet({
	url:url,
	content:getContent,
	load:function(resp){
	    var fn = function(){
		dojo.html.set(node, resp);
		dojo.fadeIn({
		    node: node,
		    duration:duration
		}).play();
	    };

	    if(hiding.status() == "playing"){
		var h = dojo.connect(hiding, "onEnd", null,
		    function(){
			fn();
			dojo.disconnect(h);
		    });
	    }
	    else
		fn();
	}});
};

LG.init = function(map, url){
    LG.map = map;

    GEvent.addListener(LG, 'view-full', function(){
	map.setCenter(LG.bounds.getCenter(), map.getBoundsZoomLevel(LG.bounds));
    });

    GEvent.addListener(LG, 'show-info', function(id){
	if(id == LG.displayedRegion) return;
	LG.displayedRegion = id;
	LG.smoothReplaceDom(LG.infoPane, LG.infoUrl, {'id':id});
    });

    GEvent.addListener(LG, 'region-selected', function(poly){
	if(poly == LG.selectedRegion) return;

	if(LG.selectedRegion){
	    GEvent.trigger(LG, 'region-deselected', LG.selectedRegion);
	}
	LG.selectedRegion = poly;
	poly.setFillStyle(poly.selectedStyle);

	var loadFn = function(){
	    if(!LG.markerManager)
		LG.markerManager = poly.markerLayer.manager;

	    poly.zoomAndCenter();
	};

	if(!poly.markerLayer){
	    var opts = {autoFocus:false, 
		icon:poly.region.iconUrl,
		manager:LG.markerManager};
	    LG.hookMarkerEvents(opts);
	    //when the markers are done, zoom in
	    LG.addOneTimeListener(opts, 'markers-finalized', loadFn);
	    poly.markerLayer = gmap.addLayer(LG.childrenUrl + '?id=' + poly.region.id, opts);
	    poly.markerLayer.show();
	}else
	    loadFn();
    });

    GEvent.addListener(LG, 'region-deselected', function(poly){
	poly.setFillStyle(poly.normalStyle);
	LG.selectedRegion = null;
    });


    LG.updateMenu = function (placeId, finalizeFn){
	var subListId = "sub" + placeId;
	var childList = dojo.byId(subListId);
	if(childList){
	    var indicator = dojo.query("span.indicator", childList.parentNode);
	    var showSubList = indicator[0].innerHTML == "+";

	    //make note of whether we're open or not
	    LG.openLinksById[placeId] = showSubList ? true : null;

	    var hideIndicator = dojo.fadeOut({node:indicator[0],
		duration:100,
		onEnd:function(){
		    indicator.empty(); //clear the content
		    indicator.addContent(showSubList ? "-" : "+");
		}});

	    var showIndicator = dojo.fadeIn({node:indicator[0], duration:100});

	    //find all sublists and display them if needed, going as deep through the tree
	    //as possible
	    var subLists = dojo.query("#" + subListId+", #" + subListId+" ul");
	    var animFn = showSubList ? dojo.fx.wipeIn : dojo.fx.wipeOut;
	    //wipeIn/Out all sublist sequentially so the UI is consistent
	    var changeSubList = dojo.fx.chain(subLists.map(function(lst){
		return animFn({node:lst});
	    }));

	    //run all the animations sequentially
	    var menuChanges = dojo.fx.chain([hideIndicator, changeSubList, showIndicator]);

	    //fire our other events after the menu animation is completed so we're not trying
	    //to do too much at once.
	    if(finalizeFn)
		dojo.connect(menuChanges, "onEnd", finalizeFn);

	    menuChanges.play();
	}else if(finalizeFn)
	    finalizeFn();
    };


    LG.selectPlace = function(placeId, from, evt){
	if(evt){
	    var evt = dojo.fixEvent(evt);
	    if(evt.target.nodeName == 'A') return;
	    dojo.stopEvent(evt);
	}
	LG.updateMenu(placeId, function(){
	    GEvent.trigger(LG, 'show-info', placeId);
	    if(LG.polyById[placeId])
		GEvent.trigger(LG, 'region-selected', LG.polyById[placeId]);
	});;

    };

    LG.bounds = new GLatLngBounds();
    LG.openLinksById = {};
    LG.polyById = {};
    LG.markById = {};
    LG.infoPane = dojo.query('.infoPane')[0];
    LG.highlightedPlaceTimers = {}

    var fn = function(doc){
	var regions = dojo.eval(doc);
	LG.loadRegionList(map, regions);
    };
    GDownloadUrl(url, fn);
};

LG.dehighlightPlace = function(placeId){
    if(LG.highlightedPlaceTimers[placeId]){
	window.clearTimeout(LG.highlightedPlaceTimers[placeId]);
	delete LG.highlightedPlaceTimers[placeId];
    }
    var poly = LG.polyById[placeId];
    if(poly && poly != LG.selectedRegion)
	poly.setFillStyle(poly.normalStyle);
};

LG.highlightPlace = function(placeId, suppressPan){
    var poly = LG.polyById[placeId];
    var mark = LG.markById[placeId];

    if(poly && poly != LG.selectedRegion)
	poly.setFillStyle(poly.highlightStyle);

    //only pull them up if they stay hovered on one spot for 500ms
    LG.highlightedPlaceTimers[placeId] = window.setTimeout(function(){	
	if(!suppressPan){
	    if(poly)
		LG.map.panTo(poly.getBounds().getCenter());
	    if(mark)
		LG.map.panTo(mark.getLatLng());
	}
	GEvent.trigger(LG, 'show-info', placeId)
    }, 500)
};


LG.hookMarkerEvents = function(opts){
    var l = GEvent.addListener(opts, 'marker-created', LG.onMarkerCreate);
    //clean up our event handler when we're done with all markers
    LG.addOneTimeListener(opts, 'markers-finalized', function(){
	GEvent.removeListener(l);
    });
};

LG.onMarkerCreate = function(gm, mark){
    LG.markById[mark.id] = gm;
    GEvent.addListener(gm, "mouseover", function(){
	LG.highlightPlace(mark.id, true);
    });

    GEvent.addListener(gm, "mouseout", function(){
	LG.dehighlightPlace(mark.id);
    });

    //redirect if we're a city, or we have no kids
    if(mark.type == 'city' || mark.type == 'neighborhood' || !mark.hasChildren){
	GEvent.addListener(gm, 'click', function(){
	    if(!gm.suppressClick)
		window.location = mark.detailUrl;
	});
    }
};

LG.loadRegionList = function(map, regions){
    var iter = function(i){
	if(i >= regions.length) return LG.finalizeRegionList(map);
	
	LG.loadRegion(map, regions[i]);

	//don't loop too tightly to let others go by
	if (i % 4 == 0)
		window.setTimeout(dojo.hitch(null, iter, i+1), 0);
	else
	    iter(i+1);
    }
    iter(0);
};

LG.makePoints = function(region){
    if(!region.points) {
	console.log('LG.makePoints: NO POINTS');
	return false;
    }
    var points = [];
    for(var i = 0; i < region.points.length; i++){
	var point = gmap.createPoint(region.points[i]);
	LG.bounds.extend(point);
	points.push(point);
    }
    //ensure we're a closed polygon
    if(!points[0].equals(points[points.length-1])){
	console.log('closing the polygon');
	points.push(points[0]);
    }

    return points;
};

LG.makePoly = function(region, points, map){
    if(!points) {
	console.log('LG.makePoly: NO POINTS');
	return false;
    }
    var color = region.color || '#ff0000';
    var weight = region.weight || 1;
    var opacity = region.opacity || .5
    var fillColor = region.fillColor || color;
    var fillOpacity = region.fillOpacity || .5;

    var poly = new GPolygon(points, 
	color, weight, opacity,
	fillColor, fillOpacity);

    //save these for later
    poly.points = points;
    poly.region = region;
    poly.strokeStyle = {opacity:opacity, color:color, weight:weight};
    poly.normalStyle = {opacity:fillOpacity, color:fillColor, weight:weight};
    poly.highlightStyle = {opacity:fillOpacity*1.25, color:fillColor, weight:weight};
    poly.selectedStyle = {opacity:fillOpacity / 2, color:fillColor, weight:weight};

    poly.setColor = function(c){
	poly.selectedStyle.color = poly.highlightStyle.color =
	    poly.normalStyle.color = c || '#ff0000';
    };

    poly.zoomAndCenter = function(){
	var bounds = poly.getBounds();
	map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));
    }

    GEvent.addListener(poly, 'mouseover', function(){
	LG.highlightPlace(region.id, true);
    });

    GEvent.addListener(poly, 'mouseout', function(){
	if(poly == LG.selectedRegion) return;
	LG.dehighlightPlace(region.id);
    });

    GEvent.addListener(poly, 'click', function(latlng){
	LG.selectPlace(region.id);
    });

    return poly;
};

LG.loadRegion = function(map, region){
    var points = LG.makePoints(region);
    var poly = LG.makePoly(region, points, map);
    if(poly)
	LG.polyById[region.id] = poly;
};

LG.finalizeRegionList = function(map){
    for(id in LG.polyById)
	map.addOverlay(LG.polyById[id]);
    GEvent.trigger(LG, 'view-full');
};

