/* Toostis project (http://toostis.com)
 * Copyright (c) 2007, 2008 Iugo panton, UAB
 * 
 * Google maps widget for event and profile
 *
 * Requires bind() function from toostis.js
 */

var GoogleMaps = function(container_id, options) {
    var latlong = new google.maps.LatLng(40.0, 20.0);
    this.options = {
        center: latlong,
        zoom: 7,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        mapTypeControlOptions: {style: google.maps.MapTypeControlStyle.DROPDOWN_MENU},
        editable: true
    };
    this.loaded = false;

    $.extend(this.options, options || { });

    if (this.options.sterilized) {
        this.options.disableDefaultUI = true;
        this.options.draggable = false;
        this.options.scrollwheel = false;
        this.options.keyboardShortcuts = false;
        this.options.disableDoubleClickZoom = true;
    }

    this.container = gId(container_id);
    this.setup();
}

GoogleMaps.prototype = {
	setup: function() {
		// Set up google maps widget
        var _this = this;
        var map = new google.maps.Map(this.container, this.options);

        // Marker
        var marker = new google.maps.Marker({
            position: this.options.center,
            map: map,
            draggable: this.options.editable
        });
        google.maps.event.addListener(marker, 'dragend',
            bind(function(event) {
                this.onMarkerPlaced(this.marker);
            }, this));

        
        google.maps.event.addListener(map, 'rightclick', bind(this.onMapClicked, this));
        google.maps.event.addListener(map, 'zoom_changed', bind(function(){this.onChange(
                        map.getCenter().lat(), 
                        map.getCenter().lng(),
                        map.getZoom())}, this));

        // Geocoder
        geocoder = new google.maps.Geocoder();

        // Add map object to base element
        this.container._googlemap = this;

		this.map = map;
        this.geocoder = geocoder;
		this.marker = marker;
        this.loaded = true;
	},

    setFromGeocoder: function(address, preserve_zoom) {
        if (preserve_zoom == undefined) 
            preserve_zoom = false;
        var map = this.map;
        var marker = this.marker;
        this.geocoder.geocode({'address': address}, function(results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
                    // Set map to the first result
                    if (preserve_zoom) {
                        map.setCenter(results[0].geometry.location);
                    } else {
                        map.fitBounds(new google.maps.LatLngBounds(
                            new google.maps.LatLng(
                                results[0].geometry.viewport.getSouthWest().lat(),
                                results[0].geometry.viewport.getSouthWest().lng()),
                            new google.maps.LatLng(
                                results[0].geometry.viewport.getNorthEast().lat(),
                                results[0].geometry.viewport.getNorthEast().lng()))
                        );
                    }
                    marker.setPosition(results[0].geometry.location);
                }
            }
        });
    },

    /*
     * This gets called on every marker place change.
     * _onMarkerPlaced should be overwritten for every map logic
     */
    onMarkerPlaced: function(marker) { 
        if (typeof this._onMarkerPlaced == 'function') {
            this._onMarkerPlaced(marker);
        }
        point = marker.getPosition();
        map_zoom = this.map.getZoom();
        this.onChange(point.lat(), point.lng(), map_zoom);
    },

    onMapClicked: function(event) {
        if (!this.options.editable) {
            return;
        }
        this.marker.setPosition(event.latLng);
        this.onMarkerPlaced(this.marker);
    },

    /* 
     * This gets called when marker position is changed
     * and saveurl is not set (should be overridden).
     */
    onChange: function(lat, lon, zoom) {
        if (typeof this._onChange == 'function') {
            this._onChange(lat, lon, zoom);
        }
    },

    getCityName: function(marker, callback) {
        // Get location by reverse geocoding
        var point = marker.getPosition();
        this.geocoder.geocode({'latLng': point, 'language': 'en'}, function(results, status) {
            var city = "";
            var country = "";
            if (status == google.maps.GeocoderStatus.OK && results.length) {
                $.each(results[0].address_components, function(index, result) {
                    // Find city (locality)
                    if ($.inArray('locality', result.types) != -1) {
                       city = result.long_name;
                    }
                    if (city == "") {
                        if ($.inArray('administrative_area_level_1', result.types) != -1) {
                            city = result.long_name;
                        }        
                    }
                    // Find country
                    if ($.inArray('country', result.types) != -1) {
                       country = result.long_name;
                    }
                });
            }
            callback(city, country);
        });
    },
    
    getAddress: function(marker, callback) {
        // Get address by reverse geocoding
        var point = marker.getPosition();
        this.geocoder.geocode({'latLng': point, 'language': 'en'}, function(results, status) {
            if (status == google.maps.GeocoderStatus.OK && results.length) {
                    // Format address
                    var result = results[0];
                    var format_elements = ['route', 'locality', 'country'];
                    var filtered_elements = {}
                    var street_number = '';

                    // Filter
                    $.each(result.address_components, function(i, element) {
                        if ($.inArray(element.types[0], format_elements) > -1) {
                            filtered_elements[element.types[0]] = element.long_name;
                        } else if (element.types[0] == 'street_number') {
                            // Deal with street number separately
                            street_number = element.long_name;
                        }
                    });

                    // Sort
                    var format_array = [];
                    $.each(format_elements, function(i, element) {
                        value = filtered_elements[element];
                        if (value) {
                            format_array.push(value);
                        }
                    });

                    // Format
                    var format_string = format_array.join(', ');
                    if (street_number) {
                        format_string = street_number + ' ' + format_string;
                    }

                    if (typeof callback == 'function') {
                        callback(format_string);
                    } else {
                        return format_string;
                    }
                }
            });
    },

	setExpander: function(expander, expandedsize) {
		this.expander = $(expander);
		this.expander.observe('click', this.expand.bind(this, expandedsize));
	},

	setCollapser: function(collapser, collapsedsize) {
		this.collapser = $(collapser);
		this.collapser.observe('click', this.collapse.bind(this, collapsedsize));
	},

    expand: function(size) {
        this.map.enableScrollWheelZoom();
        this.setSize({height: size+'px'});
        if (this.expander) {
            this.expander.hide();
        }
        if (this.collapser) {
            this.collapser.show();
        }
    },

    collapse: function(size) {
        // do not interfere with mousewheel scrolling
        this.map.disableScrollWheelZoom();
        this.setSize({height: size+'px'});
        if (this.collapser) {
            this.collapser.hide();
        }
        if (this.expander) {
            this.expander.show();
        }
    },

	setSize: function(newsize) {
		if (newsize.width) {
			this.container.style.widget = newsize.width;
		}
		if (newsize.height) {
			this.container.style.height = newsize.height;
		}
		this.map.checkResize();
		this.map.panTo(this.marker.getPoint());
	}
};

