/***

MochiKit.Maps__Google 0.2

See <http://mochikit.com/> for documentation, downloads, license, etc.

(c) 2007 Schmap ltd.  All rights Reserved.

***/

if (typeof(dojo) != 'undefined') {
    dojo.provide('MochiKit.Maps__Google');
}

if (typeof(MochiKit) == 'undefined') {
    MochiKit = {};
}

if (typeof(MochiKit.Maps__Google) == 'undefined') {
    MochiKit.Maps__Google = {};
}

if (typeof(MochiKit.Maps) == 'undefined') {
    // provide default implementation
    MochiKit.Maps = MochiKit.Maps__Google;
}

MochiKit.Maps__Google.NAME = "MochiKit.Maps__Google";
MochiKit.Maps__Google.VERSION = "0.2";
MochiKit.Maps__Google.__repr__ = function () {
    return "[" + this.NAME + " " + this.VERSION + "]";
};
MochiKit.Maps__Google.toString = function () {
    return this.__repr__();
};

MochiKit.Maps__Google.Map = function(element) {
    this.element = $(element);
    this.provider = 'dg';
    this.gmap = new GMap2(this.element);
    this.gmap.disableInfoWindow();
    this.gmap.enableDoubleClickZoom();
    this.gmap.enableContinuousZoom();
    this.gmap.enableScrollWheelZoom();
    this._gevents = {};
    var mt = this.gmap.getMapTypes();
    this._mt = {};
    
    // The following hardcodes the view order, and assumes it won't change in Google. Not great, but we can't rely on the
    // words 'Map', 'Satellite' and 'Hybrid' to match as before, since this causes problems in a multi-language solution
    // (configuring the words in the foreign language doesn't work, as there seems to be some variance based on Browser
    // maybe as to whether Google serves the foreign language or English version!)
    var mtTypes = ['Map', 'Satellite', 'Hybrid'];
    
    for(var i = 0; i < mt.length; i++)
    {
        this._mt[mtTypes[i]] = mt[i];
    }
};

MochiKit.Maps__Google.Map.prototype.__repr__ = function () {
    return "[Map at " + this.element.id + "]";
};

MochiKit.Maps__Google.Map.prototype._maxZoom = 17;

MochiKit.Maps__Google.Map.prototype.setDisplay = function(point, zoom) {
    if(zoom > 1) {
        logWarning('please correct your setDisplay calls to use a number from 0 to 1');
        zoom /= this._maxZoom   ;
    }
    var gzoom = Math.round(zoom * this._maxZoom);
    if(point instanceof GLatLng) {
        this.gmap.setCenter(point, gzoom);
    } else {
        this.gmap.setCenter(point.gmap, gzoom);
    }
};

MochiKit.Maps__Google.Map.prototype.zoomIn = function() {
        this.gmap.zoomIn();
};

MochiKit.Maps__Google.Map.prototype.zoomOut = function() {
    this.gmap.zoomOut();
};

MochiKit.Maps__Google.Map.prototype.zoomTo = function(level) {
    this.gmap.setZoom(Math.round(level * this._maxZoom));
};

MochiKit.Maps__Google.Map.prototype.getZoom = function() {
    return this.gmap.getZoom() / this._maxZoom;
};

MochiKit.Maps__Google.Map.prototype.zoomToBounds = function(bounds) {
    var zoom = this.gmap.getBoundsZoomLevel(bounds.gmap);
    this.gmap.setCenter(bounds.getCenter().gmap, zoom);
};

MochiKit.Maps__Google.Map.prototype.getBounds = function() {
    var gbounds = this.gmap.getBounds();
    var sw = gbounds.getSouthWest();
    var ne = gbounds.getNorthEast();
    return new MochiKit.Maps__Google.Bounds(sw.lat(), sw.lng(), ne.lat(), ne.lng());
};

MochiKit.Maps__Google.Map.prototype.setMapType = function(maptype) {
    if(this._mt[maptype])
        this.gmap.setMapType(this._mt[maptype]);
};

MochiKit.Maps__Google.Map.prototype.__connect__ =
    function(ident, signal, objOrFunc, funcOrStr) {
    gob = this.gmap || this;
    var evt = new MochiKit.Maps__Google.Event(signal, this, ident);
    ident.gHandle = GEvent.bind(gob, signal, evt, evt.signal);
}

