var BeerFinder = function() {
  
  // Private Variables
  var _start_address = {}
  var _beer_locations = $A([])
  var _index = 0
  var _default_delay = 0
  var _current_delay = _default_delay
  var _geo = new GClientGeocoder()
  var _completed_loading_destinations = false
  var _completed_loading_start = false
  var _browns
  
  
  // Public Methods
  var search = function() {
    if($('StartAddress').value == 'Enter your address…') return false
    show_loading_message()
    set_start_address($('StartAddress').value)
    return false
  }
  

  // Private Methods
  var setup = function() {
    _beer_locations = beer_locations
    _browns = _beer_locations.first()
    request_next_coordinates(0)
  }


  var set_start_address = function(start_address_string) {
    _start_address.address = start_address_string
    new GClientGeocoder().getLocations(_start_address.address, function(result) {
      if (result.Status.code == G_GEO_SUCCESS) {
        var these_coordinates = result.Placemark[0].Point.coordinates
        _start_lat_lng = new GLatLng(these_coordinates[1], these_coordinates[0])
        _completed_loading_start = true
        if(_completed_loading_destinations) show_results()
      }
      else if (result.Status.code == G_GEO_TOO_MANY_QUERIES) {
        _current_delay += 20
        setTimeout(function() {
          set_start_address(start_address_string)
        }, _current_delay)
      }
      else {
        update('We\'re having some trouble finding your address. Try being more (or less) specific.')
      }
    
    })
  }
  
    
  var request_next_coordinates = function() {
    if(_index == 0) {
      _completed_loading_destinations = false
      request_coordinates(_index)
      _index++
    }
    else if(_index < _beer_locations.length -1) {
      setTimeout(function() { request_coordinates(_index) }, _current_delay)
      _index++
    }
    else {
      _completed_loading_destinations = true
      if(_completed_loading_start) show_results()
      _index = 0
      _current_delay = _default_delay
    }
  }


  var request_coordinates = function(index) {
    var this_location = _beer_locations[index]
    
    _geo.getLocations(this_location.address, function (result) {
      if (result.Status.code == G_GEO_SUCCESS) {
        var these_coords = result.Placemark[0].Point.coordinates
        this_location.lat_lng = new GLatLng(these_coords[1], these_coords[0])
        if(_completed_loading_start) show_loading_message()
      }
      else if (result.Status.code == G_GEO_TOO_MANY_QUERIES) {
        _index--
        _current_delay += 20
      }
      request_next_coordinates()
    })
  }
  
  
  var show_loading_message = function() {
    if(_completed_loading_destinations)
      update('<h4 id="LoadingDistances">Searching…</h4>')
    else
      update('<h4 id="LoadingDistances">Performing digital pub crawl<br />'+(parseInt(_index/_beer_locations.length*100))+'% complete…</h4>')
  }
  
  
  var show_results = function() {
    results_html_str = '<h4>You are roughly…</h4>'
    
    var distances = []
    
    _beer_locations.each(function(beer_location, index) {
      if(!_beer_locations[index].lat_lng) return
      _beer_locations[index].distance = _start_lat_lng.distanceFrom(beer_location.lat_lng) / 1000 * 0.621371192
    })
    
    _beer_locations.sort(function(a, b) {
      if(a.distance < b.distance) return -1
      else if(a.distance > b.distance) return 1
      return 0
    })
    
    var locations_listed = 0
    var top_locations = []
    for(var i = 0; locations_listed < 5 && i < beer_locations.length; i++) {
      if(!_beer_locations[i].distance) continue
      locations_listed++
      top_locations.push(_beer_locations[i])
    }
    
    var includes_browns = false
    
    top_locations.each(function(location) {
      if(location == _browns) includes_browns = true
      var directions_link = 'http://maps.google.com/maps?daddr='+encodeURIComponent(location.name+', '+location.address)+'&saddr='+encodeURIComponent(_start_address.address)
      results_html_str += (parseInt(Math.ceil(location.distance*10))/10) + ' miles from '+location.name+'… <a href="'+directions_link+'" target="_blank">directions</a><br />'     
    })
    
    if(!includes_browns) {
      var directions_link = 'http://maps.google.com/maps?daddr='+encodeURIComponent(_browns.name+', '+_browns.address)+'&saddr='+encodeURIComponent(_start_address.address)
      results_html_str += '<div id="BrownsDistance">Brown’s Brewing Co. itself is about <span class="distance">' + Math.ceil(_browns.distance) + ' miles</span> away… <a href="'+directions_link+'" target="_blank">directions to Brown’s</a></div>'
    }
    
    update(results_html_str)
  }
  
  
  var update = function(html_str) {
    var div = document.createElement('div')
    div.innerHTML = html_str
    $('Results').innerHTML = ''
    $('Results').appendChild(div)
  }
  
  
  
  // Initialization
  Event.observe(window, 'load', setup)
  
  // Public Method Declarations
  return {search: search}
  
}();