/*
Script: map.js.php
	Contains Supporters mapping function.

Requires:
    Google Maps
    Google MarkerManager (http://gmaps-utility-library.googlecode.com/)
    supporter.js[.php]

License:
	GNU GPL.
*/


/*
Function: profile_map
    Map a addresses of a supporter described in an profile element
    (an HTML element). The profile element must contains on of more child
    elements  with the 'address' class. For each such element, the coordinates
    are extracted using the textContent of the first childs with the 'latitude'
    and 'longitude' classes. The full 'address' element is cloned in a
    infoWindow when it's corresponding marker is clicked.
    
Arguments:
    profileId - Selector for the HTML element containing the supporter profile
        of the supporter to map (optional, if not provided '.profile' is used).
        
TODO:
    Rewrite using the Supporter.fromHcard() function.
*/
function profile_map(profileId)
{
    if ((typeof GBrowserIsCompatible)!='undefined' && GBrowserIsCompatible())
    {
        var profileElement = profileId ? $(profileId) : $E('.profile');
        //If a map element is not found, create one
        if(!$('map'))
        {
            mapElement = new Element('div'); 
            mapElement.id = 'map';
            mapElement.style.height = profileElement.offsetHeight + 'px';
            mapElement.style.width = "50%";
            mapElement.style.cssFloat = "right";
            mapElement.style.styleFloat = "right";
            profileElement.style.width = "50%";
            mapElement.injectBefore(profileElement);
        }
        
        var map = new GMap2($('map'));
        map.addControl(new GSmallMapControl());
        map.addControl(new GMapTypeControl());
        map.setCenter(new GLatLng(50.75, 4.5), 8);
        
        var markers = [];
        var mapCentered = false;
        profileElement.getElements('.address').forEach(function(addressElement)
        {
            
            var latitude = addressElement.getElement('.latitude').textContent;
            var longitude = addressElement.getElement('.longitude').textContent;
            var point = new GLatLng(latitude, longitude);
            if(!mapCentered)
            {
                mapCentered = true;
                map.setCenter(point, 14);
            }
            var marker = new GMarker(point);
            var addressClone = addressElement.cloneNode(true);
            GEvent.addListener(marker, "click", function() {
                marker.openInfoWindow(addressClone);
            });
            addressElement.onclick = function() {
                map.panTo(marker.getPoint())
            };
            markers.push(marker);
        });
        
        var markerManager = new GMarkerManager(map);
        markerManager.addMarkers(markers, 0);
        markerManager.refresh();
    }
}

/*
Function: map_init()
    Initilizes a ''map'' in the element with the 'map' id and add markers for  
    supporters. Supporters are retrieved from server (URL partially hardocoded
    in PHP). Alter the ''filter'' form to
      * Use asynch. JSON supporters loading on submit
      * Turn any existing onclick on inputs named 'commitments[]' to asynch.
        JSON supporters loading    
*/
function map_init()
{
    var map = init('map');
       
    $('filter').action = 'http://map.ubuntu-be.org/index.php/supporters/json';
    
    var fetchAndUpdateSupporters = function(e)
    {
    	if($defined(e) && e.type=='submit')
    	    new Event(e).stop();       
      updateStatus('Loading supporters.', 'load');
    	this.send(
    	{
    		onComplete: function()
    		{
    		    updateStatus('Mapping supporters.', null);
    			  var supporters = Supporter.fromJson(this.response.text);
            update(supporters, map);
            updateStatus('', null);
    		}
    	});
    }
    $('filter').getElements('input').forEach(function(input)
    {
        if($defined(input.onclick) && input.name=='commitments[]')
        {
            input.onclick = fetchAndUpdateSupporters.bindAsEventListener($('filter'));
        }
    });

    $('filter').addEvent('submit', fetchAndUpdateSupporters);
    fetchAndUpdateSupporters.call($('filter'));
    /*
    TODO: Instead of always fetching a new supporters array from server we
    should track changes on form inputs. If the states of the inputs implies
    a narrower search that the one of the last fetch, a new fetch is not needed
    and the already retrieved supporters can be filtred.
    */
}

