/**
 * creates a marker with the correct attributes.
 * a subclass would be nicer.
 *
 */
function createMarker(lat, lng, priority, title, iconUrl, userId, spotId, categoryKey, promotions, onClick) {
  var gIcon = new GIcon(G_DEFAULT_ICON);
  gIcon.iconSize = new GSize(25, 30);
  gIcon.image = iconUrl;
  gIcon.printImage = iconUrl;
  gIcon.shadow = null;

  var gMarker = new GMarker(new GLatLng(lat, lng), {
      title: title,
      icon: gIcon
  });

  gMarker.priority = priority;
  gMarker.userId = userId;
  gMarker.spotId = spotId;
  gMarker.categoryKey = categoryKey;
  gMarker.promotions = promotions;
  
  GEvent.addListener(gMarker, 'click', onClick.curry(gMarker));
  return gMarker;
}

function category_marker_icon_path(categoryKey) {
  return '/images/categories/25x25/' + categoryKey + '_marker.png';
}

/**
 * A Search via the Qiro Database.
 * @callback - function(markers) {} to be called with the found markers
 * @options - the options for the search. expects categoryIds:[] and userIds:[]
 */
var QiroMarkerSearch = Class.create({
  
  initialize: function(callback, priority, options) {
    this.callback = callback;
    this.priority = priority;
    this.options = options;

    // this.categories <- { category.id : category }
    this.categories = options.categories.inject({}, function(categories, category) {
      categories[category.id] = category;
      return categories;
    });

    new Ajax.Request("/spots/bounding_box.json", {
      onSuccess: this.onSuccess.bind(this),
      method: 'get',
      evalJSON: 'force',
      contentType: 'application/json',
      parameters: this.getUrl()
    });
  },

  // private

  onSuccess: function(transport) {
    var spots = transport.responseJSON.spots;
    var users = transport.responseJSON.users;
    
    this.callback(spots.map(this.createSpotMarker.bind(this)));
    this.callback(users.map(this.createUserMarker.bind(this)));
  },  

  createUserMarker: function(user) {
    var onClick = this.showUserWindow.curry(user);
    var iconPath = category_marker_icon_path('find_me');
    var loc = user.position;
    
    return createMarker(loc.latitude, loc.longitude, this.priority, user.nick, iconPath, user.nick, null, 'find_me', null, onClick);
  },

  createSpotMarker: function(spot) {
    var onClick = this.showInfoWindow.curry(spot);
    var iconPath = category_marker_icon_path(spot.category_key);
    var loc = spot.location

    return createMarker(loc.latitude, loc.longitude, this.priority, spot.name, iconPath, null, spot.id, spot.category_key, spot.spot_promotions, onClick);
  },
  
  showInfoWindow: function(json, marker, event) {
    map.setMarkerSelection(marker);
    
    promotion.pause();
    
    new Ajax.Request("/spots/" + json.id + "/marker", {
      method: 'get',
      onSuccess: function(transport) {
        map.map.openInfoWindowHtml(marker.getLatLng(), transport.responseText, { maxWidth: 300, onCloseFn: promotion.unpause.bind(promotion) });
 	    }
    });
  },
  
  showUserWindow: function(user, marker, event) {
    new Ajax.Request("/users/" + user.nick + "/marker", {
      asynchronous: true,
      method: 'get',
      onSuccess: function(transport) {
        map.map.openInfoWindowHtml(marker.getLatLng(), transport.responseText, { maxWidth: 300 });
      }
    });
  },
  
  getUrl: function() {
    var categoryIds = this.options.categories.map(function(c) {
      return 'category_ids[]=' + c.id;
    });

    var sw = this.options.southWest;
    var ne = this.options.northEast;

    return 'south_west=' + sw.lat() + "," + sw.lng()
      + '&' + 'north_east=' + ne.lat() + "," +  ne.lng()            
      + '&' + categoryIds.join('&');
  }
    
});

/**
 * A Search via Google
 *
 */
var GoogleMarkerSearch = Class.create({

  initialize: function(callback, priority, options) {
    this.callback = callback;
    this.priority = priority;
    this.searches = options.categories.map(this.createSearch.bind(this));
  },

  // private

  createSearch: function(category) {
    var localsearch = new GlocalSearch();
    localsearch.setCenterPoint(map.map);
    localsearch.setSearchCompleteCallback(this, this.onSearchComplete.bind(this).curry(localsearch, category));
    localsearch.execute(category.searchtext);
    return localsearch;
  },

  onSearchComplete: function(localsearch, category) {
    var results = localsearch.results.map(this.createMarker.bind(this).curry(category));
    this.callback(results);
  },

  createMarker: function(category, json) {
    var iconPath = category_marker_icon_path(category.key);
    var onClick = this.showInfoWindow.curry(json);

    return createMarker(json.lat, json.lng, this.priority, json.titleNoFormatting, iconPath, null, null, category.key, null, onClick);
  },

  showInfoWindow: function(json, marker, evt) {
    map.setMarkerSelection(marker);

    promotion.pause();

    if (marker.spotId) {
      new Ajax.Request("/spots/" + marker.spotId + "/marker", {
        method: 'get',
        onSuccess: function(transport) {
          map.map.openInfoWindowHtml(marker.getLatLng(), transport.responseText, { maxWidth: 300, onCloseFn: promotion.unpause.bind(promotion) });
   	    }
      });
    } else {
      showGoogleMarkerInfo(marker, json);
    }
  }

});

/**
 * A Search that combines other Searches
 *
 */
var CompositeMarkerSearch = Class.create({

  subsearches: [
    { 'class': QiroMarkerSearch, 'priority': 1 },
    { 'class': GoogleMarkerSearch, 'priority': 2 }
  ],

  initialize: function(callback, options) {
    this.subsearches.each(function(subsearch) {
      new subsearch['class'](callback, subsearch['priority'], options);
    });
  }
    
});

// The Spotsearch to use
var Search = CompositeMarkerSearch;

