/* TODO: Bookmarking a page with an invalid character can mess things up.  e.g. joško */



// set variables required for flickr search and display
var printdpi = 300;
var requestProxy = 'flickrproxy.php';
var requestMethod = 'post';
var requestApiKey = '8bf5e0b223f6d90765db388561a1286b';
var responseFormat = 'json';
var nojsoncallback = 1;

// initialize ajax cache
var ajaxCache = new Hash();

// this function determines whether an ajax response already exists in the cache
function recentlyCached(id) {
	var now = new Date();
	var timeLimitInSeconds = 300;
	
	if (ajaxCache[id] === undefined || !ajaxCache[id] || (ajaxCache[id] && now.getTime()-ajaxCache[id].responseTime.getTime() > timeLimitInSeconds*1000) )
		return false;
	else
		return true;
}

// function to generate a flickr photo URL
function flickrBuildPhotoURL(object) {

	// build hash of sizes and their suffixes
	var sizes = $H({
		'square' : '_s',
		'thumbnail' : '_t',
		'small' : '_m',
		'medium' : '',
		'large' : '_b',
		'original' : '_o'
	});
	
	// if the requested size is the original, some extra information is required
	if (object['size'] == 'original' && object['originalsecret'] && object['originalformat'])
		return 'http://farm' + object['farm'] + '.static.flickr.com/' + object['server'] + '/' + object['id'] + '_' + object['originalsecret'] + '_o' + '.' + object['originalformat'];
	else
		return 'http://farm' + object['farm'] + '.static.flickr.com/' + object['server'] + '/' + object['id'] + '_' + object['secret'] + sizes[object['size']] + '.jpg';

}





/*  prepare YUI history script.  Note: initialization occurs in the calling html document  */

// set the module name. multiple modules are possible, but this page only uses one, which is based on the search form.
var myModule = 'searchform';

// get bookmark state, if any
var myModuleBookmarkedState = YAHOO.util.History.getBookmarkedState(myModule); 

// set initial (default) state, if no bookmarked state is present
var myModuleInitialState = myModuleBookmarkedState || '';

// this function determines what happens when the module state is changed, i.e. after a back/forward click
function myModuleStateChangeHandler(state) {

	// fill out and submit the form
	if (state) fillFormAndPrepareSearch(state);

}

// register the module
YAHOO.util.History.register(myModule, myModuleInitialState, myModuleStateChangeHandler);

// this function determines what happens when the module is first loaded.
YAHOO.util.History.onLoadEvent.subscribe( function() {
	
	// get the current state of the module
	var myModuleCurrentState = YAHOO.util.History.getCurrentState(myModule);

	// if the state is not null, that means the form should be filled out and processed
	if (myModuleCurrentState) fillFormAndPrepareSearch(myModuleCurrentState);
	
} );



function buildBookmarkURL(state) {
	var url = '#' + myModule + '=' + escape(escape(state));
	return url;
}



