var yetToLoad = 0;
var geocoder = new GClientGeocoder();

function addGoogleMapFromForm() {
    var container = $('maps');
    var mapContainer = new Element('div', {
        class: 'map-row'
    });
    mapContainer.injectTop(container);

    var width = $('width').getValue().toInt();
    var height = $('height').getValue().toInt();
    var mapDiv = new Element('div', {
        class: 'map',
        styles: {
            width: width + 'px',
            height: height + 'px'
        }
    });
    mapDiv.injectTop(mapContainer);

    var mapDelete = new Element('input', {
        type: 'button',
        class: 'remove-button',
        value: 'remove'
    });
    mapDelete.onclick = function() {
        mapContainer.remove();
    }
    mapDelete.inject(mapContainer);

    placeEntries = {};

    for(var i = 1; i <= 2; i++)
    {
        var placeEntry = {};
        placeEntry.name = $('place' + i + 'name').getValue();
        placeEntry.address = $('place' + i +'address').getValue();
        placeEntries[i] = placeEntry;
    }

    loadGoogleMap(mapDiv, placeEntries, width, height);
}

function loadGoogleMap(mapDiv, placeEntries, width, height) {
    var places = Array();

    var done = false;
    var allDone = function()
    {
        if(places.length > 0 && yetToLoad == 0 && !done)
        {
            loadGoogleMapFromCoordinates(mapDiv, places, width, height);
            done = true;
        }
    }

    for(var i = 0; i < placeEntries.length; i++)
    {
        var placeEntry = placeEntries[i];
        var place = {};
        place.name = placeEntry.name;
        place.address = placeEntry.address;
        yetToLoad++;
        geocoder.getLatLng(
            placeEntry.address,
            makeLoadGeocodeDataFunction(place, allDone));
        places.push(place);
    }

    allDone();

}

function makeLoadGeocodeDataFunction(place, allDone)
{
    return function(point) {
        if(!point)
            yetToLoad--;
        else
        {
            place.lat = point.lat();
            place.lon = point.lng();
            yetToLoad--;
            allDone();
        }
    };
}

function urlToLatitudeLongitude(url)
{
    var opts = {};
    url.split('?')[1].split('&').forEach(function(couple) {
        var x = couple.split('=');
        opts[x[0]] = x[1];
    });
    return opts.ll.split(',').map(function(x) { return x.toFloat(); });
}

function makeInfoFunction(marker, place)
{
    return function() {
        marker.openInfoWindowHtml("<div class='gmap-place-informations'><p class='name'>" + place.name + "</p><p class='address'>" + place.address + "</p></div>", {maxWidth: 200});
    }
}

function loadGoogleMapFromCoordinates(div, places, width, height)
{
    var map = new GMap2(div);
    var enclosingArea = null;
    var markers = Array();
    var infoFunction = null;
    for(var i = 0; i < places.length; i++)
    {
        var place = places[i];
        var point = new GLatLng(place.lat, place.lon);
        var marker = new GMarker(point);
        infoFunction = makeInfoFunction(marker, place);
        GEvent.addListener(marker, 'click', infoFunction);
        markers.push(marker);
        if(enclosingArea == null)
            // no previous marker: area is a point containing just this
            enclosingArea = {
                left: place.lat,
                top: place.lon,
                right: place.lat,
                bottom: place.lon
            };
        else {
            // adapt enclosing area to the new point if needed
            enclosingArea.left = Math.min(enclosingArea.left, place.lat);
            enclosingArea.right = Math.max(enclosingArea.right, place.lat);
            enclosingArea.top = Math.min(enclosingArea.top, place.lon);
            enclosingArea.bottom = Math.max(enclosingArea.bottom, place.lon);
        }
    }
    if(enclosingArea != null)
    {
        // add some 'border' to the region
        xAdd = (enclosingArea.right - enclosingArea.left)/10;
        yAdd = (enclosingArea.bottom - enclosingArea.top)/10;
        enclosingArea.left -= xAdd;
        enclosingArea.right += xAdd;
        enclosingArea.top -= yAdd;
        enclosingArea.bottom += yAdd;
        // ensure we have a certain minimum size
        var min = 0.001;
        var increaseY = min - (enclosingArea.bottom - enclosingArea.top);
        if(increaseY > 0)
        {
            enclosingArea.top -= increaseY/2;
            enclosingArea.bottom += increaseY/2;
        }
        var increaseX = min - (enclosingArea.right - enclosingArea.left);
        if(increaseX > 0)
        {
            enclosingArea.left -= increaseX/2;
            enclosingArea.right += increaseX/2;
        }
        // adapt to container size to keep ratio
        xRatio = (enclosingArea.right - enclosingArea.left)/width;
        yRatio = (enclosingArea.bottom - enclosingArea.top)/height;
        if(xRatio > yRatio)
        {
            var newY = height*xRatio;
            var diff = newY - (enclosingArea.bottom - enclosingArea.top);
            enclosingArea.top -= diff/2;
            enclosingArea.bottom += diff/2;
        }
        else
        {
            var newX = width*yRatio;
            var diff = newX - (enclosingArea.right - enclosingArea.left);
            enclosingArea.left -= diff/2;
            enclosingArea.right += diff/2;
        }
        // we can now set position and zoom [do NOT create GLatLngBounds through
        // its normal constructor! it hits a bug in gmap api!]
        var bounds = new GLatLngBounds;
        bounds.extend(new GLatLng(enclosingArea.left, enclosingArea.bottom));
        bounds.extend(new GLatLng(enclosingArea.right, enclosingArea.top));
        var zoom = map.getBoundsZoomLevel(bounds);
        var center = new GLatLng((enclosingArea.right + enclosingArea.left)/2, (enclosingArea.bottom + enclosingArea.top)/2);
        map.setCenter(center, zoom);
    }
    // now we can add all markers
    for(var i = 0; i < markers.length; i++)
        map.addOverlay(markers[i]);
    map.addControl(new GSmallZoomControl());
    // if there's only one marker, immediatly open the info window
    if(markers.length == 1)
        infoFunction();
}
