/**
 * @author John Jessee
 */

flickr = (function(){
	var DataSet = function(path){
		this.data = {};
		this.path = path||[];
		this.index = 0;
	}
	DataSet.prototype = {
		items:function(){
			if(arguments.length==1 && typeof arguments[0] == 'number'){
				return this.items()[arguments[0]];
			}
			var out = this.data || {};
			for(var i=0;i<this.path.length;i++){
				if( out[this.path[i]] ) out = out[this.path[i]];			
			}
			return out;
		},
		load:function(data,path){
			this.data = data;
			this.index = 0;
			this.path = path || this.path;
		},
		count:function(){
			return this.items().length;
		},
		findItem:function(key,value){
			var items = this.items();
			var result = false;
			for(var i=0;i<this.count();i++){
				if(items[i][key] == value){
					result = {
						index:i,
						item:items[i]
					}
					break;
				}
			}
			return result;
		},
		currentItem:function(index){
			if(arguments.length == 0) return this.items(this.index);
			if(typeof arguments[0] == 'number'){
				this.index = arguments[0];
			}
		},
		currentIndex:function(){
			return this.index;
		},
		nextItem:function(index,makeCurrent){
			if(arguments.length == 0){
				return this.nextItem(this.index);
			}
			if (typeof arguments[0] == 'boolean') {
				return this.nextItem(this.index,arguments[0]);
			}
			var outIndex = (arguments[0] == this.count() - 1) ? 0 : index + 1;
			this.currentItem(outIndex);
			return this.items(outIndex);
			
			
			
		},
		previousItem:function(index){
			if(arguments.length == 0){
				return this.previousItem(this.index);
			}
			if (typeof arguments[0] == 'boolean') {
				return this.previousItem(this.index,arguments[0]);
			}
			var outIndex = (arguments[0] == 0) ? this.count() - 1 : index-1;
			this.currentItem(outIndex);
			return this.items(outIndex);
		}
	}
	
	
	var flickrRequest = function(methodName,options){
		this.settings = $.extend({
			method: methodName,
			dataSetPath:[],
			defaultValues:{}
		},options);
		this.listeners = {
			'send':[],
			'receive':[],
			'success':[],
			'failure':[],
			'before':[]
		};
		this.dataSet = this.settings.dataSet || new DataSet(this.settings.dataSetPath);
	};
	flickrRequest.prototype = {
		defaultParams:function(o,replace){
			if(!arguments.length) return this.settings.defaultValues;
			if (replace) {
				this.settings.defaultValues = 0;
				return this;
			}
			$.extend(this.settings.defaultValues,o);
			return this;
		},
		send:function(params,callbacks){
			params = jQuery.extend({},this.settings.defaultValues,params);
			
			var listeners = jQuery.extend({
				onSend : function(){},
				onReceive : function(){},
				onSuccess : function(){},
				onFailure : function(){},
				beforeSend:function(){}
			},callbacks);
			this.listeners = jQuery.extend(this.listeners,listeners);
			
			var data = jQuery.extend({
				'api_key':'25285394ee3ab512238e8ee2b65f6e55',
				'format':'json',
				'jsoncallback':'flickr.callbacks.' + this.settings.method ,
				'method':'flickr.'+ this.settings.method
			},params);
			this.fireEvent('before',this);
			if(this.listeners.beforeSend.call(this) == false) return;
			this.lastParams = data;
			jQuery.ajax({
				dataType:'jsonp',
				url:'http://api.flickr.com/services/rest/',
				data:data
			});
			return this;
		},
		receive:function(response){
			this.dataSet.load(response);
			this.fireEvent('receive',response);
			this.fireEvent('onReceive',response);
			if(response.stat=='fail'){
				this.fireEvent('failure',response);
				this.fireEvent('onFailure',response);
				return;
			}
			this.fireEvent('success',response);
			this.fireEvent('onSuccess',response);
		},
		fireEvent:function(eventName,data){
			
			var ev = this.listeners[eventName];
			if((typeof ev)== 'function'){
				ev.call(this,data);
				return;
			} 
			for(var i = 0; i<ev.length;i++){
				ev[i].call(this,data);
			}
		},
		addListener:function(eventName,fn){
			if(!this.listeners[eventName]) return this;
			this.listeners[eventName].push(fn);
			return this;
		},
		addListeners:function(o){
			var that = this;
			$.each(o,function(key,value){
				that.addListener(key.toString(),value);
			})
			return this;
		},
		removeListener:function(eventName,fnName){
			if(arguments.length==1){
				this.listeners[eventName]=[];
			}
			else{
				var ev = this.listeners[eventName];
				var l = ev.length;
				for(var i = 0; i<l;i++){
					if(ev[i] === fnName){
						 ev.splice(i,1);
						 break;
					}
				}
			}
			return this;
		}
	};
	

	return {
		callbacks:{},
		utilities:(function(){
			return {
				maximumSize:function(photo){
					return ((photo.o_height>1024 || photo.o_width>1024)?'b':'d');
				},
				makePhotoURL :function(size,format,farmId,serverId,id,secret){
					size = size || 't';
					format = format || 'jpg';
					
					if (typeof arguments[2] == 'object'){
						var photo = arguments[2];
						var secret = photo.secret;
						if (size == 'o') {
							secret = photo.originalsecret;
						}
						return this.makePhotoURL(size,format, photo.farm,photo.server,photo.id,secret)
					}
					
					return 'http://farm'+farmId+'.static.flickr.com/'+serverId+'/'+id+'_'+secret+'_'+size+'.'+ format;
				}
			}
		})(),
		addMethod:function(name,path,options){
			
			options = $.extend({
				dataSetPath : []
			},options)
			
			if (typeof path == 'object') {
				var m = this;
				var c = this.callbacks;
				for (var i = 0; i < path.length; i++) {
					if (m[path[i]]) {
						m = m[path[i]];
						c = c[path[i]];
					}
					else{
						m = m[path[i]] = {};
						c = c[path[i]] = {};
					}	
				}
				
				m[name] = new flickrRequest(path.join('.') + '.' + name, options);
				c[name] = function(response){
					m[name].receive.call(m[name], response)
				}
			}
			else {
			
				this[path] = this[path] || {};
				this.callbacks[path] = this.callbacks[path] || 	{};
				this.callbacks[path][name] = function(response){
					window.flickr[path][name].receive.call(window.flickr[path][name], response);
				};
				this[path][name] = new flickrRequest(path + '.' + name, options);
			}
		}
	}
})();