// this function fills in the search form with the passed "state" values, and prepares the photos search
function fillFormAndPrepareSearch(state) {

	if (state) {
	
		var state = unescape(state);

		// The "state" variable should arrive in queryString format, e.g. key1=value1&key2=value2...  convert it to a hash.
		var searchParams = $H(state.toQueryParams());
		
		// define search form
		var searchform = $('searchform');
		
		
		
		/* TODO: this step is redundant if the searchform 'submit' listener triggered this function */

		// get an array of elements in the form
		var elements = searchform.getElements();
		
		// update elements based on the search parameters
		elements.each( function(element) {

			if (element.type == 'radio' || element.type=='checkbox') {
			
				// find the name of the radio button, because the searchParams object only contains the ID
				var elemName = element.readAttribute('name');
				
				var paramValue = searchParams[elemName];
				
				// check the button if its value matches the searchParam value
				if (paramValue)
					element.checked = (element.value == paramValue);

			} else if (element.type=='text' || element.type=='select-one' || element.type=='textarea' ) {

				var paramValue = searchParams[element.id];
				
				element.value = paramValue;
			
			}

		});
		
		
		
		
	
		// flickr requires either a user, text, or tags for a photo search
		if (searchParams.user || searchParams.text || searchParams.tags) {
	
	
			// if performing a username search, look up the user_id and add it to the cache -- unless that has already been done recently
			if (searchParams.user && searchParams.finduserby == 'username' && !recentlyCached(searchParams.user) ) {
			
				// update status indicator
				$('notice').update('Looking up User ID for \'' + searchParams.user + '\'...');
			
				/* fix this to allow asynchronous: true  */
				// send user_id request to flickr
				new Ajax.Request(requestProxy, { 
					method: requestMethod, 
					parameters: {
						'method': 'flickr.people.findByUsername',
						'api_key': requestApiKey, 
						'format': responseFormat, 
						'nojsoncallback': nojsoncallback,
						'username': searchParams.user
					},
					onSuccess: function(transport) {
						
						if (transport.responseText.evalJSON(true).stat == 'ok') {
							
							// when the user_id is received, add it to the cache
							/* re-write this to use above "parameters" object as the cache key, instead of just the username */
							ajaxCache[searchParams.finduserby+'-'+searchParams.user] = $H({
								'responseJSON' : transport.responseText.evalJSON(true),  // add ".user.nsid" to get user_id
								'responseTime' : new Date()
							});
							
							// do photo search
							doPhotoSearch(searchParams);
						} else {
							$('notice').update('User not found.');
							
						}	
						
					}
				});
				
			// if performing an email search, look up the user_id and add it to the cache -- unless that has already been done recently
			} else if (searchParams.user && searchParams.finduserby == 'email' && !recentlyCached(searchParams.user) ) {
			
				// update status indicator
				$('notice').update('Looking up User ID for \'' + searchParams.user + '\'...');
			
				/* fix this to allow asynchronous: true  */
				// send user_id request to flickr
				new Ajax.Request(requestProxy, { 
					method: requestMethod, 
					parameters: {
						'method': 'flickr.people.findByEmail',
						'api_key': requestApiKey, 
						'format': responseFormat, 
						'nojsoncallback': nojsoncallback,
						'find_email': searchParams.user
					},
					onSuccess: function(transport) {
						
						if (transport.responseText.evalJSON(true).stat == 'ok') {
							
							// when the user_id is received, add it to the cache
							/* re-write this to use above "parameters" object as the cache key, instead of just the email */
							ajaxCache[searchParams.finduserby+'-'+searchParams.user] = $H({
								'responseJSON' : transport.responseText.evalJSON(true),  // add ".user.nsid" to get user_id
								'responseTime' : new Date()
							});
							
							// do photo search
							doPhotoSearch(searchParams);
						} else {
							$('notice').update('User not found.');
							
						}	
						
					}
				});
				
			} else {
				// do photo search
				doPhotoSearch(searchParams);
		
			}
			
			
		} else {
			$('notice').update('Invalid search terms');
		
		}

		
	}

} // end fillFormAndPrepareSearch()