MochiKit.Maps__Google.Map.prototype.__disconnect__ = function(ident) {
    if(!ident.gHandle) return;
    GEvent.removeListener(ident.gHandle);
};

MochiKit.Maps__Google.Map.prototype.listen = function(events) {
    logWarning('Map.listen is deprecated');
};

MochiKit.Maps__Google.Map.prototype.unlisten = function(events) {
    logWarning('Map.unlisten is deprecated');
};

MochiKit.Maps__Google.Map.prototype.addItem = function(item) {
    if(item.gmap !== undefined)
        this.gmap.addOverlay(item.gmap);
    else
        this.gmap.addOverlay(item);
};

MochiKit.Maps__Google.Map.prototype.getMapElement = function() {
    var imgs = this.element.getElementsByTagName('img');
    for(var i = 0; i < imgs.length; i++) {
        if(imgs[i].src.match(/mt\d+\.google\./))
            break;
    }
    if(i == imgs.length) // not initialized
        return null;
    // XXX: check in other browsers
    return imgs[i].parentNode.parentNode.parentNode;
};

MochiKit.Maps__Google.Map.prototype.convert = function(item) {
    me = this.getMapElement();
    if(!me) // not initialized
        return null;
    var c = MochiKit.Style.getElementPosition(me);
    if(item instanceof MochiKit.Maps__Google.Point) {
        // convert to MochiKit.Style.Coordinates
        var p = this.gmap.fromLatLngToDivPixel(item.gmap);
        c.x += p.x;
        c.y += p.y;
        return c;
    } else if(item instanceof MochiKit.Style.Coordinates) {
        // convert to MochiKit.Maps__Google.Point
        var gp = new GPoint(item.x - c.y, item.y - c.y);
        return new MochiKit.Maps__Google.Point(
          this.gmap.fromDivPixelToLatLng(gp));
    } else if(item instanceof MochiKit.Maps__Google.Bounds) {
        // convert to [MochiKit.Style.Coordinates, MochiKit.Style.Dimensions]
        var d = new MochiKit.Style.Dimensions;
        var p1 = this.gmap.fromLatLngToDivPixel(item.gmap.getSouthWest());
        var p2 = this.gmap.fromLatLngToDivPixel(item.gmap.getNorthEast());
        c.x += p1.x;
        c.y += p2.y;
        d.w = p2.x - p1.x;
        d.h = p1.y - p2.y;
        return [c, d];

        // [new MochiKit.Style.Coordinates(160, 257), new MochiKit.Style.Dimensions(213, 394)]
    } else if((item.length == 2) &&
              (item[0] instanceof MochiKit.Style.Coordinates) &&
              (item[1] instanceof MochiKit.Style.Dimensions)) {
        // convert to MochiKit.Maps__Google.Bounds
        var gp = new GPoint(item[0].x - c.x, item[0].y - c.y);
        var nw = this.gmap.fromDivPixelToLatLng(gp);
        gp = new GPoint(item[0].x + item[1].w - c.x, item[0].y + item[1].w - c.y);
        var se = this.gmap.fromDivPixelToLatLng(gp);
        return new MochiKit.Maps__Google.Bounds(se.lat(), nw.lng(),
                                                nw.lat(), se.lng());
    } else {
        logWarning('Map.convert: unknown argument');
        return undefined;
    }
};

MochiKit.Maps__Google.Map.prototype.hideAll = function(hide) {
    var pane = this.gmap.getPane(G_MAP_MARKER_PANE);
    if(pane) {
	    //var temValue = hide.replace(/(0|no|false)/,'');
		var temValue = Boolean(hide);
        setStyle(pane, {visibility: temValue ? 'hidden' : 'visible'});
    }
};

MochiKit.Maps__Google.Map.prototype.customOverLay = function (item) {
       var temDiv = this.divName
       $(temDiv).appendChild(this.mydiv);
       var temPos = getElementPosition(temDiv);
       var pos = this.convert(item);
       MochiKit.Style.setElementPosition(this.mydiv,{x:pos[0].x - temPos.x,y:pos[0].y - temPos.y});
       MochiKit.Style.setElementDimensions(this.mydiv,pos[1]);
} ;

MochiKit.Maps__Google.Map.prototype.getCustomZoom = function (item) {
    if(item instanceof MochiKit.Maps__Google.Bounds) {
        var zoom = this.gmap.getBoundsZoomLevel(item.gmap) ;
        return zoom +1 ;
    }

} ;

