//
// Thumbies,
//           a jQuery plugin to render Picasa albums as thumbnails
//
// @author   Paul Koppen
// @version  1.2.0
//
// @update 14 June, 2011 - release v1
// @update 15 June, 2011 - simplified config
// @update 16 June, 2011 - include photo id
// @update 22 June, 2011 - add wrap div
//                       - change title to h3 element
//                       - remove 'numcolumns' config param (just css the width)
// @update 23 June, 2011 - add album.numphotos
// @update 24 June, 2011 - replaced useralbums, singlealbum, and albumphotos by
//                         single function: fetch. arguments (except userid) can
//                         be passed in arbitrary order
// @update 4 July, 2011 - behaviour change: .thumbies(userid) now renders tiles
//                        of all albums instead of selecting the latest album
//                      - added option: numeric album id to specify n-th album
//                      - changed argument: $.thumbies.fetch/photos to
//                        $.thumbies.fetch/getalbums. Now default is to get
//                        photos when both userid and albumid are specified.
// @update 5 July, 2011 - added config option 'link-to' for easier integration
//                        with lightbox plugins (then set it to 'url')
// @update 6 July, 2011 - added 'url' attribute to album objects pointing to the
//                        full cover image (only available when no albumid)
// @update 14 July, 2011 - rewrite of code, release version 1.2.0
//
//
//
//
// On the list:
//
// @todo Specify which photos to fetch from an album
// @todo (automatically) parse data-thumbies-* attributes on tags to derive
//       $.thumbies arguments, so no extra script is needed to render thumbs
// @todo Add width and height attributes to img tags
//
//
//
// Example code:
//
//  In the HTML I have an element <div id="album"></div> in which I would like
//  to render my latest album:
//
//      $('#album').thumbies('userid', 1); // 1 is latest album
//                                         // can also pass 'albumid'
//                                         // or -1 for oldest album
//                                         // or '' for album covers
//
//  The following HTML will be appended to the album div:
//
//      <h3 class="thumbies-title">My Album Title</h3>
//      <div class="thumbies-wrap">
//          <a class="thumbies-link" href="http://picasaweb.google.com/paul.kopp
//              <img class="thumbies-thumb" src="http://...." /></a>
//          <a class="thumbies-link" href="http://picasaweb.google.com/paul.kopp
//              <img class="thumbies-thumb" src="http://...." /></a>
//          <a class="thumbies-link" href="http://picasaweb.google.com/paul.kopp
//              <img class="thumbies-thumb" src="http://...." /></a>
//          ...
//          and so on
//          ...
//      </div>
//
(function($) {

// regex used to convert album thumbnail url to the full image url (photo)
// see $.thumbies.Album
var rephoto = /\/[a-z0-9-]+(\/[^\/]+)$/;


$.thumbies = {
	///-////////////////////////////////////////////////////////////////////////
	//
	// Configuration (defaults)
	//
	
	config: {
		thumbsize:  64,		// for squares: 32, 48, 64, 72, 104, 144, 150, 160
		'link-to': 'link',	// possible values: photo (=image), link (=picasa)
	},
	
	
	///-////////////////////////////////////////////////////////////////////////
	//
	// Objects
	//
	
	Album: function(json, userid) {
		this.id        = json.gphoto$id
						? json.gphoto$id.$t
						: (json.id ? json.id.$t : '');
		this.title     = json.title ? json.title.$t : '';
		this.link      = json.link ? json.link[0].href : '';
		this.numphotos = json.gphoto$numphotos ? json.gphoto$numphotos.$t : '';
		this.thumb     = json.media$group
						? json.media$group.media$thumbnail[0].url
						: (json.icon ? json.icon.$t : '');
		this.photo     = json.media$group
						? json.media$group.media$content[0].url
						: (this.thumb ? this.thumb.replace(rephoto,'$1') : '');
		this.photos    = [];
		
		// extract photos from json, ...
		if (json.entry) {
			for (var i=0,cnt=json.entry.length; i<cnt; i++)
				this.photos.push(new $.thumbies.Photo(json.entry[i]));
			this.numphotos = this.numphotos || this.photos.length;
		}
		
		// ... or use function call to get photos
		this.getphotos = function(/*[params], callback, [force]*/){
			var a=arguments, params={}, callback=null, force=false;
			for (var i=0,cnt=a.length; i<cnt; i++)
				switch (typeof a[i]) {
					case 'object': if(a[i]!=null) params=a[i]; break;
					case 'function': callback=a[i]; break;
					case 'boolean': force=a[i]; break;
					default: alert('Unrecognised argument: '+a[i]);
				}
			// return if photos were already retrieved
			if (this.photos.length > 0 && !force)
				return callback(this.photos);
			// request photos from Picasa Web API otherwise
			$.thumbies.fetch(userid, this.id, params, function(album){
				this.photos = album.photos.slice();
				callback(this.photos);
			});
		};
	},
	
	Photo: function(json) {
		this.id     = json.gphoto$id.$t;
		this.title  = json.title.$t;
		this.link   = json.link[0].href;
		this.thumb  = json.media$group.media$thumbnail[0].url;
		this.photo  = json.media$group.media$content[0].url;
		this.width  = json.media$group.media$content[0].width;
		this.height = json.media$group.media$content[0].height;
		this.type   = json.media$group.media$content[0].type;
		this.medium = json.media$group.media$content[0].medium;
	},
	
	
	///-////////////////////////////////////////////////////////////////////////
	//
	// Picasa API interface
	//
	
	/** $.thumbies.fetch(userid, albumid, params, callback)
	 * Fetch photos or albums from Picasa and return JSON object in callback.
	 *
	 * @param  userid    String with userid. If empty, albumid is a search query
	 * @param  albumid   String. If not empty, list of photos is returned, list
	 *                   of albums otherwise (except when userid is empty too)
	 * @param  params    Object of Picasa Web API parameters
	 * @param  callback  Function to be invoked with the result
	 *
	 * @note: all arguments are required! pass empty strings/objects to 'omit'
	 *        values.
	 */
	fetch: function(userid, albumid, params, callback) {
		if (typeof callback != 'function')
			return alert('$.thumbies.fetch: Invalid callback.');
		
		//
		// catch numeric albumid
		//
		if (typeof albumid == 'number') {
			var num  = albumid,
				args = $.extend({}, params, num>0 ? {'max-results':num} : {});
			// first find the album id, then request the album
			return $.thumbies.fetch(userid, '', args, function(albums){
				var index   = num>0 ? albums.length-1 : albums.length+num,
					albumid = albums[index].id;
				$.thumbies.fetch(userid, albumid, params, callback);
			});
		}
		
		//
		// build url and query parameters
		//
		var url    = 'http://picasaweb.google.com/data/feed/api/',
			args   = $.extend({}, $.thumbies.config, params, {alt:'json'});
		
		if (userid && albumid) {					// specific album
			url        += 'user/' + userid + '/albumid/' + albumid;
			args.fields = 'gphoto:id,title,link[@rel="alternate"](@href),icon,'+
						'gphoto:numphotos,entry(gphoto:id,title,'+
						'link[@rel="alternate"](@href),'+
						'media:group(media:content,media:thumbnail(@url)))';
		}
		else if (userid) {							// albums for user
			url        += 'user/' + userid;
			args.fields = 'entry(gphoto:id,title,gphoto:numphotos,'+
						'link[@rel="alternate"](@href),'+
						'media:group(media:content,media:thumbnail(@url)))';
			args.kind = 'album';
		}
		else if (albumid) {							// photos for search query
			url        += 'all';
			args.fields = 'title,entry(gphoto:id,title,'+
						'link[@rel="alternate"](@href),'+
						'media:group(media:content,media:thumbnail(@url)))';
			args.q      = albumid;	// albumid is query
		}
		else {										// featured photos
			url        += 'featured';
			args.fields = 'id,entry(gphoto:id,title,'+
						'link[@rel="alternate"](@href),'+
						'media:group(media:content,media:thumbnail(@url)))';
		}
		
		delete args['link-to'];		// that is a Thumbies instruction
		
		//
		// fetch the album(s)
		//
		return $.getJSON(url, args, function(data){
			if (args.kind == 'album') {
				var albums = [];
				for (var i=0,cnt=data.feed.entry.length; i<cnt; i++)
					albums.push(new $.thumbies.Album(data.feed.entry[i], userid));
				callback(albums);
			}
			else callback(new $.thumbies.Album(data.feed, userid));
		});
	},
};



///-////////////////////////////////////////////////////////////////////////////
//
// jQuery plugin on HTML objects
//

/** $.fn.thumbies( userid, [albumid], [params], [callback] )
 * Render a Picasa album as thumbnails in the webpage.
 * 
 * @param  userid    String with the Picasa user id
 * @param  albumid   (optional) String with the Picasa album id or number to
 *                   specify n-th album as follows: 1 = latest album, 2 =
 *                   second, ... (so it is 1-indexed). Also, -1 = oldest album,
 *                   -2 = second oldest, and so on
 * @param  params    (optional) Object with optional extra query parameters,
 *                   e.g. {'thumbsize':48} to get 48x48 pixels thumbnails
 *                   For all config options see $.thumbies.config at the top
 *                   of this file, which specifies the defaults
 * @param  callback  (optional) Function to be invoked after all thumbnails
 *                   have been added to the page
 *                   Receives one value: the original jQuery object on which
 *                   thumbies was invoked, i.e., $(this).
 * @return $(this)
 */
$.fn.thumbies = function(userid /*, [albumid], [params], [callback] */ ) {
	// more sophisticated argument parsing allows optional parameters to be
	// left out or even put in arbitrary order. first argument, userid, is
	// fixed though.
	var a=arguments, albumid='', params={}, callback=null;
	for (var i=1,cnt=a.length; i<cnt; i++)
		switch (typeof a[i]) {
			case 'number':
			case 'string': albumid = a[i]; break;
			case 'object': params = a[i]; break;
			case 'function': callback = a[i]; break;
			default: alert('Unrecognised parameter: '+a[i]);
		}
	
	// ref to self and default config
	var self  = $(this);
	
	// Render album covers or photos in an album.
	// @param  photos  Album or photo array as returned by $.thumbies._parse*
	function render(title, photos){
		var linkto = params['link-to'] || $.thumbies.config['link-to'] || 'link';
		self
			//.append($('<h3>')
			//	.addClass('thumbies-title')
			//	.text(title))
			.append($('<div>')
				.addClass('thumbies-wrap')
				.append($.map(photos, function(photo){
					return $('<a>')
						.attr({href:photo[linkto], target:'_blank'})
						.addClass('thumbies-link')
						.append($('<img>')
							.addClass('thumbies-thumb')
							.attr({src:photo.thumb, alt:photo.title}))
						.get();
				}))
			);
		if (typeof callback == 'function')
			callback(self);
	}
	
	// if an album is specified display that one
	// otherwise display all album covers
	// the rest is all covered by $.thumbies.fetch
	$.thumbies.fetch(userid, albumid, params, function(al){
		title = al.title || userid || (albumid ? 'Photos' : 'Picasa Featured Photos');
		render(title, al.photos || al);
	});
	/*
	if (!albumid)	// display album covers
		$.thumbies.fetch(userid, albumid, params, function(albums){
			var title = userid || 'Picasa Featured Photos';
			render(title, userid ? albums : albums.photos);
		});
	else {			// display album photos
		$.thumbies.fetch(userid, albumid, params, function(album){
			var title = album.title || userid || 'Photos';
			render(title, album.photos);
		});
	}
	*/
	// always return the jQuery object to allow linking functions
	return self;
};


})(jQuery);


