function createMyOverlay() {
  var MyOverlay = function(marker, html, id, closeCallback) {
    this.marker = marker;
    this.html = html;
    this.id = id;
    this.closeCallback = closeCallback;
  }
  MyOverlay.prototype = new GOverlay();
  MyOverlay.prototype.initialize = function(map) {
    var div = document.createElement("div");
    div.className = 'mywindow';
    div.style.position = 'absolute';
    div.innerHTML = this.html;

    this._map = map;
    this._div = div;

    map.getPane(G_MAP_FLOAT_PANE).appendChild(div);  
    var content = $(div).down('div');
    this._content = content;
    
    this.computePosition();
    
    if (content.hasClassName('map-box-large')) {
      var markerPosContainer = map.fromLatLngToContainerPixel(this.marker.getPoint());
      map.panBy(new GSize(map.getSize().width/2 - markerPosContainer.x, 400 -  markerPosContainer.y));
      content.down('.button-close').onclick = this.closeCallback;
    }
    
    content.id = this.id;
  }

  MyOverlay.prototype.computePosition = function(){
    var latLng = this.marker.latlng_ || this.marker.getPoint(),
        markerPos = this._map.fromLatLngToDivPixel(latLng),
        offsetX = 13, offsetY = 25;
    if (this._content.hasClassName('map-box-large')) {
      offsetX = (352 - 44)/2 ;
      offsetY = 16;
    }
    this._div.style.top  = (markerPos.y - offsetY - this._content.getHeight()) + 'px';
    this._div.style.left = (markerPos.x - offsetX) + 'px';
  }

  MyOverlay.prototype.remove = function(){
    this._div.parentNode.removeChild(this._div);
  }

  MyOverlay.prototype.redraw = function() {
    //haven't had need for this yet
  }
  
  MyOverlay.prototype.close = function() {
    this._map.removeOverlay(this);
  }
  
  window.MyOverlay = MyOverlay;
}

