if ( Object.isUndefined(CodeCompany) ) { var CodeCompany = {}; }
if ( Object.isUndefined(window.console) ) { window.console = { log: function() { } }; }

CodeCompany.ShopFinderApp = Class.create({
	initialize: function(id, target, options) {
		this.options = Object.extend({
			defaultLocation: { lat: 0, lng: 0, zoom: 5 },
			locale: 'en_US',
			shopCount: 4,
			
			showAllShopsAtLoad: false,
			
			useCustomIcon: false,
			useAlternateIcon: false
		}, options || {});
		
		this.options.localization = Object.extend({
			addressLabel: "Indtast din adresse",
			searchLabel: "Find butik",
			addressNotFound: "The address could not be found. Please try again.",
			distanceInKm: "Afstand ca. #{distance} km.",
			routeInfo: "Distance of the route: #{routeinfo}",
			backToResults: "Back to results",
			favoriteLabel: 'Vælg som "Min butik"',
			removeFavoriteLabel: 'Remove as favorite',
		
			shopLinkLabel: 'Se butikkens side',
		
			appHeader: 'Find butik',
			resultsHeader: 'Resultat',
			directionsHeader: 'Kørselsvejledning',
			
			introText: 'Noget introtext her'
		}, options.localization || {} );
		
		this.options.customIcon = Object.extend({
			/*
			markerIcon: "http://devel.garant.nu/files/garant.nu/design/gfx/gmap_garant.png",
			markerShadow: "http://devel.garant.nu/files/garant.nu/design/gfx/gmap_garant_shadow.png"
			*/
			markerIcon: "",
			markerShadow: ""
		}, options.customIcon || {});
		
		if ( !Object.isUndefined(options.customIcon) )
		{
			this.options.customIcon.iconSize = Object.extend({
				w: 32,
				h: 32
			}, options.customIcon.iconSize || {});
		
			this.options.customIcon.shadowSize = Object.extend({
				w: 32,
				h: 32
			}, options.customIcon.shadowSize || {});
		
			this.options.customIcon.iconAnchor = Object.extend({
				x: 0,
				y: 0
			}, options.customIcon.iconAnchor || {});
		
			this.options.customIcon.infoWindowAnchor = Object.extend({
				x: 0,
				y: 0
			}, options.customIcon.infoWindowAnchor || {});
		}
		
		this.options.alternateIcon = Object.extend({
			/*
			markerIcon: "http://devel.garant.nu/files/garant.nu/design/gfx/gmap_garant.png",
			markerShadow: "http://devel.garant.nu/files/garant.nu/design/gfx/gmap_garant_shadow.png"
			*/
			markerIcon: "",
			markerShadow: ""
		}, options.alternateIcon || {});
		
		if ( !Object.isUndefined(options.alternateIcon) )
		{
			this.options.alternateIcon.iconSize = Object.extend({
				w: 32,
				h: 32
			}, options.alternateIcon.iconSize || {});
		
			this.options.alternateIcon.shadowSize = Object.extend({
				w: 32,
				h: 32
			}, options.alternateIcon.shadowSize || {});
		
			this.options.alternateIcon.iconAnchor = Object.extend({
				x: 0,
				y: 0
			}, options.alternateIcon.iconAnchor || {});
		
			this.options.alternateIcon.infoWindowAnchor = Object.extend({
				x: 0,
				y: 0
			}, options.alternateIcon.infoWindowAnchor || {});
		}
		
		this.target = $(target);
		this.id = id;
		
		this.appTemplate = new Template(
			'<div class="gmapcontainer"><div id="mapcontainer_#{id}" class="gmap">&nbsp;</div></div>'+
			'<div id="shopfinderapp_#{id}" class="sidebar">#{sidebar}</div>'+
			'<div id="selectedshop_#{id}" class="routeinfo" style="display:none;"><ul>'+
			'<li class="routesummary"><span id="routeinfo_#{id}"></span></li>'+
			'<li class="favoriteshop" id="favorite_#{id}"></li>'+
			'</ul></div>'+
			'<div id="routecontainer_#{id}" style="display:none; float:right" class="routecontainer">'+
			'<h2>#{directionsHeader}</h2>'+
			'<div id="route_#{id}" class="routedetail"></div>'+
			'</div>'
		);
		
		this.sideBarTemplate = new Template(
			'<h2>#{appHeader}</h2>'+
			'<span class="fieldLabel">#{addressLabel}</span><br />'+
			'<input type="text" class="search" name="address" id="searchaddress_#{id}" /><br />'+
			'<ul class="shopselect">'+
			'<li><input type="checkbox" id="floors_#{id}" class="action nostop" checked /><span>#{floorLabel}</span></li>'+
			'<li><input type="checkbox" id="curtains_#{id}" class="action nostop" checked /><span>#{curtainsLabel}</span></li>'+
			// '<li><input type="checkbox" id="allShops_#{id}" class="action" checked /><span>#{allLabel}</span></li>'+
			'</ul>'+
			'<div class="appButtonWrapper"><button class="appButton action" id="search_#{id}" title="#{searchLabel}"></button></div>'+
			'<div id="tools_#{id}"></div>'+
			'<div id="results_#{id}" class="results">&nbsp;</div>'/*+
			'<div id="route_#{id}" class="routedetail"></div>'*/
		);
		
		this.resultsTemplate = new Template(
			'<h2 class="resultsheader">#{resultsHeader}</h2>#{results}'
		);
		
		this.resultTemplate = new Template(
			'<div class="shopinfo action #{favorite}" id="shop_#{shopid}"><span class="shopname">#{shopName}</span><br />'+
			'Tlf.: #{tlf}<br />'+
			this.options.localization.distanceInKm+'<br />'+
			'<a href="#{link}" class="shoplink noaction"><span class="noaction">#{shopLinkLabel}</span></a><br />'+
			'<a class="shoplink action" id="#{favoriteaction}_#{shopid}"><span>#{favoritelabel}</span></a>'+
			'</div>'
		);
		
		this.favoriteTemplate = new Template('<button id="#{action}_'+this.id+'" class="action">#{label}</button>');
		
		this.infoTemplate = new Template(
			'<div class="infobubble">'+
			'<h3>#{butiksnavn}</h3>'+
			'#{adresse}<br />'+
			'#{postnr}&nbsp;#{by}<br />'+
			'Tlf: #{tlf}<br />'+
			'<div class="infolinks">'+
			'<a class="shoplink noaction" href="#{link}"><span class="noaction">#{linktext}</span></a>'+
			'#{routelink}'+
			'</div>'+
			'</div>');
		
		this.routeLink = new Template('<br /><a class="shoplink action" id="shop_#{shopid}_#{shopid}"><span>Kørselsvejledning</span></a>'+
		'<script type="text/javascript">$("shop_#{shopid}_#{shopid}").observe("click", this.mapApp_#{appId}.delegatedClick.bindAsEventListener(this.mapApp_#{appId}));</script>')
		
		this.target.update(this.appTemplate.evaluate(Object.extend({
			id: this.id,
			sidebar: this.sideBarTemplate.evaluate(Object.extend({id: this.id }, this.options.localization))
		}, this.options.localization)));
		
		this._state = null;
		
		this._messageBar = null;
		this._overlay = null;
		
		this.currentAddress = null;
		this.gdir = null;
		
		this.selectedShopId = null;
		this.resultBounds = null;
		
		this.loading = true;
		
		this.initApp.bind(this).defer();
	},
	
	initApp: function()
	{
		// this.target.relativize();
		
		this.gmap = new google.maps.Map2(document.getElementById('mapcontainer_'+this.id));
		
		this.gmap.enableDoubleClickZoom();
		this.gmap.enableScrollWheelZoom();
		this.gmap.addControl(new google.maps.SmallZoomControl());
		
		this.gmap.setCenter(new google.maps.LatLng(
			this.options.defaultLocation.lat, 
			this.options.defaultLocation.lng
		), this.options.defaultLocation.zoom);

		this.results = $('results_'+this.id);
		this.routeinfo = $('routeinfo_'+this.id);
		this.routedetail = $('route_'+this.id);
		this.tools = $('tools_'+this.id);
		
		this.routesummary = $('selectedshop_'+this.id);
		this.favoritebutton = $('favorite_'+this.id);
		
		this.geocoder = new google.maps.ClientGeocoder();
		$('shopfinderapp_'+this.id).observe("click", this.delegatedClick.bindAsEventListener(this));
		$('mapcontainer_'+this.id).observe("click", this.delegatedClick.bindAsEventListener(this));
		
		$('searchaddress_'+this.id).observe("keypress", (function(event){ if ( event.keyCode == Event.KEY_RETURN ) { this.onSearch(true); } }).bind(this));
		$('searchaddress_'+this.id).activate();
		
		this.markericon = null;
		
		if ( this.options.useCustomIcon )
		{
			this.markericon = new google.maps.Icon();
			this.markericon.image = this.options.customIcon.markerIcon;
			this.markericon.shadow = this.options.customIcon.markerShadow;
			this.markericon.imageSize = new google.maps.Size(this.options.customIcon.iconSize.w,this.options.customIcon.iconSize.h);
			this.markericon.shadowSize = new google.maps.Size(this.options.customIcon.shadowSize.w, this.options.customIcon.shadowSize.h);
			this.markericon.iconAnchor = new google.maps.Point(this.options.customIcon.iconAnchor.x,this.options.customIcon.iconAnchor.y);
			this.markericon.infoWindowAnchor = new google.maps.Point(this.options.customIcon.infoWindowAnchor.x,this.options.customIcon.infoWindowAnchor.y);
		}
		
		if ( this.options.useAlternateIcon )
		{
			this.altMarkericon = new google.maps.Icon();
			this.altMarkericon.image = this.options.alternateIcon.markerIcon;
			this.altMarkericon.shadow = this.options.alternateIcon.markerShadow;
			this.altMarkericon.imageSize = new google.maps.Size(this.options.alternateIcon.iconSize.w,this.options.alternateIcon.iconSize.h);
			this.altMarkericon.shadowSize = new google.maps.Size(this.options.alternateIcon.shadowSize.w, this.options.alternateIcon.shadowSize.h);
			this.altMarkericon.iconAnchor = new google.maps.Point(this.options.alternateIcon.iconAnchor.x,this.options.alternateIcon.iconAnchor.y);
			this.altMarkericon.infoWindowAnchor = new google.maps.Point(this.options.alternateIcon.infoWindowAnchor.x,this.options.alternateIcon.infoWindowAnchor.y);
		}
		
		this.setState(new CodeCompany.ShopFinderStateDefault(this));
	},
	
	setState: function(newState)
	{
		this._state = newState;
		this._state.updateGUI();
	},
	
	getState: function() { return this._state; },
	
	_actionElem: function(e)
	{
		return ( e.element().hasClassName('action') ) ? e.element() : e.element().up('.action');
	},
	
	delegatedClick: function(e)
	{
		if ( !e.element().hasClassName('noaction') )
		{
			if ( actionElem = this._actionElem(e) )
			{
				var tokens = actionElem.identify().split('_');
				this.handleClick(tokens[0], tokens[1]);
				if ( !e.element().hasClassName('nostop') )
				{
					Event.stop(e);
				}
			}
		}
	},
	
	handleClick: function(action, id)
	{
		console.log('click');
		switch (action)
		{
			case 'search':
				this.onSearch(true);
			break;
			
			case 'shop':
				this._state.onShopClick(id);
			break;
			
			case 'showresults':
				this.showResults();
			break;
			
			case 'markfavorite':
				this.markAsFavorite(id);
			break;
			
			case 'removefavorite':
				this.markAsFavorite('');
			break;
		}
	},
	
	filterClick: function(action)
	{
		if ( $('curtains_'+this.id).checked || $('floors_'+this.id).checked )
		{
			this.onSearch(false);
		}
	},
	
	onSearch: function(directSearch)
	{
		this._state.onSearch(directSearch);
	},
	
	showOverlay: function()
	{
		return;
		
		if ( !this._overlay )
		{
			this._overlay = new Element('div', { className: "mapOverlay", style: "display: none; position: absolute;" });
			this.target.insert(this._overlay);
		}
		
		(function(){
			this._overlay.show();
			this._overlay.clonePosition(this.target);
			this._overlay.setOpacity(0.4);
		}).bind(this).defer();
	},
	
	hideOverlay: function()
	{
		if ( this._overlay )
		{
			this._overlay.hide();
		}
	},
	
	showMessage: function(msg)
	{
		if ( !this._messageBar )
		{
			this._messageBar = new Element('div', { className: "messageBar", style: "display:none; position: absolute; top:4px; left:4px;"});
			this.target.insert(this._messageBar);
		}
		
		(function(){
			this._messageBar.makePositioned();
			this._messageBar.update('<span>'+msg+'</span>');
			this._messageBar.appear({ duration: 0.4 });
			
			(function(){
				this._messageBar.fade({ duration: 2 });
			}).bind(this).delay(5);
		}).bind(this).defer();
	},
	
	findShops: function()
	{
		if ( this.currentAddress )
		{
			var searchCriteria = { };
			
			this.currentShops = this.options.locationFinder.findNearest(
				this.currentAddress.lat(), 
				this.currentAddress.lng(), 
				this.options.shopCount,
				searchCriteria
			);
		}
	},
	
	renderSidebarResults: function()
	{
		this.results.update();
		var favShop = this.getFavoriteShop();
		var result = "";
		
		// render sidebar results
		this.currentShops.each(function(shop) {
			result += this.resultTemplate.evaluate({
				shopid: shop.location.data.butiksnr,
				shopName: shop.location.data.butiksnavn,
				shopAddress: shop.location.data.by,
				distance: shop.distance,
				tlf: shop.location.data.tlf,
				link: shop.location.data.link,
				shopLinkLabel: this.options.localization.shopLinkLabel,
				favorite: (shop.location.data.butiksnr == favShop)?'favoriteshop':'',
				favoriteaction: (shop.location.data.butiksnr == favShop)?'removefavorite':'markfavorite',
				favoritelabel: (shop.location.data.butiksnr == favShop)?this.options.localization.removeFavoriteLabel:this.options.localization.favoriteLabel
			});
		}, this);
		
		this.results.update(this.resultsTemplate.evaluate(Object.extend(this.options.localization, { results: result })));
		
		this.results.show();
	},
	
	renderShops: function(selectFavorite)
	{
		if ( selectFavorite == null ) { selectFavorite = false; }
		this.gmap.clearOverlays();
		
		this.selectedShopId = null;
		
		this.resultBounds = new google.maps.LatLngBounds();
		this.resultBounds.extend(this.currentAddress);
		
		this.currentShops.each(function(shop) {
			var markerPoint = new google.maps.LatLng(shop.location.data.lat, shop.location.data.lng);
			var marker = new google.maps.Marker(markerPoint, { icon: (shop.location.data.drop!='')?this.altMarkericon:this.markericon });
			
			var routeLink = this.routeLink.evaluate({shopid: shop.location.data.butiksnr, appId: this.id });
			
			marker.bindInfoWindowHtml(this.infoTemplate.evaluate(Object.extend({ routelink: routeLink, linktext: this.options.localization.shopLinkLabel }, shop.location.data)));
			// events
			// google.maps.Event.addListener(marker, "click", this.onShopClick.bind(this, shop.location.data.butiksnr));
			
			google.maps.Event.addListener(marker, "mouseover", this.hoverShop.bind(this, shop.location.data.butiksnr, true));
			google.maps.Event.addListener(marker, "mouseout", this.hoverShop.bind(this, shop.location.data.butiksnr, false));
			
			this.gmap.addOverlay(marker);
			this.resultBounds.extend(markerPoint);
		}, this);
		
		this.renderSidebarResults();
		
		this.gmap.setCenter(this.resultBounds.getCenter(), this.gmap.getBoundsZoomLevel(this.resultBounds));
		if ( !selectFavorite )
		{
			// set zoom to show all shops in list
		}
		else
		{
			/*
			// select nearest shop
			this.onShopClick(this.currentShops[0].location.data.butiksnr);
			*/
			// Select Favorite
			var favShop = this.getFavoriteShop();
			if ( this.currentShops.find(function(shop){ return shop.location.data.butiksnr == favShop; }) )
			{
				this.onShopClick(this.getFavoriteShop());
			}
		}
	},
	
	showResults: function()
	{
		this.reset();
		this.renderShops(false);
	},
	
	selectShop: function(id)
	{
		var current = this.results.down('.selectedshop');
		
		if ( current )
		{
			current.removeClassName('selectedshop');
		}
		
		$('shop_'+id).addClassName('selectedshop');
		this.selectedShopId = id;
	},
	
	hoverShop: function(id, mouseIn)
	{
		var hover = $('shop_'+id);
		
		if ( mouseIn )
		{
			hover.addClassName('hoveredshop');
		}
		else
		{
			hover.removeClassName('hoveredshop');
		}
	},
	
	onShopClick: function(id)
	{
		// this.gmap.clearOverlays();
		this.selectShop(id);

		var shop = this.currentShops.find(function(s){ return s.location.data.butiksnr == id; });
		if ( !this.gdir ) 
		{ 
			this.gdir = new google.maps.Directions(this.gmap, this.routedetail); 
			google.maps.Event.addListener(this.gdir, "addoverlay", this.onDirectionsLoaded.bind(this));
		}
		
		Effect.BlindUp('routecontainer_'+this.id, { queue: 'end', afterFinish: (function(){
			this.gdir.clear();
			this.gdir.load("from: "+this.currentAddress.lat()+","+this.currentAddress.lng()+" to: "+shop.location.data.lat+","+shop.location.data.lng, { "getSteps": true, "locale": this.options.locale });
		}).bind(this) });
	},
	
	onDirectionsLoaded: function()
	{
		var route = this.gdir.getRoute(0);
		var numSteps = route.getNumSteps();
		
		//
		// Ensure that all waypoints is visible on map
		//
		var bounds = new google.maps.LatLngBounds();
		
		// add all waypoints
		for ( var i = 0; i < numSteps; i += 1 )
		{
			var thisStep = route.getStep(i);
			bounds.extend(thisStep.getLatLng());
		}
		
		// center and zoom map to fit 
		this.gmap.setCenter(bounds.getCenter(),this.gmap.getBoundsZoomLevel(bounds));
		
		this.showRouteInfo(route);
	},
	
	showRouteInfo: function(route)
	{
		(function(){ Effect.BlindDown('routecontainer_'+this.id, { queue: 'end' }); }).bind(this).defer();
	},
	
	renderFavoriteButton: function()
	{
		// update favorite button
		var favShop = this.getFavoriteShop();
		if ( this.selectedShopId == favShop )
		{
			this.favoritebutton.update(this.favoriteTemplate.evaluate({action: 'removefavorite', label: this.options.localization.removeFavoriteLabel }));
		}
		else
		{
			this.favoritebutton.update(this.favoriteTemplate.evaluate({action: 'markfavorite', label: this.options.localization.favoriteLabel }));
		}
	},
	
	reset: function()
	{
		(function(){ Effect.BlindUp('routecontainer_'+this.id, { queue: 'end' }); }).bind(this).defer();
	},
	
	markAsFavorite: function(id)
	{
		this.setFavoriteShop(id);
		this.renderSidebarResults();
	},
	
	getFavoriteShop: function()
	{
		return CodeCompany.Cookie.read("favoriteshop");
	},
	
	setFavoriteShop: function(id)
	{
		CodeCompany.Cookie.write("favoriteshop", id, 365);
	}
});