/*
Function: init
    Initializes a ''map'' in the 'el' DOM element.
*/
function init(el)
{
    if((typeof GBrowserIsCompatible)!='undefined' && GBrowserIsCompatible())
        return initMap(el);
    else
        return initList(el);
}
/*
Function: initMap
    Initializes a GMap2 in the 'el' DOM element.
    
Returns:
    A MarkerManager for the created map.

Arguments:
    el - An element or element selector (used as argument for $())

External:
   center - An object with tree attribute, latitude, longitude and zoom used
       initial center and zoom level for the GMap2 (optional).
*/
function initMap(el)
{
    var map = new GMap2($(el));
    map.addControl(new GSmallMapControl());
    map.addControl(new GMapTypeControl());
    if($defined(center) && $type(center)=='object') map.setCenter(new GLatLng(center.latitude, center.longitude), center.zoom);
    map.enableScrollWheelZoom();
    return new MarkerManager(map);
}

/*
Function: initList
    Initializes an empty list element (ul) in the 'el' DOM element. The created
    element has the "supporters" class.

Arguments:
    el - An element or element selector (used as argument for $())
   
Returns:
    The new list element.
*/
function initList(el)
{
    return new Element('ul').injectInside($(el)).addClass('supporters');
}

/*
Function: update
    Update a ''map'' to display a set of supporters. The exact behavior depends
    on the type of map. With a GMap or a MakerManager, supporters'
    getMarkers() are show on the map. With a list element (ul or ol), items are
    created with content from supporters' getInfowindow.

Arguments:
    supporters - An array of supporters (instances of Supporter).
    map - A GMap, a MarkerManager or a list DOM element.
*/
function update(supporters, map)
{
    if($type(map)=='object')
    {
        if(map.addOverlay)
            return updateMap(supporters, map);
        else if(map.addMarkers)
            return updateMarkerManager(supporters, map);
    }
    if($type(map)=='element' && (map.getTag()=='ul' || map.getTag()=='ol'))
    {
        return updateList(supporters, map);
    }
    return updateStatus('Cannot update ' + map + '.');
}

/*
Function: updateMap
    Update a GMap2 to display a set of supporters. Clears all map's overlay then
    add supporters' getMarkers.

Arguments:
    supporters - An array of supporters (instances of Supporter).
    map - A GMap2 to display supporters onto.
*/
function updateMap(supporters, map)
{
  map.clearOverlays();
  supporters.forEach(function(supporter) 
  {
    supporter.getMarkers().forEach(function(marker)
    {
      map.addOverlay(marker)
    });
  });
}

/*
Function: updateMarkerManager
    Update a MarkerManager to display a set of supporters. Clears all
    markerManager's markers, then add supporters' getMarkers().

Arguments:
    supporters - An array of supporters (instances of Supporter).
    markerManager - A MarkerManager.
*/
function updateMarkerManager(supporters, markerManager)
{
  markerManager.clearMarkers();
  supporters.forEach(function(supporter) 
  {
    markerManager.addMarkers(supporter.getMarkers(), 0);
  });
  markerManager.refresh();
}

/*
Function: updateList
    Update a list element to display a set of supporters. Empty list, then
    add supporters' getInfoWindow in list items.

Arguments:
    supporters - An array of supporters (instances of Supporter).
    list - A list element.
*/
function updateList(supporters, list)
{
    list.empty();
    supporters.forEach(function(supporter)
    {
        supporter.addresses.forEach(function(address)
        {
            supporter.getInfoWindow(address).injectInside(new Element('li').injectInside(list));
        });
    });
}

/*
Function: updateStatus
    Updates the content ofthe DOM element  id "info" with message.
    
Arguments:
    message - The end-user message to display in $('info').
    type - The type of end user message. Either 'info', 'load' or 'error'.
*/
function updateStatus(message, type)
{
    var element = $('info');
    if(element)
    {
    //Empty the status element
    element.empty();
    switch(type)
        {
            case 'error':
                element.removeClass('info');
                element.removeClass('load');
                element.addClass(type);
                break;
            case 'info':
                element.removeClass('error');
                element.removeClass('load');
                element.addClass(type);
                break;
            case 'load':
                element.removeClass('error');
                element.removeClass('info');
                element.addClass(type);
                break;
            default:
                element.removeClass('error');
                element.removeClass('info');
                element.removeClass('load');
                break;
        }
        switch($type(message))
        {
            case 'element':
            case 'textnode': message.injectInside(element); break;
            case 'collection': element.forEach(function(e){e.injectInside(element);}); break;
            default: element.setHTML(message); break;
        }
    }
}
