// ==UserScript==
// @name	Flickr Upcoming Event
// @namespace	http://6v8.gamboni.org/
// @description This is a greasemonkey script to enhance flickr pages and be able to easilly associate photos with an upcoming event. When a shot is associated to an event, it can then be tagged and located from the data provided by the event.
// @version        0.2
// @identifier	http://6v8.gamboni.org/IMG/js/flickrupcomingevent.user.js
// @date           2006-09-29
// @creator        Pierre Andrews (mortimer.pa@free.fr)
// @include http://*flickr.com/photos/*/*
// @exclude http://*flickr.com/photos/organize*
// ==/UserScript==

// --------------------------------------------------------------------
//
// This is a Greasemonkey user script.
//
// To install, you need Greasemonkey: http://greasemonkey.mozdev.org/
// Then restart Firefox and revisit this script.
// Under Tools, there will be a new menu item to "Install User Script".
// Accept the default configuration and install.
//
// --------------------------------------------------------------------
// Copyright (C) 2006 Pierre Andrews
// 
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// The GNU General Public License is available by visiting
//   http://www.gnu.org/copyleft/gpl.html
// or by writing to
//   Free Software Foundation, Inc.
//   51 Franklin Street, Fifth Floor
//   Boston, MA  02110-1301
//   USA

var DEBUG = false;

