﻿var CMH = CMH || {};
CMH.Map = function(mapContainer, locations, options)
{
    var me       = this;
	var self	 = CMH.Map;
    me.locations = locations.length ? locations : [locations];
    me.options   = options || {};
    me.options.color = me.options.color || "blue"; //default color

    me.map       = _getMap();
    me.markers	 = _getMarkers();
	me.bounds	 = new GLatLngBounds(); //to calc bounds
    
    if (!options.disableClick)
        _addListeners();
    
    _mapLocations();
    
	// Get a new google map
	function _getMap()
	{
		//set div size first
		//mapContainer.setStyle(self.SMALL_MAP_SIZE);

		var map = new GMap(mapContainer);
		map.setCenter(new GLatLng(0, 0), 8); //default center
		map.addControl(new GSmallMapControl());
		map.addControl(new GMapTypeControl(1));

		//show/hide controls w/ mouseover
		GEvent.addListener(map, "mouseover", function() { map.showControls(); });
		GEvent.addListener(map, "mouseout", function() { map.hideControls(); });
		map.hideControls(); //hide to begin with
		map.enableGoogleBar();

		//map.enableScrollWheelZoom();
		return map;
	}

    function _addListeners()
    {
		//if ($("map-size-toggle"))
		//	Event.observe("map-size-toggle", "click", _sizeToggle);

        for(var i = 0; i < me.markers.length; i++)
            _addListener(i+1, me.markers[i]);
    }
    
    function _addListener(id, marker)
    {
		GEvent.addListener(marker, "click", function()
		{ 
			_selectMarker(marker);
			
			if (me.options.markerCallback)
			    me.options.markerCallback(marker);
		});

		//find all map pin symbols and have each symbol trigger the corresponding marker
		$$("a.pin-" + id).each(function(a) {
			Event.observe(a, "click", function(e) {
				Event.stop(e);
				GEvent.trigger(marker, "click");
			});
		});
    }
    
    // Map all of the markers 
    function _mapLocations()
    {
        for(var i = 0; i < me.markers.length; i++)
        {
            if (!me.markers[i]) continue;
			me.map.addOverlay(me.markers[i]);
			me.bounds.extend(me.markers[i].getLatLng());
		}
		me.bounds = self.scaleBounds(me.map, me.bounds, 1.2);
		_setCenter();
		me.map.savePosition(); //to save initial zoom and position
    }
    
    function _setCenter(center, zoom_out)
    {
		me.map.checkResize(); //check if map div was re-sized
		var zoom = me.map.getBoundsZoomLevel(me.bounds);
		if (zoom > self.MAX_ZOOM) zoom = self.MAX_ZOOM;
		if (!zoom_out && zoom < me.map.getZoom()) zoom = null; //don't zoom out
		center = center || me.bounds.getCenter();
		me.map.setCenter(center, zoom);
    }
    
    // Get an array of markers for all of the list items
    function _getMarkers()
    {
        var markers = [];
        for(var i = 0; i < me.locations.length; i++)
            markers.push(_getMarker(me.locations[i]));
        
        return markers;
    }
    
    function _getMarker(location)
    {
        var icon = new GIcon(G_DEFAULT_ICON);
        icon.image = "/source/maps/images/marker-" + me.options.color + ".png";
        icon.iconSize = new GSize(34,36);

        icon.shadow = "/source/maps/images/marker-shadow.png";
        icon.shadowSize = new GSize(35,23);
       
        var marker = new CMH.LabeledMarker(
			new GLatLng(location.latitude, location.longitude), 
			{
				icon: icon,
				infoText: location.desc,
				labelText: location.id,
				labelColor: me.options.color,
				labelClass: "marker-label",
				labelSelectedClass: "marker-label-selected"
			}
		);

        marker.listItem = location.listItem;      
                                           
        return marker;
    }
    

    // Select a marker and zoom and pan to it
    function _selectMarker(marker)
    {
		if (marker.isSelected()) return; //skip zoom and pan if already selected

        _deselectMarkers();

        var z = me.map.getZoom();
        me.map.setZoom((z<10)? 10:z);
        me.map.panTo(marker.getLatLng());
        marker.select();
    }
    
    // Deselect all markers
    function _deselectMarkers()
    {
        for(var i = 0; i < me.markers.length; i++)
            me.markers[i].deselect();
    }
    
    function _sizeToggle(e)
    {
		Event.stop(e);
		var toggleLink = Event.element(e);
		if (!toggleLink) return;

		//enlarge if curr map width is the small size		
		var enlarge = (mapContainer.getStyle('width') == self.SMALL_MAP_SIZE.width);
		//change link text
		var linkText = enlarge? toggleLink.innerHTML.replace("bigger", "smaller") : toggleLink.innerHTML.replace("smaller", "bigger");
		toggleLink.innerHTML = linkText;

		var mapParent = $(mapContainer.parentNode);
		var mapGrandParent = $(mapParent.parentNode);
		if(enlarge) { //strip classes from wrapper divs, add clear
			mapParent.removeClassName("map");
			mapGrandParent.removeClassName("secondary");
			mapGrandParent.addClassName("clear");
		}
		else { //add classes back to wrapper divs, remove clear so map floats right
			mapParent.addClassName("map");
			mapGrandParent.addClassName("secondary");
			mapGrandParent.removeClassName("clear");
		}

		var size = enlarge? self.LARGE_MAP_SIZE : self.SMALL_MAP_SIZE;
        if (!enlarge) _deselectMarkers(); //if going to small size, unselect markers
        //resize map
		mapContainer.setStyle(size);
		//centering
		if (enlarge) _setCenter(me.map.getCenter());
		else _setCenter(null, true);

		//fancy animated resize (scriptaculous effects required)
//		var outer_size = {height:'420px', width:'645px', margin:'0'};
//		new Effect.Parallel(
//			[
//				new Effect.Morph(mapContainer, { style: size }),
//				new Effect.Morph(mapParent, { style: outer_size })
//			],
//			{ afterFinish: _setCenter }
//		);
    }
}


