//console.log();

var SM = function() {

    var map;

    var mapId;

    var currentZoom;

    var originalCenter;

    var originalZoom;

    var skipZoomDispatch;

    var lastParams;

    var mapInitialized = false;

    var setDimensions = function() {
	listInterface.setDimensions();
	mapInterface.setDimensions();
    };

    var unload = function() {
	GUnload();
	$(window).unbind();
    };

    var startLoading = function() {
	$('#location_list').addClass('loading');
    };

    var stopLoading = function() {
	$('#location_list').removeClass('loading');
    };

    var saveTransientState = function(opts) {
      if (opts.lastCenter) {
	$.cookie('lastCenter',opts.lastCenter, {"path": '/'});
      }
      if (opts.lastLocation) {
	$.cookie('lastLocation',opts.lastLocation, {"path": '/'});
      }
      if (opts.lastZoom) {
	$.cookie('lastZoom',opts.lastZoom, {"path": '/'});
      }
    };

    var clearTransientState = function() {
      $.cookie('lastCenter',null, {"path": '/', "expires": -1});
      $.cookie('lastLocation',null, {"path": '/', "expires": -1});
      $.cookie('lastZoom',null, {"path": '/', "expires": -1});
    };

    var mapInterface = function() {

	var markers = [];

	var icon = new GIcon({
	    image: "/images/markers/marker-red.png",
	    shadow: "/images/shadow.png",
            iconSize: new GSize(16, 26),
	    shadowSize: new GSize(29, 26),
	    iconAnchor: new GPoint(7.0, 26.0),
	    infoWindowAnchor: new GPoint(9, 2),
	    infoShadowAnchor: new GPoint(18, 25)
	});

	var openMarker = null;

	var markerOptions = {"icon": icon};

	var InfoWindow = function(marker, location) {
	    this.marker = marker;
	    this.content = $(document.createElement('div'));
	    this.content.attr({"id": location.id, "class": "map_location"});
	    this.content.append(location.map_output());
	    this.content.append("<div class=\"bottom\"></div>");
	    this.closeFunc = function(e) { e.data.content.hide(); };
	    $('.close_link',this.content).bind('click',{content: this}, this.closeFunc);
	    $(map.getPane(G_MAP_FLOAT_PANE)).append(this.content);
	};
	InfoWindow.prototype = new GOverlay();
	InfoWindow.prototype.initialize = function(map) {
	    this.content.css({
		left: ( map.fromLatLngToDivPixel( this.marker.getLatLng() ).x + ( -33 ) ) + 'px',
		bottom: ( -1 * map.fromLatLngToDivPixel( this.marker.getLatLng() ).y + ( 26 ) ) + 'px'
	    });
	};
	InfoWindow.prototype.remove = function() {
	    $('.close_link',this.content).unbind();
	    this.marker = null;
	    this.content.remove();
	};
	InfoWindow.prototype.redraw = function(force) {
	    if (!force) return;
	    this.content.css({
		left: ( map.fromLatLngToDivPixel( this.marker.getLatLng() ).x + ( -33 ) ) + 'px',
		bottom: ( -1 * map.fromLatLngToDivPixel( this.marker.getLatLng() ).y + ( 26 ) ) + 'px'
	    });
	};
	InfoWindow.prototype.show = function(force) {
	    if (openMarker == this.marker && !force) { return; }
	    if (openMarker) { openMarker.infoWindow.hide(); }
	    openMarker = this.marker;
	    listInterface.show(this.marker.location.id);
	    map.panTo(this.marker.getLatLng());
	    this.content.fadeIn('fast');
	    saveTransientState({
			       lastCenter: this.marker.location.lat+','+this.marker.location.lng,
			       lastLocation: this.marker.location.id,
			       lastZoom: map.getZoom()
			     });
	};
	InfoWindow.prototype.hide = function() {
	    if (this.marker == null) { return; }
	    clearTransientState();
	    openMarker = null;
	    listInterface.hide(this.marker.location.id);
	    this.content.fadeOut('slow');
	};

	return {
	    init: function(params) {
		mapId = params.map_canvas;
		map = new GMap2(document.getElementById(mapId), { mapTypes: [G_NORMAL_MAP, G_SATELLITE_MAP, G_PHYSICAL_MAP] });
		this.setDimensions();
		map.addControl(new GLargeMapControl3D());
		map.addControl(new GMapTypeControl());
		map.addControl(new GScaleControl());
		// OPTIMIZE: zoom refresh
 		GEvent.addListener(map, 'zoomend', function(o,n) {
				     currentZoom = n;
				     if (!skipZoomDispatch) {
				       SWFAddress.setValue(paramsToSWFAddress(buildFilters()));
				     }
 		});
		GEvent.addListener(map, 'dragend', function() {
				     saveTransientState({
				       'lastCenter': map.getCenter().lat()+','+map.getCenter().lng()
				     });
				   });
	    },
	    add: function(l) {
		var p = new GLatLng(l.lat,l.lng);
		var m = new GMarker(p,markerOptions);
		m.infoWindow = new InfoWindow(m,l);
		m.location = l;
		GEvent.addListener(m, 'click', function() {
		    m.infoWindow.show();
		});
		map.addOverlay(m);
		map.addOverlay(m.infoWindow);
		markers[l.id] = m;
		if ((openMarker && openMarker.location.id == m.location.id) || ($.cookie('lastLocation') && parseInt($.cookie('lastLocation')) == parseInt(m.location.id))) {
		  m.infoWindow.show(true);
		}
	    },
	    clear: function() {
		map.clearOverlays();
		markers = [];
	    },
	    show: function(id) {
		markers[id].infoWindow.show();
	    },
	    hide: function(id) {
	      if (!markers[id]) {
		return;
	      }
	      markers[id].infoWindow.hide();
   	    },
	    setDimensions: function() {
		var canvas = $(document.getElementById(mapId));
		canvas.css({'top': 0,
			    'right': 0,
			    'bottom': $(window).height(),
			    'left': $('#sidebar').width(),
			    'width': $(window).width()-$('#sidebar').width()});
		canvas.height($(window).height());
	    }
	};
    }();

    var listInterface = function() {
        var showFunc = function(e) { mapInterface.show(e.data.id); };
	var detailFunc = function(e) { window.location = e.data.slug; };
	return {
	    noResults: function() {
		listInterface.clear();
		$('#location_list').append('<div class="location_list no_results"><h3>Sorry, no results were found.</h3><p>Try changing your search criteria.</p></div>');
	    },
	    add: function(l) {
		$('#location_list').append(["<div class=\"location_list\" id=\"location_list_" + l.id + "\">",l.list_output(),"</div>"].join("\n"));
		$('#location_list_' + l.id).bind('click', {"id": l.id}, showFunc);
		$('#location_list_' + l.id).bind('dblclick', {"slug": l.slug}, detailFunc);
		$('#location_list_' + l.id).bind('mouseover', {}, function() { $(this).toggleClass('hover'); });
		$('#location_list_' + l.id).bind('mouseout', {}, function() { $(this).toggleClass('hover'); });
	    },
	    show: function(id) {
		var item = $('#location_list_' + id);
		var list = $('#location_list');
		item.toggleClass('highlight');
		list.animate({scrollTop: '+=' + ((item.offset().top - list.offset().top) - item.height()) + 'px'});
	    },
	    hide: function(id) {
		var item = $('#location_list_' + id);
		item.toggleClass('highlight');
	    },
	    clear: function() {
		$('#location_list .location_list').each(function() {
		    $(this).unbind();
		    $(this).remove();
		});
	    },
	    toggleSpecificTime: function() {
		$('#day_filter_now').uncheck();
		$('#day_filter_select').toggle();
		this.setDimensions();
	    },
	    toggleRightNow: function() {
		$('#day_filter').uncheck();
		$('#day_filter_select').hide();
		this.setDimensions();
	    },
	    setDimensions: function() {
		$('#location_list').height($(window).height()-$('#search_form_wrapper').innerHeight()-$('#headline').innerHeight());
	    }
	};
    }();

    var Location = function(data) {
	this.id = data.id;
	this.name = data.name;
	this.lat = data.lat;
	this.lng = data.lng;
	this.address = data.short_address;
	this.average_rating = data.average_rating;
	this.comments_count = data.comments_count;
	this.slug = "/locations/" + data.slug;
	this.features = data.features;
	this.hours = data.condensed_hours;
	this.close_link = "<a href=\"javascript:void(0);\" class=\"close_link\">&nbsp;</a>";
	this.display_name = "<h4 class=\"name\">" + this.name + "</h4>";
	this.display_address = "<p class=\"address\">" + this.address + "</p>";
	this.rating_info = "<p class=\"rating_info\"> " + setStars(this.average_rating) + "</p>";
	this.comment_info = "<p class=\"comment_info\">Comments: " + this.comments_count + "</p>";
	this.detail_link = "<p class=\"detail_link\"><a href=\"http://maps.google.com/maps?f=d&source=s_d&hl=en&geocode=&daddr=" + encodeURIComponent(data.short_address) + "&ie=UTF8&t=h\" onclick=\"window.open(this.href); return false;\" class=\"directions_link\">Directions</a> <a href=\"" + this.slug + "\">Details &raquo;</a></p>";
	if (this.features.length) {
	    this.feature_display = "<p class=\"features\">" + $.map($(this.features), function(i) { return '<span class="feature" style="background-color: #' + i.color + '; color: #FFF;" title="' + i.description + '">' + i.name + '</span>'; }).join(' ') + "</p>";
	}
	if (this.hours.length) {
	    this.display_hours = "<h4>Hours:</h4>\n<div class=\"hours\"><ul>" + $.map(this.hours, function(h){ return ('<li><strong>' + h.day_start + (h.day_end > '' ? (' - ' + h.day_end) : '')) + '</strong>: ' + h.hours + '</li>'; }).join("\n") + "</ul></div>";
	}
	this.map_output = function() { return ["<div class=\"content\">",[this.close_link,this.display_name,this.display_address,this.feature_display,this.display_hours,this.detail_link].join("\n"),"</div>"].join("\n");};
	this.list_output = function() { return [this.display_name,this.rating_info,this.comment_info].join("\n");};
    };

    var getLocations = function(origin,filters) {
	var search_params = {
	    "origin": origin.name,
	    "bounds_ne": map.getBounds().getNorthEast().lat() + ',' + map.getBounds().getNorthEast().lng(),
	    "bounds_sw": map.getBounds().getSouthWest().lat() + ',' + map.getBounds().getSouthWest().lng()
	};
	if (filters.day && filters.time) {
	    if (filters.day == 'now' && filters.time == 'now') {
		var date = new Date();
		search_params.day = ((date.getDay() == 0) ? 7 : date.getDay());
		search_params.time = [sprintf("%02d",date.getHours()),sprintf("%02d",date.getMinutes())].join('.');
	    } else {
		search_params.day = filters.day;
		search_params.time = filters.time;
	    }
	}
	if (filters.features) {
	    search_params.features = filters.features.join(',');
	}
	$.getJSON('/locations/map', search_params, function(msg) {
	    if (msg.length > 0) {
		$.each(msg,function(i) {
		    var l = new Location(this);
		    listInterface.add(l);
		    mapInterface.add(l);
		});
	    } else {
		listInterface.noResults();
	    }
    	    stopLoading();
	});
    };

    var clearLocations = function() {
	mapInterface.clear();
	listInterface.clear();
    };

    var buildFilters = function() {
	var out = {};

	var origin = $('#origin').val();
	var feature_filter = getFeatureFilter();
	var time_filter = getTimeFilter();

	if (origin) { out['origin'] = origin; }
	if (feature_filter.length) { out['features'] = feature_filter; }
	if (time_filter.day && time_filter.time) {
	    out['time'] = time_filter.time;
	    out['day'] = time_filter.day;
	}
	if (currentZoom) { out['zoom'] = currentZoom; };
	return out;
    };

    var getFeatureFilter = function() {
	return $.map($('#search_form .feature'),function(i) {
	    if ($(i).is(':checked')) {
	      return $(i).val();
	    }
	    return null;
	});
    };

    var getTimeFilter = function() {
	if ($('#day_filter_now').is(':checked')) {
	    return {"day": "now", "time": "now"};
	} else if ($('#day_filter').is(':checked')) {
	    return {"day": $('#day').val(), "time": $('#time').val()};
	} else {
	    return {};
	}
    };

    var paramsFromSWFAddress = function() {
	var params = SWFAddress.getValue();
	var out = {};
	$(params.split('/')).each(function() {
	    var split_regex = new RegExp("^(.*?):(.*?)$");
	    if (this > '') {
		out[this.replace(split_regex,"$1")] = unescape(this.replace(split_regex,"$2"));
	    }
	});
	return out;
    };

    var paramsToSWFAddress = function(obj) {
	var out = [];
	for (var i in obj) {
	  out.push([i,obj[i]].join(':'));
	}
	return '/' + out.join('/') + '/';
    };

    var resetForm = function(params) {
        $('#search_form .feature').each(function() { $(this).uncheck(); });
	$('#day_filter_now').uncheck();
	$('#day_filter').uncheck();
	$('#day_filter_select').hide();
	$('#origin').val(params.origin);
	if (params.features) {
	    $(params.features.split(',')).each(function() {
		$('#feature_'+this).check();
	    });
	}
	if (params.day && params.time) {
	    if (params.day == 'now' && params.time == 'now') {
		$('#day_filter_now').check();
	    } else {
		$('#day_filter').check();
		$('#day_filter_select').show();
		$('#day').val(params.day);
		$('#time').val(params.time);
	    }
	}
    };

    var setStars = function(rating) {
      var stars = [];
      for (var i = 0; i < 5; i++) {
	if (i < rating) {
	  stars.push('<img src="/images/rating-star.png" alt="" />');
	} else {
	  stars.push('<img src="/images/rating-no-star.png" alt="" />');
	}
      }
      return stars.join('');
    };

    return {
	init: function(params) {
	    $(window).ready(setDimensions);
	    $(window).bind('resize',setDimensions);
	    $(window).bind('unload',unload);
	    mapInterface.init(params, {"filters": buildFilters()});
	    $('#location_list').ajaxStart(startLoading);
 	    SWFAddress.addEventListener(SWFAddressEvent.CHANGE, this.dispatch);
	},
        dispatch: function(e) {
	  var params = paramsFromSWFAddress();
	  if (params.l && originalCenter) {
	    mapInterface.show(params.l);
	  } else if (lastParams && (!params.l && lastParams.l)) {
	    mapInterface.hide(lastParams.l);
	  } else {
	    SM.search(params);
	  }
	  lastParams = params;
	},
	search: function(params) {
	    // Since we can come to the page fresh and rely on SWFAddress for params,
	    // clear all form entities and reset from values in SWFAddress
	    clearLocations();

	    // If swfaddress params different than the current origin value, set originalCenter to null so it will reset the location
	    if (lastParams && params.origin != lastParams.origin) {
	      originalCenter = null;
	      clearTransientState();
	    }

	    resetForm(params);

	    // We don't want to recenter unless we are called from swfaddress_search, or on init
	    if (!originalCenter) {
	      var origin = $.cookie('lastCenter') || params.origin;
	      $.getJSON('/locations/geocode', {"origin": origin}, function(msg) {
			  var zoom = parseInt(params.zoom || $.cookie('lastZoom') || msg.zoom);
			  if (!$.cookie('trueZoom')) {
			    $.cookie('trueZoom',parseInt(msg.zoom),{'path': '/'});
			  }
			  originalZoom = $.cookie('trueZoom');
			  originalCenter = msg.lat+','+msg.lng;
			  skipZoomDispatch = true;
			  map.setCenter(new GLatLng(msg.lat,msg.lng),zoom);
			  getLocations(msg,buildFilters());
			  skipZoomDispatch = null;
			});
	    } else { // Search using coordinates on current center
	      if (params.zoom || $.cookie('trueZoom') || $.cookie('lastZoom')) {
		var zoom = parseInt(params.zoom || $.cookie('trueZoom') || $.cookie('lastZoom'));
		skipZoomDispatch = true;
		map.setZoom(zoom);
		skipZoomDispatch = null;
	      }
	      var origin = map.getCenter().lat()+','+map.getCenter().lng();
	      getLocations({"name": origin}, buildFilters());
	    }
	    return false;
    	},
	swfaddress_search: function(form) {
  	    lastParams = null;
	    originalCenter = null;
	    currentZoom = null;
	    originalZoom = null;
            $.cookie('trueZoom',null, {"path": '/', "expires": -1});
	    clearTransientState();
 	    SWFAddress.setValue(paramsToSWFAddress(buildFilters()));
	    return false;
	},
	toggleSpecificTime: function() {
	    listInterface.toggleSpecificTime();
	},
	toggleRightNow: function() {
	    listInterface.toggleRightNow();
	}
    };

}();