// this function performs the flickr search for photos
function doPhotoSearch(searchParams) {
	
	// update status indicator
	$('notice').update('Requesting photos...');

	// convert strings to numbers
	searchParams.showdimensions = Number(searchParams.showdimensions);
	searchParams.showowners = Number(searchParams.showowners);

	// prepare user id
	// if the search contained a user id, use that
	if (searchParams.finduserby == 'user_id') {
		searchParams.user_id = searchParams.user;
	
	// if the search contained a username or email, use the ID returned by the previous lookup
	} else if (ajaxCache[searchParams.finduserby+'-'+searchParams.user]) {
		searchParams.user_id = ajaxCache[searchParams.finduserby+'-'+searchParams.user].responseJSON.user.nsid;
		
	} else {
		searchParams.user_id = '';
		
	}

	/* TODO: this should be cached */
	// send request for photos
	new Ajax.Request(requestProxy, {
		method: requestMethod,
		parameters: { 
			'method': 		'flickr.photos.search', 
			'api_key': 		requestApiKey, 
			'format': 		responseFormat, 
			'nojsoncallback': nojsoncallback,
			'user_id': 		searchParams.user_id,
			'text': 		searchParams.text,
			'tags': 		searchParams.tags,
			'sort': 		searchParams.sort,
			'page':			searchParams.page ? searchParams.page : 1,
			'per_page': 	searchParams.perpage,
			'extras': 		'original_format'
		}, 
		onSuccess: function(transport) {
			
			// json return variable (sanitized)
			var photosJSON = transport.responseText.evalJSON(true);

			// update status indicator
			$('notice').update('Found '+photosJSON.photos.total+' photos.');
			
			// remove any existing photos from the page
			$('photos').innerHTML = '';

			// scroll to top of photos div
			$('photos').scrollTo();

			// loop through list of photos, creating HTML elements for each one
			for(var i=0, j=photosJSON.photos.photo.length; i < j; i++) {
			
				// create hash from current photo data
				var photo = $H(photosJSON.photos.photo[i]);

				// insert photo into page
				new Insertion.Bottom($('photos'),
					'<div class="photo ' + searchParams.displaysize + '" id="photo' + photo.id + '">'
					+	'<a class="img" href="http://www.flickr.com/photos/' + photo.owner + '/' + photo.id + '">'
					+		'<img alt="' + photo.title + '" src="' + flickrBuildPhotoURL(photo.merge({ 'size': searchParams.displaysize })) + '" />'
					+	'</a>'
					+	(searchParams.showdimensions ? '<div class="dimensions" id="dimensions' + photo.id + '"><em>loading...</em></div>' : '')
					+	(searchParams.showowners ? '<div class="owner" id="owner' + photo.id + '"><em>loading...</em></div>' : '')
					+'</div>'
				);
				
	
				/* TODO: drag & drop */
				// var dd = new YAHOO.util.DD("photo"+photo.id);
				
				
				/* TODO: this should be cached */
				// if requested, get large dimensions of this photo
				if (searchParams.showdimensions) {

					new Ajax.Request(requestProxy, { 
						method: requestMethod, 
						parameters: {
							'method': 'flickr.photos.getSizes',
							'api_key': requestApiKey, 
							'format': responseFormat, 
							'nojsoncallback': nojsoncallback,
							'photo_id': photo.id
						},
						onSuccess: function(transport) {

							var sizesJSON = transport.responseText.evalJSON(true);
							var width = sizesJSON.sizes.size[sizesJSON.sizes.size.length-1].width;
							var height = sizesJSON.sizes.size[sizesJSON.sizes.size.length-1].height;
							var source = sizesJSON.sizes.size[sizesJSON.sizes.size.length-1].source;
							
							var dimensions = $H( { 'screen' : width+'x'+height, 'print' : Math.round(width/printdpi)+'x'+Math.round(height/printdpi) } );
							
							// insert dimensions into page
							var dimensionsdiv = $('dimensions'+photosJSON.photos.photo[this].id);
							dimensionsdiv.innerHTML = '';
							new Insertion.Bottom(dimensionsdiv,
								'<a href="' + source + '">'
								+	'' + dimensions.screen + ' / ' + dimensions.print
								+'</a>'
							);
							
								
						}.bind(i) // bind success function to current iteration in FOR loop. ("this" keyword will refer to the current "i")
					});
				}
				
				
				

				// if requested, show the owner of this photo
				/* TODO: this API call retrieves more than just the Owner, so it should be re-named and re-positioned accordingly */
				if (searchParams.showowners) {
					
					// function to insert owner into the page
					function insertOwnerLink(ownerUserID,ownerUsername,photoID,photoDateTaken) {
						
						var ownerdiv = $('owner'+photoID);
						ownerdiv.innerHTML = '';
	
						// build query params for owner link
						var ownerClickQueryString = $H({
							'user' : ownerUserID,
							'finduserby' : 'user_id',
							'text' : '',
							'tags' : '',
							'sort' : searchParams.sort,
							'perpage' : searchParams.perpage,
							'displaysize' : searchParams.displaysize,
							'showowners' : 0,
							'showdimensions' : (searchParams.showdimensions ? searchParams.showdimensions : 0),
							'highlight' : (searchParams.highlight ? searchParams.highlight : '')
						}).toQueryString();
						
						// build anchor element and insert into div
						var ownerAnchor = document.createElement("a");
						ownerAnchor.setAttribute("href", buildBookmarkURL(ownerClickQueryString));
						ownerAnchor.setAttribute("title", 'Find photos by ' + ownerUsername);
						ownerAnchor.innerHTML = ownerUsername;
						ownerdiv.appendChild(ownerAnchor);
						
						// listen for click on owner anchor
						Event.observe(ownerAnchor, 'click', function(event) {
							YAHOO.util.History.navigate(myModule, escape(ownerClickQueryString));
							Event.stop(event);
						});
						
						
						// insert link to contact list
						var contactsAnchor = document.createElement("a");
						contactsAnchor.setAttribute("href", "javascript:void(0);");
						contactsAnchor.setAttribute("title", 'Show ' + ownerUsername + '\'s contacts');
						contactsAnchor.style.marginLeft = "3px";
						contactsAnchor.style.fontWeight = "bold";
						contactsAnchor.innerHTML = "+";
						ownerdiv.appendChild(contactsAnchor);
						
						// listen for click on contact anchor
						Event.observe(contactsAnchor, 'click', function(event) {
							getContacts(ownerUserID);
							Event.stop(event);
						});
						
					}
					
				
					
					/* TODO: this should be cached */
					new Ajax.Request(requestProxy, { 
						method: requestMethod, 
						parameters: {
							'method': 'flickr.photos.getInfo',
							'api_key': requestApiKey, 
							'format': responseFormat, 
							'nojsoncallback': nojsoncallback,
							'photo_id': photo.id
						},
						onSuccess: function(transport) {
							
							var ownerJSON = transport.responseText.evalJSON(true);
							var ownerUsername = ownerJSON.photo.owner.username;
							var ownerUserID = ownerJSON.photo.owner.nsid;
							var photoDateTaken = ownerJSON.photo.dates.taken;
							var photoID = photosJSON.photos.photo[this].id;
							
							insertOwnerLink(ownerUserID,ownerUsername,photoID,photoDateTaken);
															
						}.bind(i) // bind success function to current iteration in FOR loop. ("this" keyword will refer to the current "i")
					});
					
				}
				
				
				
			} // end FOR loop through photos 

			// insert a div to clear the photos div
			new Insertion.Bottom($('photos'), '<div class="clear"></div>');
			
			
			// empty the page navigation div
			$('pages').innerHTML = '';
			
			
			if (photosJSON.photos.total > 0) {
				
				// determine previous and next pages
				var prevpage = photosJSON.photos.page-1;
				var nextpage = photosJSON.photos.page+1;
				
				// generate a link to the previous page
				var prevPageQueryString = $H({
					'user' : searchParams.user,
					'finduserby' : searchParams.finduserby,
					'text' : searchParams.text,
					'tags' : searchParams.tags,
					'sort' : searchParams.sort,
					'page' : prevpage,
					'perpage' : searchParams.perpage,
					'displaysize' : searchParams.displaysize,
					'showowners' : (searchParams.showowners ? searchParams.showowners : 0),
					'showdimensions' : (searchParams.showdimensions ? searchParams.showdimensions : 0),
					'highlight' : (searchParams.highlight ? searchParams.highlight : '')
				}).toQueryString();
				
				// generate a link to the next page
				var nextPageQueryString = $H({
					'user' : searchParams.user,
					'finduserby' : searchParams.finduserby,
					'text' : searchParams.text,
					'tags' : searchParams.tags,
					'sort' : searchParams.sort,
					'page' : nextpage,
					'perpage' : searchParams.perpage,
					'displaysize' : searchParams.displaysize,
					'showowners' : (searchParams.showowners ? searchParams.showowners : 0),
					'showdimensions' : (searchParams.showdimensions ? searchParams.showdimensions : 0),
					'highlight' : (searchParams.highlight ? searchParams.highlight : '')
				}).toQueryString();
										  
				// insert html into pages div
				new Insertion.Bottom($('pages'),
					  '<span class="previous">'
					+ ( (prevpage > 0) ? '<a href="' + buildBookmarkURL(prevPageQueryString) + '" id="prevAnchor">&laquo;</a>' : '&laquo;')
					+ '</span>'
					+ '&nbsp;Page ' + photosJSON.photos.page + ' of ' + photosJSON.photos.pages + '&nbsp;'
					+ '<span class="next">'
					+ ( (nextpage <= photosJSON.photos.pages ) ? '<a href="' + buildBookmarkURL(nextPageQueryString) + '" id="nextAnchor">&raquo;</a>' : '&raquo;')
					+ '</span><br />'
				);
				
				// listen for next/back click
				Event.observe(prevAnchor, 'click', function(event) {
					YAHOO.util.History.navigate(myModule, escape(prevPageQueryString));
					Event.stop(event);
				});
				Event.observe(nextAnchor, 'click', function(event) {
					YAHOO.util.History.navigate(myModule, escape(nextPageQueryString));
					Event.stop(event);
				});
				
			}
			
		},
		onFailure: function(transport) {
			// update status indicator
			$('notice').update('Ajax failure.');

		}
	}); // end of form.request
	

} // end doPhotoSearch()




