Cardtastic = {};

Cardtastic.Stockist = function(longitude, latitude, name, html)
{
    this.lon  = longitude;
    this.lat  = latitude;
    this.name = name;
    this.html = html;
};

Cardtastic.Stockists = function(mapElement, resultsElement, initialPosition)
{
    this.debugEnabled   = true;

    this.resultsElement = resultsElement;
    this.markers        = new Array();
    this.map            = new google.maps.Map2(mapElement);
    this.geocoder       = new google.maps.ClientGeocoder();

    this.geocoder.setBaseCountryCode('GB'); // great britain

    this.map.addControl(new google.maps.LargeMapControl());
    this.map.addControl(new google.maps.MapTypeControl());
    this.map.addControl(new google.maps.OverviewMapControl());
    this.map.setCenter(new google.maps.LatLng(initialPosition.lat, initialPosition.lon), initialPosition.zoom);

    this.markerManager = new MarkerManager(this.map);

    this.createSearchCenterMarker = function()
    {
        var icon = new google.maps.Icon(G_DEFAULT_ICON);
        icon.image = "/media/images/icons/maps/icong.png";
        var marker = new google.maps.Marker(new google.maps.LatLng(0, 0), {"icon": icon, "title": "Search Center"});
        marker.hide();
        this.map.addOverlay(marker);
        return marker;
    }

    this.searchCenterMarker = this.createSearchCenterMarker();

    this.createMarker = function(stockist)
    {
        var point  = new google.maps.LatLng(stockist.lat, stockist.lon);
        var marker = new google.maps.Marker(point, {"title": stockist.name});
        google.maps.Event.addListener(marker, "click", function()
        {
            marker.openInfoWindowHtml(stockist.html);
        });
        return marker;
    };

    this.addStockists = function(stockists)
    {
        var m = new Array();
        for (var i in stockists) {
            var stockist = stockists[i];
            var marker = this.createMarker(stockist);
            this.markers.push({"marker": marker, "stockist": stockist});
            m.push(marker);
        }
        this.markerManager.addMarkers(m, 0);
        this.markerManager.refresh();
    };

    this.showLocation = function(address)
    {
        this.geocoder.getLocations(address, google.maps.Event.callback(this, _addAddressToMap));
    };

    this.clickMarker = function(marker)
    {
        var markerLatLng = marker.getLatLng();
        var mapBounds = this.map.getBounds();
        var showMarker = function()
        {
            google.maps.Event.trigger(marker, "click");
        };
        if (mapBounds.containsLatLng(markerLatLng) == false) {
            this.map.panTo(markerLatLng);
            /*
             * We can't call click on a marker that isn't there...
             *
             * The following is a hack to call the 'click' function on the marker
             * shortly after the map has been centered on the marker, this is
             * needed because the marker doesn't exist on the map until the marker
             * manager has added it.
             */
            setTimeout(showMarker, 10);
        } else {
            showMarker();
        }
        return false;
    };

    this.showClosest = function(place, point, distances)
    {
        document.getElementById('address').value = place.address;
        var heading = document.createElement('h3');
        heading.appendChild(document.createTextNode('Stockists closest to ' + place.address));
        var list = document.createElement('ol');
        var bounds = new google.maps.LatLngBounds();
        for (var i = 0; i < Math.min(distances.length, 10); i++) {
            var marker       = this.markers[distances[i].markerIndex].marker;
            var stockist     = this.markers[distances[i].markerIndex].stockist;
            var distance     = distances[i].distance;
            var km           = (Math.round(distance / 100)) / 10;
            var item         = document.createElement('li');
            var link         = document.createElement('a');
            var linkText     = document.createTextNode(stockist.name);
            var distanceText = document.createTextNode(' (' + String(km) + 'km)');
            link.setAttribute('href', '#');
            link.onclick = google.maps.Event.callbackArgs(this, this.clickMarker, marker);
            link.appendChild(linkText)
            item.appendChild(link);
            item.appendChild(distanceText);
            list.appendChild(item);
            _debug(item);
            bounds.extend(marker.getLatLng());
        }
        //var zoom = this.map.getBoundsZoomLevel(bounds);
        //this.map.setZoom(zoom);
        //this.map.setCenter(bounds.getCenter());
        this.map.setCenter(point);
        while (this.resultsElement.firstChild) {
            this.resultsElement.removeChild(this.resultsElement.firstChild);
        };
        this.resultsElement.appendChild(heading);
        this.resultsElement.appendChild(list);
    }

    var _debug = function(msg)
    {
        if (this.debugEnabled == true) {
            google.maps.Log.write(msg);
        }
    };

    var _addAddressToMap = function(response)
    {
        if (!response || response.Status.code != 200) {
            alert("Sorry, we were unable to find that address");
        } else {
            //for (var p = 0; p < response.Placemark.length; p++) {
            //    alert(response.Placemark[p].address);
            //}

            place = response.Placemark[0];
            point = new google.maps.LatLng(
                place.Point.coordinates[1],
                place.Point.coordinates[0]
            );

            this.searchCenterMarker.setLatLng(point);
            this.searchCenterMarker.show();

            var distances       = new Array();
            var closestDistance = null;
            var closestMarker   = null;

            for (var i = 0; i < this.markers.length; i++) {
                var marker   = this.markers[i].marker;
                var distance = point.distanceFrom(marker.getLatLng());
                distances.push({'distance': distance, 'markerIndex': i});
            }
            distances.sort(function(a, b)
            {
                return a.distance - b.distance;
            });
            this.showClosest(place, point, distances);
            //this.map.panTo(point);
        }
    };
}