//= provide "assets"

dd.ui.Map = Class.create({
  initialize : function(element, options){
    this.element = $(element);
    this.options = Object.extend({
      height : 400,
      width: 600,
      pan : false,
      zoom : false,
      map_type :  G_PHYSICAL_MAP
    }, options||{});
    
    this.geo = {};
    this.markers = $A();
    
    this.build();
    this.map = new GMap2(this.m);
    this.map.setMapType(this.options.map_type);    
    
    if(!this.options.pan){
      this.map.disableDragging();
    }
    
    if(!this.options.zoom){
      this.map.disableDoubleClickZoom();
    }    

    GEvent.addListener(this.map, "moveend", this.onMove.bind(this));
    GEvent.addListener(this.map, "zoomend", this.onZoom.bind(this));
    this.center();    
  },
  enablePan : function(){
    this.map.enableDragging();    
  },
  disablePan : function(){
    this.map.disableDragging();    
  },
  enableZoom : function(){
    this.map.enableDoubleClickZoom();        
  },
  disableZoom : function(){
    this.map.disableDoubleClickZoom();    
  },
  build : function(){
    this.m = new Element('div', {className: 'map'}).setStyle({
      height : this.options.height+'px',
      width : this.options.width+'px'
    });
    this.element.insert(this.m);
  },
  center : function(){
    if(this.options.map_latitude && this.options.map_longitude && this.options.zoom){
      this.setCenter(this.getPoint(this.options.map_latitude, this.options.map_longitude), this.options.zoom);
    }else if(this.options.address){
      this.getLocation(this.options.address, this.options.id, function(point, zoom){
        this.setCenter(point, zoom);
        this.save();
      });
    }
  },
  getLocation : function(address, id, callback){    
    var c = callback.wrap(function(proceed, data){
      try{
        var bounds = this.getBoundsFromWOEID(data);    
        var point = bounds.getCenter();
        var zoom = this.map.getBoundsZoomLevel(bounds);
        proceed(point, zoom);
      }catch(e){}
    });
    getJSON('http://where.yahooapis.com/v1/places.q(%27'+escape(address)+'%27)?format=json&appid=0hAohbDV34FSLcpx6KAOLgTzV28ZrEc57SP1IiD2phqfyv9hr_3LoBYQkMjLlOn3oXg-&callback=?', c.bind(this));
  },
  getBoundsFromWOEID : function(data){
    var place = data.places.place[0];
    var southWest = place.boundingBox.southWest;
    var northEast = place.boundingBox.northEast;
    var bounds = new GLatLngBounds(new GLatLng(southWest.latitude, southWest.longitude), new GLatLng(northEast.latitude, northEast.longitude));
    return bounds;
  },
  getPoint : function(latitude, longitude){
    return new GLatLng(latitude, longitude, true);
  },
  setCenter : function(point, zoom){
    this.map.setCenter(point, parseInt(zoom, 10));
    this.setMapLatLong(point);
    this.setZoom(zoom);  
  },
  setMapLatLong : function(point){
    this.geo.map_lat = point.y;
    this.geo.map_long = point.x;
  },
  setZoom : function(zoom){
    this.geo.zoom = this.map.getZoom();
  },
  onMove : function(){
    this.setMapLatLong(this.map.getCenter());
  },
  onZoom : function(){
    this.setZoom();
  },
  addMarker : function(options){
    var marker = new dd.ui.Map.marker(this.map, options);
    this.markers.push(marker);
    if(options.latitude && options.longitude){
      marker.plot(this.getPoint(options.latitude, options.longitude));
    }else if(options.address){
      this.getLocation(options.address, options.id, function(point, z){
        marker.plot(point);
      });     
    }
    return marker;
  },
  addPath : function(points, options){
    var p = $A();
    var path = new dd.ui.Map.path(this.map, options);    
    var size = points.size();
    points.each(function(point, i){
      point.first = i==0;
      point.last = i==size-1;
      point.order = i;
      point.status = this.status;
      if(point.latitude && point.longitude){
        point.point = this.getPoint(point.latitude, point.longitude);
        p.push(point);        
      }else if(point.address){
        this.getLocation(options.address, options.id, function(_p, z){
          point.point = _p;
          p.push(point);
          if(p.size()==size){
            path.plot(p);
          }
        });     
      }
    }, this);
    if(p.size()==size){
      path.plot(p);
    }
    return path;
  },
  fitMapToMarkers : function(e){
    if(e) e.stop();
    if(this.markers){
      var polyline = new GPolyline(this.markers.pluck('point'), "#FF0000", 10);
      var bounds = polyline.getBounds();
      this.setCenter(bounds.getCenter(), this.map.getBoundsZoomLevel(bounds));
    }
  }
});

dd.ui.Map.path = Class.create({
  initialize : function(map, options){
    this.map = map;
    this.options = Object.extend({
      'color' : '#ff0000',
      'width' : 2
    }, options||{});    
  },
  plot : function(points){
    this.points = points.sortBy(function(point){
      return point.order;
    });
    if(!this.path){
      this.path = new GPolyline(this.points.pluck('point'), this.options.color, this.options.width);
      this.map.addOverlay(this.path);   
    }else{
      this.map.removeOverlay(this.path);
      this.path = new GPolyline(this.points.pluck('point'), this.options.color, this.options.width);
      this.map.addOverlay(this.path);
    }
  },
  push : function(options){
    var point = new GLatLng(options.latitude, options.longitude, true);
    var size = this.points.size();
    var last = this.points.last();
    if(size==0 || (last.options.latitude != options.latitude && last.longitude != options.longitude)){
      this.points.last().options.last = false;
      this.points.push({
        order: size,
        point : point,
        last : true
      });
      this.plot(this.points);
    }
  }
});

