(function($) {
  $.fn.gMap = function(performDefaultConfig) {
    var performDefaultConfig = typeof(performDefaultConfig) != 'undefined' ? performDefaultConfig : false;
    var $this = this;

    if (performDefaultConfig) {
      $($.fn.gMap.defaults.onLoadCallbacks).each(function() {
        $this.onGmapLoad(this);
      });

      $this.center()
           .controls({add: $.fn.gMap.defaults.controls})
           .overlays({add: $.fn.gMap.defaults.overlays});
    }

    return this;
  };

  $.fn.gMap.defaults = {
    lat: 51.32,
    lng: 0.5,
    zoom: 6,
    overlays: [],
    controls: [],
    onLoadCallbacks: [],
    maxZoom: 16,
    minZoom: 0
  };

  $.fn.gMap.icons = {};
  $.fn.gMap.advertTypes = ['owner','grower','helper'];
  for(var i in $.fn.gMap.advertTypes){
    var advertType = $.fn.gMap.advertTypes[i];
    $.fn.gMap.icons[advertType] = new GIcon();
    $.fn.gMap.icons[advertType].image = '/images/map-marker-' + advertType + '.png';
    $.fn.gMap.icons[advertType].iconAnchor = new GPoint(13, 12);
    $.fn.gMap.icons[advertType].iconSize = new GSize(26, 24);
    $.fn.gMap.icons[advertType].infoWindowAnchor = new GPoint(33, 82);
  }
  $.fn.gMap.areaTypes = ['14x14','21x21','29x29','44x44'];
  $.each($.fn.gMap.areaTypes, function() {
    $.fn.gMap.icons[this] = new GIcon();
    $.fn.gMap.icons[this].image = '/images/map-marker-area-' + this + '.png';
  });

  $.fn.gMap.icons['14x14'].iconSize         = new GSize(14, 14);
  $.fn.gMap.icons['14x14'].iconAnchor       = new GPoint(9, 25);
  $.fn.gMap.icons['14x14'].infoWindowAnchor = new GPoint(36, 98);

  $.fn.gMap.icons['21x21'].iconSize         = new GSize(21, 21);
  $.fn.gMap.icons['21x21'].iconAnchor       = new GPoint(9, 25);
  $.fn.gMap.icons['21x21'].infoWindowAnchor = new GPoint(31, 96);

  $.fn.gMap.icons['29x29'].iconSize         = new GSize(29, 29);
  $.fn.gMap.icons['29x29'].iconAnchor       = new GPoint(9, 25);
  $.fn.gMap.icons['29x29'].infoWindowAnchor = new GPoint(27, 93);

  $.fn.gMap.icons['44x44'].iconSize         = new GSize(44, 44);
  $.fn.gMap.icons['44x44'].iconAnchor       = new GPoint(23, 58);
  $.fn.gMap.icons['44x44'].infoWindowAnchor = new GPoint(35, 116);

  $.fn.center = function(options) {
    var opts = updateOptions(options);

    return this.each(function() {
      if (opts.lat && opts.lng) {
        map(this).setCenter(new GLatLng(opts.lat, opts.lng), opts.zoom);
      } else {
        map(this).getCenter();
      };
    });
  };

  $.fn.controls = function(options) {
    if (!options) return this;

    var validActions = [ 'add', 'remove' ];

    return this.each(function(i, el) {
      $.each(validActions, function(j, action) {
        $(options[action]).each(function(k, control) {
          map(el)[action + 'Control'](control);
        });
      });
    });
  };

  $.fn.overlays = function(options) {
    if (!options) return this;

    var validActions = [ 'add', 'remove' ];

    return this.each(function(i, el) {
      $.each(validActions, function(j, action) {
        $(options[action]).each(function(k, overlay) {
          map(el)[action + 'Overlay'](overlay);
        });
      });
    });
  };

  $.fn.applyToEach = function(func) {
    return this.each(function() {
      func.apply(map(this));
    });
  };

  $.fn.onDragEnd = function(callback) {
    return this.addGmapEvent('dragend', callback);
  };

  $.fn.onZoom = function(callback) {
    return this.addGmapEvent('zoomend', callback);
  };

  $.fn.onGmapLoad = function(callback) {
    return this.addGmapEvent('load', callback);
  };

  $.fn.addGmapEvent = function(eType, callback) {
    return this.each(function() {
      GEvent.addListener(map(this), eType, callback);
    });
  };
  //
  // GMarker.prototype.openCustomInfoWindow = function(html, advertType){
  //   $('#gMap div.info-window').remove();
  //   var gOverlay = new GOverlay();
  //   gOverlay.initialize(map('#gMap'), this, html, advertType);
  // };

  GMarker.prototype.openCustomInfoWindow = function(marker, html, advertType) {
    $('#gMap div.info-window').remove();
    var gOverlay = new LandshareOverlay(marker, html, advertType);
    map('#gMap').addOverlay(gOverlay);
  };

  var LandshareOverlay = function(marker, html, advertType) {
    this.marker = marker;
    this.html = html;
    this.advertType = advertType;
  }
  LandshareOverlay.prototype = new GOverlay();
  LandshareOverlay.prototype.initialize = function(map) {
    this.map = map;

    this.div = $('<div class="info-window info-window-' + this.advertType + '"><div class="content">' + this.html + '</div></div>');
    var markerPoint = this.map.fromLatLngToDivPixel(this.marker.getLatLng());
    this.div.css({
      left: markerPoint.x - this.marker.getIcon().infoWindowAnchor.x,
      top:  markerPoint.y - this.marker.getIcon().infoWindowAnchor.y
    });

    $(map.getPane(G_MAP_FLOAT_PANE)).append(this.div);
    $(map.getPane(G_MAP_FLOAT_PANE)).click(function(self) {
      return function(){$(self.div).remove();}
    }(this));
  };
  LandshareOverlay.prototype.remove = function() {};
  LandshareOverlay.prototype.redraw = function() {};

  //
  // GOverlay.prototype.initialize = function(gMap, gMarker, html, advertType){
  //   this.gMap = gMap;
  //   this.gMarker = gMarker;
  //
  //   var $_infoWindow
  //       = this.$infoWindow
  //       = $('<div class="info-window info-window-' + advertType + '"><div class="content">' + html + '</div></div>');
  //   $(gMap.getPane(G_MAP_FLOAT_PANE)).append(this.$infoWindow);
  //     // http://code.google.com/apis/maps/documentation/reference.html#GMapPane
  //   this.redraw();
  //
  //   $(gMap.getPane(G_MAP_FLOAT_PANE)).click(function(){
  //     $_infoWindow.hide();
  //   });
  // };
  // GOverlay.prototype.redraw = function(){
  //   var infoWindowAnchor = [33, 116],
  //       markerPoint = this.gMap.fromLatLngToDivPixel(this.gMarker.getLatLng());
  //   this.$infoWindow.css({
  //     left: markerPoint.x - this.gMarker.getIcon().infoWindowAnchor.x,
  //     top:  markerPoint.y - this.gMarker.getIcon().infoWindowAnchor.y
  //   });
  // };

  // Private //
  function init(el, options) {
    var newMap = new GMap2(el),
        mapTypes = newMap.getMapTypes(),
        maxResFn = function(){ return $.fn.gMap.defaults.maxZoom; },
        minResFn = function(){ return $.fn.gMap.defaults.minZoom; };
    for(var i=mapTypes.length-1; i>0; i--){
      mapTypes[i].getMaximumResolution = maxResFn;
      mapTypes[i].getMinimumResolution = minResFn;
    }
    G_NORMAL_MAP.getMaximumResolution = maxResFn;
    G_NORMAL_MAP.getMinimumResolution = minResFn;
    maps[$(el).attr('id')] = newMap;
    return newMap;
  }

  var maps = {};
  function map(el) {
    return maps[$(el).attr('id')] ? maps[$(el).attr('id')] : init(el);
  }

  function updateOptions(opts) {
    return $.extend($.fn.gMap.defaults, opts);
  }
})(jQuery);