Map = (function() {
  var fullsize = false, toggleButton, map = null, bounds, overWindows = new Hash(), currentOverlayId, timer, currentInfoWindow,
      markerClusterer, markers;
  
  // Load google map API
  function init() {
    google.load("maps", "2");
    google.setOnLoadCallback(function() {
      // If something need to be done before creating map
      createMyOverlay();
      initCallback.defer();
    });
  }
  
  // Register UI: expand/collapse map
  function registerUI() {
    toggleButton = $$('.button-google-full').first();
    toggleButton.observe('click', toogleFullsize);
    
    $('town-list').observe('click', changeCity);
  }
  
  function changeCity(event) {
    var element = event.element();
    Cookie.setData('cityId', element.id);
    setCityId(element.id)
  }
  
  function setCityId(id)  {
    var element = $(id),
        bb      = element.readAttribute('bb');
    bb = eval(bb);
    bounds = new GLatLngBounds(new GLatLng(bb[1][0], bb[1][1]), new GLatLng(bb[0][0], bb[0][1]));
    $('town-list').hide();
    $("selected_city").update(element.innerHTML);
    
    map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));
  }
  
  
  function storeLocation() {
    Cookie.setData('bounds', map.getBounds().getCenter().toUrlValue() + "|" + map.getZoom());
  }
  
  // Initialize Map oject
  function initCallback() {
    if (GBrowserIsCompatible()) {
      // Create a new google map
      map = new GMap2($('map'));

      Cookie.init({name: 'moxity', expires: 90});
      setCityId(Cookie.getData('cityId') || 'city_1');
      var location = Cookie.getData('bounds');
      if (location) {
        var tmp = location.split('|')
        map.setCenter(GLatLng.fromUrlValue(tmp[0]), parseInt(tmp[1]));
      }
      
      // Add controls
      map.setUIToDefault();
      map.disableScrollWheelZoom();
      
      $(map.getPane(G_MAP_FLOAT_PANE)).observe("mouseover", mouseOverWindowPane);
      $(map.getPane(G_MAP_FLOAT_PANE)).observe("mouseout", mouseOutWindowPane);
      $(map.getPane(G_MAP_MARKER_PANE)).observe("mouseout", mouseOutMakerPane);
    
      GEvent.bind(map, "zoomend", this, closeInfoWindow);
      GEvent.bind(map, "onClusterClicked", this, onClusterClicked);
      GEvent.bind(map, "moveend", this, storeLocation);
      
      // Register Map UI
      registerUI();
      // Debug 
      window.map = map;
    }
  }
  
  function onClusterClicked(cluster) {
    var c = markerClusterer.getClusters().find(function(c) {return c.getBounds() == cluster.bounds_})
    map.setCenter(cluster.bounds_.getCenter());

    var ids = c.getMarkers().map(function(c) {return c.marker.id});
    showInfoWindow(cluster, ids)
  }
  
  // Toggle map size
  function toogleFullsize(event) {
		var center = map.getCenter();
    event.stop();
    fullsize = !fullsize;

		$('main').toggleClassName('large');
		$('sidebar', 'newsfeed').invoke('toggle'),
    toggleButton.toggleClassName("button-google-full").toggleClassName("button-google-normal");
		
		$('map').setStyle({width: fullsize ? '990px' : '640px', height: fullsize ? '580px' : '480px'});

		map.checkResize()
		map.setCenter(center);

    $("timeline_next", "timeline_back", "full_timeline_next", "full_timeline_back").invoke("toggle");
	  $$('#test_timeline .extended').invoke("toggle");

    $$('#ds_v div').invoke("setStyle", {height: fullsize ? '580px' : '480px'});

  }
  
  function showInfoWindow(gmarker, id) {
    hideOverWindow(currentOverlayId, true);
    if (typeof id == "string"){
      new Ajax.Request("/events/" + id + "/big_window", {onSuccess: openInfoWindow.curry(gmarker, id), 
                                                         parameters: {authenticity_token: authenticity_token}});
    }
    else {
      new Ajax.Request("/events/cluster_window", {onSuccess: openInfoWindow.curry(gmarker, id), 
                                                  parameters: {authenticity_token: authenticity_token, "id[]": id}});
      
    }
  }
  
  function openInfoWindow(gmarker, id, response) {
    closeInfoWindow();
    currentInfoWindow = new MyOverlay(gmarker, response.responseText, id, closeInfoWindow);
    map.addOverlay(currentInfoWindow);
    $(document.body).fire('moxity:window_opened', {id: id});
  }
  
  function closeInfoWindow(event) {
    if (currentInfoWindow)
      currentInfoWindow.close();
    currentInfoWindow = null;
    $(document.body).fire('moxity:window_closed');
    if (event && typeof event.stop == "function" )
      event.stop();
  }
    
  function showOverWindow(gmarker, id) {
    // Check if tooltip == tooltip of currentInfoWindow
    if (currentInfoWindow && currentInfoWindow.id == id)
      return;
      
    // Same current id, just kill hideWindow timer
    if (currentOverlayId == id) {
      stopTimer();
      return;
    }
    // Different id, hide immediatly current window
    if (currentOverlayId && currentOverlayId != id) {
      hideOverWindow(currentOverlayId, true);
    }
      
    currentOverlayId = id;
    
    // Already in cache
    if (overWindows.get(id)) {
      var overlay = overWindows.get(id);
      overlay.computePosition();
      map.addOverlay(overlay);
    }
    // Else request content
    else {
      new Ajax.Request("/events/" + id + "/small_window", {onSuccess: openOverWindow.curry(gmarker, id), 
                                                           parameters: {authenticity_token: authenticity_token}});
     }
  }
  
  function hideOverWindow(id, immediatly) {
    if (!id)
      return;
    //Delay hide
    if (!timer && !immediatly) {
      startTimer(id);
    } else {
      timer = null;
      var overlay = overWindows.get(id);
      if (overlay)
        map.removeOverlay(overlay);
      currentOverlayId = null;
    }
  }
  
  function openOverWindow(gmarker, id, response) {
    if (currentOverlayId != id)
      return;
      
    var overlay = new MyOverlay(gmarker, response.responseText, id);
    map.addOverlay(overlay);
    overWindows.set(id, overlay);
  }
  
  function mouseOverWindowPane(event) {
    stopTimer();
  }
  
  function mouseOutWindowPane(event) {
    var box = event.element().up("div.map-box-mox");
    if (box)
      hideOverWindow(box.id);
  }
  
  function mouseOutMakerPane(event) {
    if (currentOverlayId)
      hideOverWindow(currentOverlayId);
  }
  
  function stopTimer() {
    if (timer){
      clearTimeout(timer);
      timer = null;
    }
  }
  
  function startTimer(id) {
    if (!timer) {
      timer = setTimeout(hideOverWindow.curry(id), 10);
    }
  }
  
  var theme2Icon = {'01_concert' : "concert",
                    '02_dance': "danse",
                    '03_opera' : "opera",
                    '04_cinema' : "cinema",
                    '05_humanitarian' : "grandes_causes",
                    '06_moxity' : "moxiptits",
                    '07_arts' : "arts",
                    '08_literature': "litterature",
                    '09_theater' : "theatre",
                    '10_sport' : "sport",
                    '11_lifestyle' : "art_de_vivre",
                    '12_clubbing' : "clubbing",             
                    '13_political_meeting' : "politique",
                    '14_geek' : "technologie",
                    '15_humor' : "humour",
                    '16_science' : "sciences",
                    '17_society' : "societe",
                    '18_economy' : "economie",
                    '19_industry' : "industrie",
                    '20_courses' : "cours",
                    '21_other' : "autre"};
  
  // Set map markers
  function setPoints(points) {
    if (map) {
      map.clearOverlays();
      overWindows.keys().each(function(key) {overWindows.unset(key)});
      markers = [];
      points.each(function(marker) {
        var icon = new GIcon({image:            "/images/picto_small_" + theme2Icon[marker.theme]+ ".png",
                              iconSize:         new GSize(34, 44),
                              iconAnchor:       new GPoint(9, 34),
                              infoWindowAnchor: new GPoint(9, 2),
                              infoShadowAnchor: new GPoint(9, 25)});
        var gmarker = new GMarker(new GLatLng(marker.lat, marker.lng), {icon: icon});
        gmarker.id = marker.id;
        GEvent.bind(gmarker, "mouseover", this, showOverWindow.curry(gmarker, marker.id));
        GEvent.bind(gmarker, "click", this, showInfoWindow.curry(gmarker, marker.id));
        markers.push(gmarker);        
      });
      if (markerClusterer) {
        markerClusterer.clearMarkers();
        markerClusterer.addMarkers(markers);
      }
      else
        markerClusterer = new MarkerClusterer(map, markers, {maxZoom: 30});
    }
    else {
      setPoints.delay(0.1, points); 
    }
  }
  
  function isFullSize() {
    return fullsize;
  }
  
  function openTooltip(id) {
    var clusters = markerClusterer.getClusters();
    clusters.each(function(cluster) {
      var markers = cluster.getMarkers();
      if (markers.length == 1) {
        if (markers.first().marker.id == id) {
          showOverWindow(markers.first().marker, id);
          return;
        }
      } else {
        markers.each(function(marker) {
          if (marker.marker.id == id) {
            showOverWindow(marker.marker, id);
            throw $break;
          }
        })
      }
    });
  }
  
  
  function closeTooltip(id) {
    hideOverWindow(id, true);
  }
  
  function closeWindow() {
    closeInfoWindow();
  }
  
  function openWindow(id) {
    var marker = markers.find(function(m) {return m.id == id});
    map.setCenter(marker.getLatLng(), 17);
    showInfoWindow(marker, id)
  }
  
  return {init:          init,
          isFullSize:    isFullSize,
          openTooltip:   openTooltip,
          openWindow:    openWindow,
          closeTooltip:  closeTooltip,
          closeWindow:   closeWindow,
          storeLocation: storeLocation,
          setPoints:     setPoints}
})();

Map.init();


EventList = (function() {
  var currentElement = null, timer = null;
  function init() {
    //$('results').observe('mouseover', mouseover).observe('mouseout', mouseout);
    $('results').observe('click', click);
    $(document.body).observe('moxity:window_closed', windowClosed).observe('moxity:window_opened', windowOpened);
  }
  
  function windowClosed(event) {
    $$('#results div').invoke('removeClassName', 'selected')
  }

  function windowOpened(event) {
    var id = event.memo.id;
    var element = $('results').down("div#event_" + id);
    if (element)
      element.addClassName('selected');
  }

  function click(event) {
    event.stop();
    var element = event.element().up(".result") || event.element();
    Map.openWindow(getId(element));
  }
  
  function getId(element) {
    return element.id.gsub('event_', '');
  }
  return {init: init}
})();
EventList.init();