// Parse the locations out of the list items
CMH.Map.GetLocations = function(listItems)
{
    var locations = [];
    for(var i = 0; i < listItems.length; i++)
    {
        var loc = CMH.Map.GetLocation(i + 1, listItems[i]);
        if (loc) locations.push(loc);
    }
    
    return locations;
}
    
// Parse a location out of an html container
CMH.Map.GetLocation = function(id, item)
{
    if (item.select(".latitude")[0])
        return { id: id,
                 latitude:      item.select(".latitude")[0].innerHTML,
                 longitude:     item.select(".longitude")[0].innerHTML,
                 desc:		    item.select(".desc")[0] ? item.select(".desc")[0] : null,
                 listItem:      item };
    else
        return null;
}

// Select a list item by changing its class
CMH.Map.selectListItem = function(listItem, allListItems)
{
    CMH.Map.deselectListItems(allListItems);
    listItem.className = "current";
}
    
// Deselect all list items
CMH.Map.deselectListItems = function(listItems)
{
    for(var i = 0; i < listItems.length; i++)
        listItems[i].className = "";
}


CMH.Map.scaleBounds = function(map, bounds, scale) {
	//scale using pixel points
	var pNE = map.fromLatLngToDivPixel(bounds.getNorthEast());
	var pSW = map.fromLatLngToDivPixel(bounds.getSouthWest());
	var xPix = (((pNE.x - pSW.x)*scale) - (pNE.x - pSW.x))/2;
	var yPix = (((pSW.y - pNE.y)*scale) - (pSW.y - pNE.y))/2;

	//create new bounding lat/lng points
	var bNE = map.fromDivPixelToLatLng(new GPoint(pNE.x+xPix,pNE.y-(yPix*2)));
	var bSW = map.fromDivPixelToLatLng(new GPoint(pSW.x-xPix,pSW.y+(yPix/2)));
	//map.addOverlay(new GMarker(bNE));
	//map.addOverlay(new GMarker(bSW));
	bounds.extend(bNE);
	bounds.extend(bSW);
	return bounds;
} 

// store max zIndex
CMH.Map.recordZIndex = function(zIndex)
{
	if (CMH.Map.MAX_ZINDEX == 0 || zIndex > CMH.Map.MAX_ZINDEX)
		CMH.Map.MAX_ZINDEX = zIndex;
}

// return new max zIndex
CMH.Map.getMaxZIndex = function()
{
	return CMH.Map.MAX_ZINDEX++;
}

CMH.Map.MAX_ZOOM = 14;
CMH.Map.MAX_ZINDEX = 0;
CMH.Map.LARGE_MAP_SIZE = {height:'675px', width:'675px', border:'1px solid gray'};
CMH.Map.SMALL_MAP_SIZE = {height:'675px', width:'675px', border:'1px solid gray'};