// Locator code
// Locator shows events around me
var GoogleMapsLocator = function(container_id, options) {
    var latlang = new google.maps.LatLng(40.0, 20.0);
    this.options = {
        center: latlang,
        zoom: 7,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        mapTypeControlOptions: {style: google.maps.MapTypeControlStyle.DROPDOWN_MENU},
    };
    this.loaded = false;

    $.extend(this.options, options || { });

    if (this.options.sterilized) {
        this.options.disableDefaultUI = true;
        this.options.scrollwheel = false;
        this.options.keyboardShortcuts = false;
        this.options.disableDoubleClickZoom = true;
    }

    this.container = gId(container_id);
    this.setup();
}

GoogleMapsLocator.prototype = {
	setup: function() {
		// Set up google maps widget
        var _this = this;
        var map = new google.maps.Map(this.container, this.options);

        // Geocoder
        geocoder = new google.maps.Geocoder();

        // Add map object to base element
        this.container._googlemap = this;

        // Info window
        this.iw = new google.maps.InfoWindow({maxWidth: 300});

		this.map = map;
        this.geocoder = geocoder;
        this.loaded = true;
	},

    addMarker: function(latitude, longitude, title, info, extraOptions) {

        // Constructor options
        var latlong = new google.maps.LatLng(latitude, longitude);
        var options = {
            position: latlong,
            map: this.map,
            title: title }
        if (typeof extraOptions != "undefined") {
            $.extend(options, extraOptions);
        }

        // Marker
        var marker = new google.maps.Marker(options);

        // marker.setIcon('http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=|005522');
        // marker.setShape(google.maps.MarkerShape({coords:[2,2,1,4], type:'poly'}));
        google.maps.event.addListener(marker, 'click',
            bind(function(event) {
                this.iw.close();
                this.iw.setContent(info);
                this.iw.open(this.map, marker);
            }, this));
    }
};