GMap2.prototype.withinBoundsUrl = function() {
  return '/' + $.grep([ 'listings',
    this.advertTypePath(), 'within',
    this.sw(), this.ne(), 'map'], function(n) {
     return n != null;
    }).join('/');
};

GMap2.prototype.sw = function() {
  return this.getBounds().getSouthWest().toUrlValue();
}

GMap2.prototype.ne = function() {
  return this.getBounds().getNorthEast().toUrlValue();
}

GMap2.prototype.advertTypePath = function() {
  return function(type) {
    return type && type != 'all' ? 'type/' + type : null;
  }($.fn.gMap.advert_type);
};

LandshareMap = function(map, advert_type) {
  this.map = map;
  this.advert_type =
    this.zoomLevel() >= $.fn.gMap.defaults.listingsZoomLevel ? advert_type : null;
};
LandshareMap.prototype = {
  // getData: function(returnTo) {
  //   $this = this;
  //   $.getJSON(this.url(), function(data) {
  //     $this._data = data;
  //     returnTo.apply($this);
  //   });
  // },
  // adverts: function() {
  //   if (this._data == null) {
  //     this.getData(LandshareMap.prototype.adverts);
  //     return;
  //   };
  //
  //   return $.map(this._data, function(ob) {
  //     return ob['advert'];
  //   })
  // },

  mapUrl: function() {
    return '/' + $.grep([ 'listings',
      this.advertPath(), 'within',
      this.sw(), this.ne(), this.zoomLevel(), 'map'], function(n) {
       return n != null;
      }).join('/');
  },
  listingsUrl: function() {
    return '/' + $.grep([ 'listings',
      this.advertPath(), 'within',
      this.sw(), this.ne() ], function(n) {
       return n != null;
    }).join('/');
  },
  sw: function() {
    return this.map.getBounds().getSouthWest().toUrlValue();
  },
  ne: function() {
    return this.map.getBounds().getNorthEast().toUrlValue();
  },
  zoomLevel: function() {
    return this.map.getZoom();
  },
  advertPath: function() {
    return function(type) {
      return type && type != 'all' ? 'type/' + type : null;
    }(this.advert_type);
  }
};

