Application = (function() {
  var map, mapController, slider, sliderValues, waiting_content, search, listMode, listValid, moreCompanies, currentOffset;
  
  // Load google map API
  function init(center, zoom, id) {
    listMode = false;
    listValid = false;
    initCallback(center, zoom, id);
    waitingContent = $('waiting_content');
  }

  function registerTabs() {
    $('tabs').observe('click', function(event) {
      var li = event.findElement('li');
      $('filter_content').hide();
      $('list_content').hide();
      $(li.id.gsub('_tab', '_content')).show();
      li.up().select('li').invoke("removeClassName", "selected");
      li.addClassName("selected");
      listMode = (li.id == 'list_tab');
      updateList();
    });
  }
  
  function registerList() {
    $('list_container').on('click', '.company', function(event, element) {
      mapController.openPopupForPointId(element.readAttribute('data-id'));
      event.stop();
    });
    $('list_container').on('mouseover', '.company', function(event, element) {
      element.addClassName("over");
    })
    $('list_container').on('mouseout', '.company', function(event, element) {
      element.removeClassName("over");
    })
  }

  function openPopupForCompany(marker, id) {
    mapController.select({
      offset: 0,
      limit: 1,
      condition: 'id = "' + id + '"',
      properties: ["html"],
      callback: function(response) {
        marker.openPopup(response.markers[0].html);
      }          
    });
  }
  
  function updateList() {
    if (!listMode || listValid) {
      return;
    }
    listValid = true;
    requesrMoreCompanies(0);
  }
  
  function requesrMoreCompanies(offset) {
    var content = $('list_container'), 
        templateWithoutImage = new Template("<div class='company' data-id='#{id}'>\
                                              <span class='logo'></span>\
                                              <span class='name'>#{fullname}</span>\
                                              <span class='address'>#{address}</span>\
                                             </div>"),
        template = new Template("<div class='company' data-id='#{id}'>\
                                  <span class='logo'><img width=88 src='http://crunchbase.com/#{icon}'/></span>\
                                  <span class='name'>#{fullname}</span>\
                                  <span class='address'>#{address}</span>\
                                 </div>"),
        limit = 20;
    currentOffset = offset;
    mapController.select({
      offset: offset,
      limit: limit,
      order: "created_at DESC",
      properties: ["address", "icon", "fullname"],
      callback: function(response) {
        if (offset == 0) {
          content.update('');
        }

        var markers = response.markers;
        markers.each(function(marker) {
          var html = marker.icon && marker.icon != "empty.gif" ? template.evaluate(marker) : templateWithoutImage.evaluate(marker);
          content.insert(html);
        });
        // Add more button
        if (offset + limit < response.totalCount) {
          content.insert(moreCompanies.show());
        } else {
          moreCompanies.hide();
        }
    }});
  }
  
  function addMoreCompanies(event) {
    event.stop();
    requesrMoreCompanies(currentOffset + 20);
  }
    
  function registerControls() {
    var handles = [$('handle1'), $('handle2')],
        legends = [$('handle1_legend'), $('handle2_legend')];

    function selectAll() {
      $('categories').select('input').each(function(e){e.checked = true});
      updateMap();
    }
    
    function deselectAll() {
      $('categories').select('input').each(function(e){e.checked = false});
      updateMap();
    }
    
    function date(prefix, value) {
      return prefix + ' '  + (value == 0 ? 'Before 1990' : (value == 20 ? 'To today' : 1990 + value));
    }

    function updateLegend(update) {
      var changed = false;
      slider.values.each(function(value, index) {
        if (sliderValues[index] != value) {
          var legend = legends[index],
              margin;
          if (index == 0)
            margin = value == 0 ? 0 : -7;
          else
            margin = value == 20 ? -43 : -35;
            
          legend.style.left = parseFloat(handles[index].style.left) + margin  + 'px';
          legend.update(date(index == 0 ? '' : '', value));
          changed = true;
        }
      });
      if (changed) 
        sliderValues = slider.values.clone();
      if (update)
        updateMap();
    }

    slider = new Control.Slider(['handle1','handle2'],'track',{sliderValue:[2, 20],
                                                               values:$R(0,20),
                                                               range:$R(0,20),
                                                               restricted:true,
                                                               spans:['selected_tack'],
                                                               onSlide:updateLegend.curry(false),
                                                               onChange:updateLegend.curry(true)});
    sliderValues = [-1, -1]
    
    $("select_all").observe('click', selectAll);
    $("deselect_all").observe('click', deselectAll);
    updateLegend();
  }
                            
  function registerUI() {
    registerControls();
    registerTabs();
    registerList();
   
    search = $('search');
    moreCompanies = new Element('a').addClassName('more').update("Show more companies...").observe('click', addMoreCompanies);
    
    if (search) {
      search.observe('focus', function() {
          //if (search.value == search.title) {
            search.value = '';
            search.addClassName('focus');
            setTimeout(updateMap, 100);
          //}
        })
        .observe('blur', function() {
          if (search.value.strip().empty()) {
            search.value = search.title;
            search.removeClassName('focus');
          }
        })
        .observe('keypress', function() {
          setTimeout(updateMap, 100);
        });
    }
   
    $('controls').observe('click', updateMap);
  }
  
  function buildCondition() {
    // Categories
    var categories = $$('#categories input')
                      .findAll(function(input){return input.checked})
                      .map(function(input) {return input.value });
    var condition = Maptimize.Condition();
    if (categories.length > 0)  {
      condition.appendAnd(['cat IN ?', categories]);
    }

    // Number of employees      
    var number_of_employees = $('number_of_employees'),
        nbEmployees         = number_of_employees.options[number_of_employees.selectedIndex].value;
    if (nbEmployees != 0) {
      nbEmployees = nbEmployees.split("-");
      condition.appendAnd(["nbe >= ?", parseInt(nbEmployees[0])]);
      if (nbEmployees.length == 2) {
        condition.appendAnd(["nbe <= ?", parseInt(nbEmployees[1])]);
      }
    }
    
    // Deadpool
    if ($('date_type_without_deadpool').checked)
      condition.appendAnd({ deadpooled: 0 });
    if ($('date_type_only_deadpool').checked)
      condition.appendAnd({ deadpooled: 1 });
    
    // Time
    if (slider.values.first() > 0) {
      var date = new Date(1990 + parseInt(slider.values.first()), 0, 1);
      condition.appendAnd(["founded_at > ?", date.getTime()/1000]);
    }

    if (slider.values.last() < 20) {
      var date = new Date(1990 + parseInt(slider.values.last() + 1), 0, 1);
      condition.appendAnd(["founded_at < ?", date.getTime()/1000]);
    }
          
    if (search.value && search.value != search.title) {
      condition.appendAnd('name LIKE "' + search.value.toLowerCase() + '"'); 
    }        
    return condition;
  }
  
  function updateMap() {
    var condition = buildCondition();
    mapController.setCondition(condition);
    mapController.refresh();
  }
    
  function initCallback(center, zoom, id) {
    center = center || [25, 0];
    var mapOptions = {
      zoom: zoom || 3,
      center:  new google.maps.LatLng(center[0], center[1]),
      mapTypeId: google.maps.MapTypeId.ROADMAP,
      scrollwheel: false
    };
    
    // Create a new google map
    map = new google.maps.Map($("map"), mapOptions);
    window.map = map;
    
    // Attach maptimize plugin and set event listeners
    mapController = new com.maptimize.MapController(map);
    
    google.maps.event.addListener(map, 'afterRefresh', function() {
      $('counter').update(mapController.getTotalPointsCount() + " companies on the map");
      listValid = false;
      updateList();
      if (id) {
        mapController.openPopupForPointId(id);
        id = false;
      }
    });
    
    window.mapController = mapController;
    
    registerUI();
    updateMap();
  }

  function clear() {
    if (search.value == '' || search.value == search.title)
      return;
    search.value = ''
    updateMap();
  }
  return {init:  init,
          clear: clear}
})();