/* TODO: Import contacts -- UED?  */
/* TODO: Set cookie to remember recently searched usernames/emails/ids? Someone wants to remember 8257045@N02 and 82198312@N00 without adding to their flickr contacts */

function getContacts(user) {
	new Ajax.Request(requestProxy, { 
		method: requestMethod, 
		parameters: {
			'method': 'flickr.contacts.getPublicList',
			'api_key': requestApiKey, 
			'format': responseFormat, 
			'nojsoncallback': nojsoncallback,
			'per_page' : 66,
			'user_id': user
		},
		onSuccess: function(transport) {
			
			// json return variable (sanitized)
			var contactsJSON = transport.responseText.evalJSON(true);
			
			// empty the contacts div
			$('contacts').innerHTML = '';

			
			/* TODO: Add pagination for long contact lists*/
		
		
			// build Header and UL elements and insert into div
			var userH2 = document.createElement("h2");
			userH2.innerHTML = user + '\'s Contacts';

			var userUL = document.createElement("ul");
			
			$('contacts').appendChild(userH2);
			$('contacts').appendChild(userUL);
			
			var userLinkParams = new Array();
			
			// loop through list of contacts, creating HTML elements for each one
			for(var i=0, j=contactsJSON.contacts.contact.length; i < j; i++) {
			
				// create hash from current contact data
				var contact = $H(contactsJSON.contacts.contact);

				// query params for user link
				userLinkParams[i] = $H({
					'user' : contact[i].nsid,
					'finduserby' : 'user_id',
					'text' : '',
					'tags' : '',
					'sort' : document.getElementById('sort').value,
					'perpage' : document.getElementById('perpage').value,
					'displaysize' : document.getElementById('displaysize').value,
					'showowners' : 1,
					'showdimensions' : 0,
					'highlight' : ''
				}).toQueryString();
				
				// build LI and Anchor elements and insert into div
				var userLI = document.createElement("li");
				
				var userAnchor = document.createElement("a");
				userAnchor.setAttribute("href", buildBookmarkURL(userLinkParams[i]));
				userAnchor.innerHTML = '<img src="' + buildUserIcon(contact[i].nsid,contact[i].iconfarm,contact[i].iconserver) + '" title="' + contact[i].username + '" />';
				
				userLI.appendChild(userAnchor);
				userUL.appendChild(userLI);
				
			
				// listen for click on user anchor
				Event.observe(userAnchor, 'click', function(event) {
					YAHOO.util.History.navigate(myModule, escape(userLinkParams[this]));
					Event.stop(event);
				}.bind(i));
				

			}
			
		}
	});
}





function buildUserIcon(nsid,iconfarm,iconserver) {
	var iconURL = 'http://farm' + iconfarm + '.static.flickr.com/' + iconserver + '/buddyicons/' + nsid + '.jpg';
	return iconURL;
}






// listen for Page Load
Event.observe(window, 'load', function() {
	
	
	// define search form
	var searchform = $('searchform');
	
	// listen for Search Form Submission
	Event.observe(searchform, 'submit', function(event) {
		
		// create a query string from the form values, for the YUI history manager
		var formQueryString = Form.serialize(searchform);

		/* TODO: the query string isn't working with radio buttons OR unchecked checkboxes */
		
		// navigate to a new YUI history "state", named after the form values query string
		YAHOO.util.History.navigate(myModule, escape(formQueryString)); 	
			
		// prevent default form posting
		Event.stop(event);
												
	}); // end of submit event listener
	
	
}); // end of load event listener