(function () {

	
	//update information
	var SCRIPT = {
		name: "Flickr Upcoming Event",
		namespace: "http://6v8.gamboni.org/",
		description: "This is a greasemonkey script to enhance flickr pages and be able to easilly associate photos with an upcoming event. When a shot is associated to an event, it can then be tagged and located from the data provided by the event.",
		identifier: "http://6v8.gamboni.org/IMG/js/flickrupcomingevent.user.js",
		version: "0.2",								// version
		date: (new Date("2006-09-29"))		// update date
		.valueOf()
	};
	
	function wbr( html ) {
	    return (''+html).replace( /[-\/_.]|\w{20}/g,
				      function( c ){ return c+'<wbr/>'; } );
	}
	
	function M8_log() {
		if(unsafeWindow.console)
			unsafeWindow.console.log(arguments);
		else
			GM_log(arguments);
	}

	function getObjectMethodClosure01(object, method,arg1) {
		return function(arg) {
			return object[method](arg1); 
		}
	}	

	
	function getObjectMethodClosure03(object, method,arg1,arg2,arg3) {
		return function(arg) {
			return object[method](arg1,arg2,arg3); 
		}
	}	

	function getObjectMethodClosure11(object, method,arg1) {
		return function(arg) {
			return object[method](arg,arg1); 
		}
	}	
	function getObjectMethodClosure12(object, method,arg1,arg2) {
		return function(arg) {
			return object[method](arg,arg1,arg2); 
		}
	}	
	function getObjectMethodClosure13(object, method,arg1,arg2,arg3) {
		return function(arg) {
			return object[method](arg,arg1,arg2,arg3); 
		}
	}	

	var flickrupcomingevent = function() {this.init();}

	flickrupcomingevent.prototype = {
		UPCOMING_API_KEY: '684909d568',
		tagged: false,
		canTag: false,
		upcoming_token: GM_getValue('upcoming_token'),
		upcoming_user_name: GM_getValue('upcoming_user_name'),
		upcoming_user_username: GM_getValue('upcoming_user_username'),
		upcoming_user_id: GM_getValue('upcoming_user_id'),

		event_id: '',
		events: {},

		init: function() {
			
			if(unsafeWindow.page_photo_id) {
				var privacy_and_upcoming = document.evaluate(
															 "//p[@class='Privacy']",
															 document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null
				).singleNodeValue;
				
				var div;
				var links = privacy_and_upcoming.getElementsByTagName('a');
				if(links.length > 0) {
					for(var i = 0; i < links.length; i++) {  
						link = links[i];
						var matches;
						if(matches = /http:\/\/upcoming.org\/event\/([0-9]+)/.exec(link.href)) {
							this.tagged = true;
							this.event_id = matches[1];
							break;
						}
					}
					link.parentNode.appendChild(document.createElement('br'));
					div = link.parentNode.appendChild(document.createElement('div'));
				} else {
					privacy_and_upcoming.appendChild(document.createElement('br'));
					div = privacy_and_upcoming.appendChild(document.createElement('div'));
				}
				if(!this.upcoming_token) {
					var img = div.appendChild(document.createElement('img'));
					img.align="left";
					img.alt="Upcoming.org event tool";
					img.src="/images/icon_upcoming_over.gif";
					div.appendChild(document.createTextNode('You first have to authorize the connection with upcoming. First go '));
					var a = div.appendChild(document.createElement('a'));
					a.innerHTML = 'here';
					a.target = 'blank';
					a.href= 'http://upcoming.org/services/auth/?api_key='+this.UPCOMING_API_KEY;
					div.appendChild(document.createTextNode('. When you are done, come back to this page and:'));
					div.appendChild(document.createElement('br'));
					var label = div.appendChild(document.createElement('label'));
					label.htmlFor = 'upcoming_frob';
					label.innerHTML = 'Enter the frob given by upcoming here';
					var input = div.appendChild(document.createElement('input'));
					input.id = 'upcoming_frob';
					var button = document.createElement('button');
					button.type = 'button';
					button.innerHTML = 'Finish authorization';
					button.addEventListener('click',getObjectMethodClosure01(this,'finishAuth',input),true);
					button.className = 'SmallButt';
					div.appendChild(button);
				} else {
					this.upcomingAuthenticated(div);
				}
			}
		},
		
		finishAuth: function(input) {
			this.makeUpcomingCall('auth.getToken',{frob: input.value},getObjectMethodClosure11(this,'authDone',input.parentNode),getObjectMethodClosure11(this,'authError',input.parentNode));
		},

		authDone: function(rsp,div) {
			this.upcoming_token = ''+rsp.token.@token;
			this.upcoming_user_username = ''+rsp.token.@user_username;
			this.upcoming_user_name = ''+rsp.token.@user_name;
			this.upcoming_user_id = ''+rsp.token.@user_id;
			
			GM_setValue('upcoming_token',this.upcoming_token);
			GM_setValue('upcoming_user_username',this.upcoming_user_username);
			GM_setValue('upcoming_user_name',this.upcoming_user_name);
			GM_setValue('upcoming_user_id',this.upcoming_user_id);
			
			this.upcomingAuthenticated(div);
		},

		authError: function(msg,div) {
			GM_setValue('upcoming_token','');
		},

		upcomingAuthenticated: function(div) {
			if(!this.tagged) {
				for each(tag in unsafeWindow.global_photos[unsafeWindow.page_photo_id].tags_rawA) {
					if(tag.indexOf('upcoming:') >= 0) {
						this.tagged = true;
						this.event_id = tag.replace('upcoming:','');
					}
				}
			}
			var tagger = document.getElementById('tagadder');
			if(tagger) {
				this.canTag = true;
			}
			if(this.tagged) {
				div.innerHTML = '<img id="flickrphotocompass_wait" src="http://www.flickr.com/images/pulser2.gif" style="margin:0;padding:0;margin-right:4px;border:0px #ffffff;height: 16px;" /> Getting event details.';
				this.makeUpcomingCall('event.getInfo',{event_id:this.event_id},getObjectMethodClosure11(this,'eventInfoReceived',div),getObjectMethodClosure11(this,'standard_error',div));
			} else {
				if(this.canTag) {
					div.innerHTML = '<img id="flickrphotocompass_wait" src="http://www.flickr.com/images/pulser2.gif" style="margin:0;padding:0;margin-right:4px;border:0px #ffffff;height: 16px;" /> Fetching events.';
					this.makeUpcomingCall('user.getWatchlist',{user_id:this.upcoming_user_id,show:'past'},getObjectMethodClosure11(this,'eventListDetailedReceived',div),getObjectMethodClosure11(this,'standard_error',div));
				}
			}
		},

		eventInfoReceived: function(rsp,div) {
			var event = rsp.event;
			this.events[event.@id] = {id:event.@id,
									  username:event.@username,
									  status:event.@status,
									  name: event.@name,
									  tags: event.@tags,
									  description: event.@description,
									  start_date: event.@start_date,
									  end_date: event.@end_date,
									  start_time: event.@start_time,
									  end_time: event.@end_time, 
									  personal: event.@personal,
									  metro_id: event.@metro_id,
									  venue_id: event.@venue_id,
									  user_id: event.@user_id,
									  category_id: event.@category_id,
									  latitude: event.@latitude,
									  longitude: event.@longitude,
									  geocoding_precision: event.@geocoding_precision,
									  geocoding_ambiguous: event.@geocoding_ambiguous
			};
			this.displayEventInfo(div);
		},

		
		autoTag: function(tags) {
			unsafeWindow.tagrs_addTag(unsafeWindow.page_photo_id,tags);
		},

		displayEventInfo: function(div) {
			div.innerHTML = '';
			div.setAttribute('style','position:relative;left:-18px;');
			event = this.events[this.event_id];
			var ul = div.appendChild(document.createElement('ul'));
			ul.setAttribute('style',"margin: 0 24px;list-style-image:url(/images/icon_upcoming_over.gif);");

			var li = ul.appendChild(document.createElement('li'));
			li.className="Stats";
			li.innerHTML = '<b>Event:</b> <a href="http://www.upcoming.org/event/'+event.id+'">'+event.name+'</a> ';
			if(this.canTag) {
				var a = li.appendChild(document.createElement('a'));
				a.setAttribute('style',"text-decoration: none; color: rgb(201, 201, 201);");
				a.href="javascript:;";
				a.innerHTML = '[+]';
				a.addEventListener('click',getObjectMethodClosure01(this,'autoTag','"'+event.name+'"'),true);
			}

			var li = ul.appendChild(document.createElement('li'));
			li.className="Stats";
			li.innerHTML = '<b>Metro:</b> searching...';
			this.makeUpcomingCall('metro.getInfo',{metro_id:event.metro_id},getObjectMethodClosure11(this,'metroInfoReceived',li),getObjectMethodClosure11(this,'standard_error',li));

			
			var li = ul.appendChild(document.createElement('li'));
			li.className="Stats";
			li.innerHTML = '<b>Venue:</b> searching...';
			this.makeUpcomingCall('venue.getInfo',{venue_id:event.venue_id},getObjectMethodClosure11(this,'venueInfoReceived',li),getObjectMethodClosure11(this,'standard_error',li));


			if(event.description+"") {
				var li = ul.appendChild(document.createElement('li'));
				li.className="Stats";
				li.innerHTML = '<b>Description:</b> '+wbr( event.description );
			}

			var li = ul.appendChild(document.createElement('li'));
			li.className="Stats";
			li.innerHTML = '<b>See other photos</b> from this event by: <a class="Plain" href="'+unsafeWindow.global_photos[unsafeWindow.page_photo_id].ownersUrl+'/tags/upcomingevent'+this.event_id+'">This User</a>, <a class="Plain" href="http://www.flickr.com/photos/tags/upcomingevent'+this.event_id+'">Everyone</a>';
		},

		metroInfoReceived: function(rsp,li) {
			var metro = rsp.metro[0];
			
			this.makeUpcomingCall('state.getInfo',{state_id:metro.@state_id},getObjectMethodClosure12(this,'stateInfoReceived',li,metro),getObjectMethodClosure11(this,'standard_error',li));
		},

		stateInfoReceived: function(rsp,li,metro) {
			var state = rsp.state[0];
		
			this.makeUpcomingCall('country.getInfo',{country_id:state.@country_id},getObjectMethodClosure13(this,'countryInfoReceived',li,metro,state),getObjectMethodClosure11(this,'standard_error',li));
		},
		
		countryInfoReceived: function(rsp,li,metro,state) {
			var country = rsp.country[0];
			li.innerHTML = '<b>Metro:</b> <a href="http://upcoming.org/metro/'+country.@code+'">'+country.@name+'</a> > <a href="http://upcoming.org/metro/'+country.@code+'/'+state.@code+'">'+state.@name+'</a> > <a href="http://upcoming.org/metro/'+country.@code+'/'+state.@code+'/'+metro.@code+'">'+metro.@name+'</a> ';
			if(this.canTag) {
				var a = li.appendChild(document.createElement('a'));
				a.setAttribute('style',"text-decoration: none; color: rgb(201, 201, 201);");
				a.href="javascript:;";
				a.innerHTML = '[+]';
				a.addEventListener('click',getObjectMethodClosure01(this,'autoTag','"'+country.@name+'" "'+state.@name+'" "'+metro.@name+'" "'+country.@name+'>'+state.@name+'>'+metro.@name+'"'),true);
			}
		},

		venueInfoReceived: function(rsp,li) {
			var venue = rsp.venue[0];
			/*<venue id="2142" name="Alex Theatre" address="216 N. Brand Blvd."
			  city="Glendale, CA" zip="91203" phone="818-243-ALEX"
			  url="http://www.alextheatre.org/" description="The 1,450-seat Alex Theatre
			  is a historic, cultural and artistic treasure built in 1925 as the
			  Alexander Theatre, a vaudeville and motion picture house with Greek and
			  Egyptian motifs." user_id="1" private="0"
			  latitude="37.9183" longitude="-122.024" geocoding_precision="zip" 
			  geocoding_ambiguous="0"
			  />*/

			li.innerHTML = '';
			var b = li.appendChild(document.createElement('b'));
			b.innerHTML = 'Venue: ';

			var venue_link = li.appendChild(document.createElement('a'));
			venue_link.href= venue.@url;
			venue_link.innerHTML = venue.@name+' ';
			if(this.canTag) {
				var a = li.appendChild(document.createElement('a'));
				a.setAttribute('style',"text-decoration: none; color: rgb(201, 201, 201);");
				a.href="javascript:;";
				a.innerHTML = '[+]';
				a.addEventListener('click',getObjectMethodClosure01(this,'autoTag','"'+venue.@name+'"'),true);
			}

			var ul = li.appendChild(document.createElement('ul'));
			//			ul.setAttribute('style','list-style-type:none;');

			if(venue.@address+"") {
				var li2 = ul.appendChild(document.createElement('li'));
				li2.className = 'Stats';
				li2.setAttribute('style','list-style-type:none; list-style-image:none;');
				li2.innerHTML = venue.@address+' ';
				if(this.canTag) {
					var a = li2.appendChild(document.createElement('a'));
					a.setAttribute('style',"text-decoration: none; color: rgb(201, 201, 201);");
					a.href="javascript:;";
					a.innerHTML = '[+]';
					a.addEventListener('click',getObjectMethodClosure01(this,'autoTag','"'+venue.@address+'"'),true);
				}
			}

			if(venue.@city+"") {
				var li2 = ul.appendChild(document.createElement('li'));
				li2.className = 'Stats';
				li2.setAttribute('style','list-style-type:none; list-style-image:none;');
				li2.innerHTML = venue.@city+' ';
				if(this.canTag) {
					var a = li2.appendChild(document.createElement('a'));
					a.setAttribute('style',"text-decoration: none; color: rgb(201, 201, 201);");
					a.href="javascript:;";
					a.innerHTML = '[+]';
					a.addEventListener('click',getObjectMethodClosure01(this,'autoTag','"'+venue.@city+'"'),true);
				}
			}

			if(venue.@zip+"") {
				var li2 = ul.appendChild(document.createElement('li'));			
				li2.className = 'Stats';
				li2.setAttribute('style','list-style-type:none; list-style-image:none;');
				li2.innerHTML = venue.@zip+' ';
				if(this.canTag) {
					var a = li2.appendChild(document.createElement('a'));
					a.setAttribute('style',"text-decoration: none; color: rgb(201, 201, 201);");
					a.href="javascript:;";
					a.innerHTML = '[+]';
					a.addEventListener('click',getObjectMethodClosure01(this,'autoTag','"'+venue.@zip+'"'),true);
				}
			}
			
			if(unsafeWindow.global_photos[unsafeWindow.page_photo_id].isOwner && venue.@longitude+"" && venue.@latitude+"" && venue.@geocoding_ambiguous*1 == 0) {
				var li2 = ul.appendChild(document.createElement('li'));
				li2.setAttribute('style','list-style-type:none; list-style-image:none;');
				li2.className = 'Stats';
				var a = li2.appendChild(document.createElement('a'));
				a.setAttribute('style',"text-decoration: none; color: rgb(201, 201, 201);");
				a.innerHTML = "geotag this photo";
				a.href="javascript:;";
				a.addEventListener('click',getObjectMethodClosure03(this,'setLatLon',venue.@latitude,venue.@longitude,venue.@geocoding_precision),true);
			}

		},

		setLatLon: function(lat,lon,precision) {
			var accuracy = 6; //default accuracy is ~region accuracy
			switch(precision) {
				case 'zip':
					accuracy = 11;
					break;
				case 'address':
					accuracy = 16;
					break;
			}
			var listener = {
				flickr_photos_geo_setLocation_onLoad: function(success, responseXML, responseText, params){
					if(DEBUG) M8_log(responseText);
				}
			};
				
			unsafeWindow.F.API.callMethod('flickr.photos.geo.setLocation', {photo_id:unsafeWindow.page_photo_id,lat:lat,lon:lon,accuracy:accuracy}, listener);
		},

		/*		eventListReceived: function(rsp,div) {
				var event_ids = '';
				for each(w in rsp..watchlist) {
				event_ids += ','+w.@event_id;
				}
				event_ids = event_ids.substr(1);
				this.makeUpcomingCall('event.getInfo',{event_id:event_ids},getObjectMethodClosure11(this,'eventListDetailedReceived',div),getObjectMethodClosure11(this,'standard_error',div));

				},*/

		eventListDetailedReceived: function(rsp, div) {
			var select = document.createElement("select");
			select.id = 'upcoming_event_select';
			for each(event in rsp..event) {
				var option = select.appendChild(document.createElement("option"));
				option.value = event.@id;
				option.innerHTML = event.@name+' ('+event.@start_date+')';
				this.events[event.@id] = {id:event.@id,
										  username:event.@username,
										  status:event.@status,
										  name: event.@name,
										  tags: event.@tags,
										  description: event.@description,
										  start_date: event.@start_date,
										  end_date: event.@end_date,
										  start_time: event.@start_time,
										  end_time: event.@end_time, 
										  personal: event.@personal,
										  metro_id: event.@metro_id,
										  venue_id: event.@venue_id,
										  user_id: event.@user_id,
										  category_id: event.@category_id,
										  latitude: event.@latitude,
										  longitude: event.@longitude,
										  geocoding_precision: event.@geocoding_precision,
										  geocoding_ambiguous: event.@geocoding_ambiguous
				};
			}
			var button = document.createElement('button');
			button.type = 'button';
			button.innerHTML = 'Tag';
			button.addEventListener('click',getObjectMethodClosure01(this,'tagPhoto',select),true);
			button.className = 'SmallButt';
			var label = div.appendChild(document.createElement('label'));
			label.htmlFor = 'upcoming_event_select';
			label.innerHTML = 'Select the event this photo was taken at:';
			div.innerHTML = '';
			var img = div.appendChild(document.createElement('img'));
			img.align="left";
			img.alt="Upcoming.org event tool";
			img.src="/images/icon_upcoming_over.gif";
			div.appendChild(label);
			div.appendChild(select);
			div.appendChild(button);
		},

		tagPhoto: function(select) {
			unsafeWindow.tagrs_addTag(unsafeWindow.page_photo_id,'"upcoming:event='+select.value+'" upcoming');
			this.event_id = select.value;
			this.displayEventInfo(select.parentNode);
		},

		makeUpcomingCall: function(method,params,callback,error) {
			var url_params = '';
			for (p in params) {
				url_params += '&'+encodeURIComponent(p)+'='+encodeURIComponent(params[p]);
			}
			if(this.upcoming_token) url_params += '&token='+this.upcoming_token;
			if(DEBUG) M8_log(url_params);
			GM_xmlhttpRequest({method: "GET",
										   url: "http://www.upcoming.org/services/rest/?api_key="+this.UPCOMING_API_KEY+'&method='+encodeURIComponent(method)+url_params,
										   headers: {
				"User-agent": "Mozilla/4.0 (compatible) Greasemonkey",
					"Accept": "application/atom+xml,application/xml,text/xml",
					},
										   onload: function(req) {
											   if(DEBUG) M8_log(req.responseText);
											   var rsp = req.responseText.replace(/<\?xml.*\?>/,'');
											   var rsp = new XML(rsp);
											   
											   if (rsp == null) {
												   error( "Could not understand Upcoming's response. "+req.responseText);
											   }
											   
											   var stat = rsp.@stat;
											   if (stat == null) {
												   error( "Could not find status of Upcoming request. "+req.responseText);
											   }
											   
											   if (stat != 'ok') {
												   if (stat == 'fail') {
													   error("Upcoming error: "+rsp..error.@msg);
												   } else {
													   error("Uknown Upcoming error. "+req.responseText);
												   }
											   }
											   callback(rsp);
										   }
			});
		},

		standard_error: function(msg,div) {
			div.innerHTML = 'There was an error, please see the console for details.';
		}
	}
	//======================================================================
	// launch
	try {
		window.addEventListener("load", function () {
			try {
										
				// update automatically (http://userscripts.org/scripts/show/2296)
				win.UserScriptUpdates.requestAutomaticUpdates(SCRIPT);
			} catch (ex) {} 
				
			var flickrgp = new flickrupcomingevent();
		}, false);
	} catch (ex) {}
})();