MochiKit.Maps__Google.Map.prototype.draggableMarker = function (item) {
     logDebug("this function is deprecated as bad implementation");
     var center = new GLatLng(item[0], item[1]);
     var baseIcon = new GIcon();
     baseIcon.iconSize = new GSize(this.OverIconSize[0], this.OverIconSize[1]);
     baseIcon.iconAnchor = new GPoint(10, 28);
     var icon = new GIcon(baseIcon);
     icon.image = this.image.toString();
     this.gmap.setCenter(center, 16);
     var marker = new GMarker(center, {draggable:true,icon:icon});
     this.marker = marker;
     this.gmap.addOverlay(marker);

} ;
MochiKit.Maps__Google.Map.prototype.disableEvent = function () {
    this.gmap.disableDragging()
    this.gmap.disableInfoWindow();
    this.gmap.disableDoubleClickZoom();
    this.gmap.disableContinuousZoom();
    this.gmap.disableScrollWheelZoom();
 } ;


MochiKit.Maps__Google.DraggableMarker = function (
        latlng, size, anchor, img) {
    var center = new GLatLng(latlng[0], latlng[1]);
    if(img) {
        var icon = new GIcon();
        icon.iconSize = new GSize(size[0], size[1]);
        icon.iconAnchor = new GPoint(anchor[0], anchor[1]);
        this.gmap = new GMarker(center, {draggable: true, icon: icon});
    } else {
        this.gmap = new GMarker(center, {draggable: true});
    }

    //GEvent.addListener(this.gmap, "dragend", function() {
    //        alert('aa');
    //});
}

MochiKit.Maps__Google.DraggableMarker.prototype.register = function (
        evt, func) {
    logDebug("register " + evt + "");
    GEvent.addListener(this.gmap, evt, func);
}

MochiKit.Maps__Google.DraggableMarker.prototype.getPoint = function () {
    return this.gmap.getPoint();
}

MochiKit.Maps__Google.Event = function(evtype, target, ident) {
    this._type = evtype;
    this._target = target;
    this._ident = ident;
};

MochiKit.Maps__Google.Event.prototype.__repr__ = function () {
    return "[Event " + this._type + ' on ' + this._target.__repr__() + "]";
};

MochiKit.Maps__Google.Event.prototype.type = function() {
    return this._type;
};

MochiKit.Maps__Google.Event.prototype.target = function() {
    return this._target;
};

MochiKit.Maps__Google.Event.prototype.signal = function() {
    if(this._ident !== undefined) {
        var connected = this._ident.connected || this._ident[6];
        if(!connected) {
            // work around MochiKit.Signal not having __disconnect__ (yet?)
            this._target.__disconnect__(this._ident);
            return;
        }
    }
    MochiKit.Signal.signal(this._target, this._type, this);
};

MochiKit.Maps__Google.Point = function(lat, lon) {
    if((lat instanceof GLatLng) && (lon === undefined)) {
        this.gmap = lat;
        this.latitude = this.gmap.lat();
        this.longitude = this.gmap.lng();
    } else {
        this.latitude = lat;
        this.longitude = lon;
        this.gmap = new GLatLng(this.latitude, this.longitude);
    }
};

MochiKit.Maps__Google.Point.prototype.__repr__ = function () {
    return "[Map Point at " + this.latitude + ',' + this.longitude + "]";
};

MochiKit.Maps__Google.Bounds = function(south, west, north, east) {
    if((south==null)||(west==null)||(north==null)||(east==null)) {
        //alert(((null,null),(null,null)));
        this.gmap = ((null,null),(null,null));
    } else {
        this.west = west;
        this.south = south;
        this.east = east;
        this.north = north;
        this.gmap = new GLatLngBounds(new GLatLng(this.south, this.west),
                                      new GLatLng(this.north, this.east));
    }
};

MochiKit.Maps__Google.Bounds.fromGeoRSS = function(georss) {
    // extract from xml node
    //  alert(georss);
    if(georss.textContent && georss.nodeName &&
       georss.nodeName.match(/box$/))
        georss = georss.textContent;
    // extract from rss triple
    else if(georss.object)
        georss = georss.object;
    var box = map(Number, georss.split(/ /));
    return new MochiKit.Maps__Google.Bounds(box[0], box[1], box[2], box[3]);
};

MochiKit.Maps__Google.Bounds.prototype.getCenter = function() {
    return new MochiKit.Maps__Google.Point((this.north + this.south) / 2,
                                   (this.west + this.east) / 2);
};