CodeCompany.ShopFinderState = Class.create({
	initialize: function(context)
	{
		this.context = context;
	},
	
	updateGUI: function() { },

	onSearch: function() { },
	
	onShopClick: function(id) { }
});

CodeCompany.ShopFinderStateDefault = Class.create(CodeCompany.ShopFinderState, {
	initialize: function($super, context)
	{
		$super(context);
	},
	
	updateGUI: function()
	{
		(function() { this.context.hideOverlay(); }).bind(this).defer();

		if ( this.context.options.showAllShopsAtLoad && this.context.loading )
		{
			this.context.loading = false;
			this.context.options.locationFinder.locations.each(function(location){
					var markerPoint = new google.maps.LatLng(location.data.lat, location.data.lng);
					if ( location.data.drop != '' )
					{
						marker = new google.maps.Marker(markerPoint, { icon: this.context.altMarkericon });
					}
					else
					{
						marker = new google.maps.Marker(markerPoint, { icon: this.context.markericon });
					}
					marker.bindInfoWindowHtml(this.context.infoTemplate.evaluate(Object.extend({ linktext: this.context.options.localization.shopLinkLabel },location.data)));
				
					this.context.gmap.addOverlay(marker);
			}, this);
		}
	},
	
	onSearch: function(directSearch)
	{
		var addr = $('searchaddress_'+this.context.id).value;
		if ( addr != "" )
		{
			if ( addr.toLowerCase().indexOf('denmark') == -1 )
			{
				addr += ', denmark';
			}
			
			this.context.setState(new CodeCompany.ShopFinderStateSearching(this.context));
			this.context._state.directSearch = directSearch;
			// make geocoding request
			this.context.geocoder.getLatLng(addr, this.context.getState().searchCallback.bind(this.context.getState()));
		}
	},
	
	onShopClick: function(id)
	{
		this.context.onShopClick(id);
	}
});

CodeCompany.ShopFinderStateSearching = Class.create(CodeCompany.ShopFinderState, {
	initialize: function($super, context)
	{
		$super(context);
	},
	
	updateGUI: function()
	{
		this.context.gmap.clearOverlays();
		this.context.showOverlay();

		this.context.reset();
	},
	
	searchCallback: function(point)
	{
		if ( point )
		{
			this.context.currentAddress = point;
			
			this.context.findShops();
			this.context.renderShops(this.directSearch);
		}
		else
		{
			this.context.showMessage(this.context.options.localization.addressNotFound);
		}
		
		$('searchaddress_'+this.context.id).activate();
		this.context.setState(new CodeCompany.ShopFinderStateDefault(this.context));
	}
});