LandshareMapMarker = function(type, ob) {
  this.type = type;
  this.ob = ob;

  this.marker = new GMarker(
    new GLatLng(ob.lat, ob.lng),
    this.icon()
  );
  GEvent.addListener(this.marker, 'click',
    this[this.type + 'InfoWindow'](this.marker, this.ob));
};
LandshareMapMarker.prototype = {
  icon: function() {
    return $.fn.gMap.icons[this.type == 'advert' ? this.ob.advert_type : this.ob.icon];
  },
  advertInfoWindow: function(marker, advert) {
    return function() {
      var advertURL = '/listings/' + advert.id;
      this.openCustomInfoWindow(marker,
        '<h3><a href="' + advertURL + '">' + advert.title + '</a></h3>' +
        '<p><a href="' + advertURL + '">' + advert.map_description + '</a></p>',
        advert.advert_type
      );
    };
  },
  areaInfoWindow: function(marker, area) {
    return function() {
      var zoom = '';
      switch(area.area_type){
        case 'OutCode':
          zoom = '13';
          break;
        case 'City':
          zoom = '10';
          break;
        case 'County':
          zoom = '8';
          break;
        default:
          zoom = '13';
      }
      var url = '<h3><a href="/listings/map?q=' + area.name + '&zoom=' + zoom + '">' + area.name + '</a></h3>'
      this.openCustomInfoWindow(marker,
        url +
        '<p>' + area.owner_count +' Landowners, ' +
        area.grower_count + ' Growers, '+
        area.helper_count +' Helpers</p>', 'area'
      );
    };
  }
};

GMap2.prototype.getPoints = function() {
  var landshareMap = new LandshareMap(this, $.fn.gMap.advert_type);

  $.getJSON(landshareMap.mapUrl(), function(data) {
    var points = $.map(data, function(ob, i) {
      var advert_type = ob['advert_type'];
      landshareMap.advert_type = ob['advert_type'];

      var advert = ob['advert'];
      if(advert){
        var landshareMarker = new LandshareMapMarker('advert', advert);
        return landshareMarker.marker;
      }

      var area = ob['area'];
      if (area) {
        var landshareMarker = new LandshareMapMarker('area', area);
        return landshareMarker.marker;
      };

      var counts = ob['counts'];
      if (counts) {
        $('li#owner-count span.count').text(counts['owner']);
        $('li#grower-count span.count').text(counts['grower']);
        $('li#helper-count span.count').text(counts['helper']);
      };

      $('a#list-url').attr('href', landshareMap.listingsUrl());
    });

    landshareMap.map.clearOverlays();
    $('#gMap').gMap().overlays({add : points});

    var map_type = $.grep(data, function(a){
      return a['map_type'];
    })[0].map_type;

    $('ul#advert-type-nav')[(map_type == 'listings' ? 'show' : 'hide')]();

    var h = $.grep(data, function(a){
      return a['hidden'];
    });

    if (h.length > 0) {
      var count = h[0]['hidden'];
      if(count > 0){
        $('#hidden-count').html(
          "There are " + count + " hidden listings click "+
          "<a href='" + landshareMap.listingsUrl() +
          "/hidden'>here</a> to see them.");
      } else {
        $('#hidden-count').html('');
      };
    };
  });
}