MochiKit.Maps__Google.Bounds.prototype.contains = function(point) {
    return (point.longitude >= this.west) && (point.longitude <= this.east) &&
           (point.latitude >= this.south) && (point.latitude <= this.north);
};

MochiKit.Maps__Google.Bounds.prototype.getWidth = function() {
    return Math.abs(this.east - this.west);
};

MochiKit.Maps__Google.Bounds.prototype.getHeight = function() {
    return Math.abs(this.north - this.south);
};

MochiKit.Maps__Google.Bounds.prototype.metersAtSouth = function() {
//    var earthRadius = 6378137 * Math.abs(Math.cos(this.south));
//    return earthRadius * Math.PI * this.getWidth() / 180;

    var convertToRadsFactor = 180 / Math.PI;
    var sinLat1 = Math.sin (this.south / convertToRadsFactor);
    var cosLat1 = Math.cos (this.south / convertToRadsFactor);
    var long1Rad = this.west / convertToRadsFactor;
    var long2Rad = this.east / convertToRadsFactor;
    var cosLongDiff = Math.cos (long2Rad - long1Rad);

    var l_dist = 6378137 * Math.acos((sinLat1 * sinLat1) + 
				        (cosLat1 * cosLat1 * cosLongDiff));
    return l_dist;
};

MochiKit.Maps__Google.Icon = function(url, dimensions, anchor) {
    this.image = url;
    this.dimensions = dimensions;
    this.anchor = anchor;
    this.gmap = new GIcon();
    this.gmap.image = this.image;
    this.gmap.iconSize = new GSize(this.dimensions.w, this.dimensions.h);
    this.gmap.iconAnchor = new GPoint(this.anchor.x, this.anchor.y);
};

//MochiKit.Maps__Google._GMarker = function(gpoint, gicon) {
//};

MochiKit.Maps__Google.Marker = function(point, icon) {
    this._m_point = point;
    this._m_icon = icon;
    GMarker.call(this, point.gmap, icon.gmap);
    this._m_imgAttr = null;
    //this.gmap = new GMarker(point.gmap, icon.gmap);
    this._gevents = {};
};

MochiKit.Maps__Google.Marker.prototype = new GMarker(new GLatLng());

MochiKit.Maps__Google.Marker.prototype.__repr__ = function () {
    return "[Marker at " + repr(this._m_point) + "]";
};

MochiKit.Maps__Google.Marker.prototype.reposition = function(point) {
    this.setLatLng(point.gmap);
};

MochiKit.Maps__Google.Marker.prototype.reposition = function(point) {
    this.setLatLng(point.gmap);
};

/*
MochiKit.Maps__Google.Marker.prototype.show = function() {
    this.gmap.show();
};

MochiKit.Maps__Google.Marker.prototype.hide = function() {
    this.gmap.hide();
};
*/
MochiKit.Maps__Google.Map.prototype.actualBoundsFromIdealBounds = function (bounds)
{
    return (bounds);
}
MochiKit.Maps__Google.Marker.prototype.initialize = function(map) {
    GMarker.prototype.initialize.call(this, map);
    nulls = 0;
    try {
    for(k in this) {
        if(this[k] && this[k].tagName)
            this._m_imgAttr = k;
    }
    } catch(e) {}
};

MochiKit.Maps__Google.Marker.prototype.redraw = function(force) {
    GMarker.prototype.redraw.call(this, force);
    if(this._m_imgAttr) {
        var img = this[this._m_imgAttr];
        img.style.zIndex = 0;
    }
};
MochiKit.Maps__Google.Marker.prototype.getElement = function() {
    if(this._m_imgAttr) {
        return this[this._m_imgAttr];
    }
};
MochiKit.Maps__Google.Marker.prototype.__connect__ = MochiKit.Maps__Google.Map.prototype.__connect__;
MochiKit.Maps__Google.Marker.prototype.__disconnect__ = MochiKit.Maps__Google.Map.prototype.__disconnect__;

MochiKit.Maps__Google.Marker.prototype.listen = function(events) {
    logWarning('Marker.listen is deprecated');
};

MochiKit.Maps__Google.Marker.prototype.unlisten = function() {
    logWarning('Marker.unlisten is deprecated');
};

MochiKit.Signal.signal(window, "MochiMaps-load", MochiKit.Maps__Google);