dd.ui.Map.icon = Class.create({
  initialize : function(icon, options){ 
    this.options = Object.extend({      
    }, options);
    this.options = Object.extend({
      anchorLeft : (this.options.width/2),
      anchorTop : (this.options.height/2),
      windowLeft : (this.options.width/2),
      windowTop : (this.options.height/2),
      imageMap : [0,0,this.options.width,0,this.options.width,this.options.height,0,this.options.height]
    }, this.options)
      
    this.icon = new GIcon(G_DEFAULT_ICON);  
    this.icon.image = icon;
    this.icon.iconSize = new GSize(this.options.width, this.options.height);    
    this.icon.iconAnchor = new GPoint(this.options.anchorLeft, this.options.anchorTop);
    this.icon.infoWindowAnchor = new GPoint(this.options.windowLeft, this.options.windowTop);
    this.icon.imageMap = this.options.imageMap;
    this.icon.shadow = '';
    this.icon.shadowSize = new GSize(0,0);
  }
});

dd.ui.Map.markerPositionCache = {};

dd.ui.Map.marker = Class.create({
  initialize : function(map, options){
    this.map = map;
    this.options = Object.extend({
      draggable : false,
      onDrag : Prototype.emptyFunction,
      labelClassName : 'ui-map-label',
      labelAnchor : 'left'
    }, options||{});
    
    this.markerOptions = {
      draggable : this.options.draggable
    };
    
    if(this.options.label){
      this.label = new Element('div').setStyle({
        'position' : 'absolute'
      }).update(new Element('div', {'className' : this.options.labelClassName}).update(this.options.label));
    }
    
    
    if(this.options.icon && this.options.icon.icon){      
      // console.log(this.options.icon.icon);
      this.markerOptions.icon = this.options.icon.icon;
    }
    
    this.map.getPane(G_MAP_MARKER_PANE).appendChild(this.label);
    
  },
  plot : function(point){ 
    this.point = point;
    if(!this.marker){   
      this.marker = new GMarker(point, this.markerOptions);
      this.map.addOverlay(this.marker);      
      // GEvent.addListener(this.marker, "click", function() {
      //    this.marker.openInfoWindowHtml('<p>Hello</p>');
      // }.bind(this));      
    }else{
      this.marker.setLatLng(point) 
    }
    
    if(this.label){
      var position = this.map.fromLatLngToDivPixel(this.point);
      var dimensions = this.label.getDimensions();
      var m = this.marker.getIcon().iconSize;
      var a = this.marker.getIcon().iconAnchor;
            
      if(this.options.labelAnchor=='right'){      
        var t = position.y-(m.height/2)-(dimensions.height/2)+a.y;
        var l = position.x-(m.width/2)-(dimensions.width);        
      }else if(this.options.labelAnchor=='left'){        
        var t = position.y-(m.height/2)-(dimensions.height/2)+a.y;
        var l = position.x+(m.width/2);        
      }
                 
      var g = new dd.Region(t, l+dimensions.width, t+dimensions.height, l);
        
      window.markerRegions = window.markerRegions||$H();
      window.markerRegions.unset(this.label.identify());
        
      var n = window.markerRegions.find(function(_r){
        return g.intersect(_r[1]);
      });
        
      if(n){
        this.options.labelAnchor = (this.options.labelAnchor=='right') ? 'left' : 'right';
        if(this.options.labelAnchor=='right'){      
          var t = position.y-(m.height/2)-(dimensions.height/2)+a.y;
          var l = position.x-(m.width/2)-(dimensions.width);        
        }else if(this.options.labelAnchor=='left'){        
          var t = position.y-(m.height/2)-(dimensions.height/2)+a.y;
          var l = position.x+(m.width/2);        
        }           
        g.update(t, l+dimensions.width, t+dimensions.height, l);
      }
      
      this.label.setStyle({
        'left' : l+'px',
        'top' : t+'px'
      });
                
      window.markerRegions.set(this.label.identify(), g);

    } 
  },
  update : function(options){
    this.plot(new GLatLng(options.latitude, options.longitude, true));
  },
  show : function(){
    this.marker.show();
    if(this.label){
      this.label.show();
    }
  },
  hide : function(){
    this.marker.hide();
    if(this.label){
      this.label.hide();
    }
  },
  toggle : function(){
    if(this.marker.isHidden()){
      this.show();
    }else{
      this.hide();
    }    
  }
});

dd.Region = Class.create({
  initialize : function(t, r, b, l){
    this.cache = {};
    this.update(t, r, b, l);
  },
  update : function(t, r, b, l){
    this.top = t;
    this.right = r;
    this.bottom = b;
    this.left = l;
  },
  contains : function(x, y){
    return (x >= this.left && x <= this.right && y >= this.top && y <= this.bottom);
  },
  intersect : function(region){
    var t = Math.max(this.top, region.top);
    var r = Math.min(this.right, region.right);
    var b = Math.min(this.bottom, region.bottom);
    var l = Math.max(this.left, region.left);    
    if(b >= t && r >= l){
        return new dd.Region(t, r, b, l);
    } else {
        return false;
    }
  }
});