(function($){
	$(function(){
		exports.init();
	});
	
	var exports = {};
	var initializing = false;

	// borrowed from Dojo
	var bind = function(scope, fn) {
		return function() {
			if(typeof fn == "string") {
				fn = scope[fn];
			}
			return fn.apply(scope, arguments);
		};
	};
	var getObject = exports.getObject = function(path,createMissing,scope){
		var obj=scope||window, 
			tokens=path.split('.'), 
			isNumber = function(t) {
				return (/^\d+$/).test(t);
			};
		for(var i=0,p; obj&&(p=tokens[i]); i++){
			if(isNumber(p)) {
				p = parseInt(p, 10);
				obj=(obj.length ? obj[p] : (createMissing?obj[p]=[]:undefined));
			} else {
				obj=(p in obj ? obj[p] : (createMissing?obj[p]={}:undefined));
			}
		}
		return obj;
	};
	
	var getFeedClass = function(elm) {
		var type = ""+elm.getAttribute("data-feedtype");
		var clz = type && exports[type] || InlineFeed;
		switch(type) {
			case "blogger":
				return BloggerFeed;
			case "delicious":
				return DeliciousFeed;
			
			default: 
				return InlineFeed;
		}
	};
	var stripUrls = function(str) {
		var re = /((http|https):\/\/[^\s]+)/g;
		return str.replace(re, '<a href="$1">[url]</a>');
	};
	var InlineFeed = function(elm){
		if(!initializing) {
			this.init && this.init.apply(this, arguments);
		}
	};
	InlineFeed.prototype.url = "";
	InlineFeed.prototype.tmpl = '<li class="entry"><h4><a href="${link}">${title}</a> (${published})</h4><p class="entry-summary">${summary}</p></li>';
	InlineFeed.prototype.init = function(elm){
		this.url = elm.href;
		this.srcNodeRef = elm;
		this.maxItems = Number(elm.getAttribute("data-feedmax") || "5");
		var feed = this, 
			node = this.domNode = document.createElement("div"); 
		elm.parentNode.replaceChild(this.domNode, elm);
		// replace the link with a div to container our listing
		
		$.when(this.load(this.url)).then(function(data){
			// fetch the data
			// render the data
			// inject into container div
			feed.render(data);
		});
	};
	InlineFeed.prototype.load = function(url) {
		return $.getJSON(url);
	};
	InlineFeed.prototype.getItemValue = function(/*Object*/ item, /*String*/property, /*value?*/defaultValue){
		// summary:
		//	Gets the value of an item's 'property'
		//
		//	item: 
		//		The item to get the value from
		//	property: 
		//		property to look up value for	
		//	defaultValue: 
		//		the default value

		var value = void(0), // undefined
			attrData = this.itemPropertyMapping[property] || {}, 
			dotpath = attrData.mapping || null,
			getter = attrData.get || null,
			format = attrData.format;
		
		if(getter) {
			value = attrData.get(item);
		} else if(dotpath){
			// use the mapping to lookup the property value in the item
			value = getObject(dotpath, false, item);
		} else {
			// fallback to a plain property look up
			value = item[property];
		}
		if(format) {
			value = format(value, property, attrData);
		}

		// TODO: lazy-loaded value access not tested
		return typeof value !== "undefined" ? 
				value : defaultValue; // not in item -> return default value
	};
	InlineFeed.prototype.render = function(data) {
		var tmpl = this.tmpl, 
			content = '', 
			items = data.items || [];

		for(var i=0; i<Math.min(this.maxItems, items.length); i++){
			content += tmpl.replace(/\$\{([^\}]+)\}/g, function(m, name){
				return data[name];
			});
		}
		this.domNode.innerHTML = '<ul class="entries">'+content+'</ul>';
	};

	exports.init = function(){
		// TODO: qsa polyfill needed
		var elms = document.querySelectorAll(".inline-feed");
		for(var i=0; i<elms.length; i++){
			var Clz = getFeedClass(elms[i]);
			new Clz(elms[i]);
		}
	};
	exports.InlineFeed = InlineFeed;
	
	
	var BloggerFeed = function(elm){
		if(!initializing) {
			this.init && this.init.apply(this, arguments);
		}
	};
	initializing = true;
	BloggerFeed.prototype = new InlineFeed;
	initializing = false;
	
	BloggerFeed.prototype.itemPropertyMapping = {
		title: { mapping: "title.$t" },
		summary: { 
			mapping:"summary.$t", 
			format: function(str){
				var max = 120;
				str = stripUrls(str);
				return str;
				// return str.length > max ? str.substring(0, 45) + "..." : str;
			}
		},
		published: { 
			mapping: "published.$t",
			format: function(str){
				var date = new Date(str);
				return [
					date.getFullYear(), 
					(1+date.getMonth()),
					date.getDate()
				].join("/");
			}
		},
		link: { get: function(item){
				var links = item.link, 
					value = "";
				for(var i=0; i<links.length; i++){
					if(links[i].rel && links[i].rel == "alternate"){
						value = links[i].href;
						break;
					}
				}
				return value;
			}
		}
	};
	BloggerFeed.prototype.render = function(resp){
		var getter = bind(this, function(item, name){
				return this.getItemValue(item, name, "");
			});

		var tmpl = this.tmpl, 
			content = '', 
			items = resp.feed.entry || [];

		for(var i=0; i<Math.min(this.maxItems, items.length); i++){
			content += tmpl.replace(/\$\{([^\}]+)\}/g, function(m, name){
				return getter(items[i], name);
			});
		}
		this.domNode.innerHTML = '<ul class="entries">'+content+'</ul>';
	};
	
	var DeliciousFeed = function(elm){
		if(!initializing) {
			this.init && this.init.apply(this, arguments);
		}
	};
	initializing = true;
	DeliciousFeed.prototype = new InlineFeed;
	initializing = false;
	
	DeliciousFeed.prototype.itemPropertyMapping = {
		title: { mapping: "d" },
		summary: { mapping:"n" },
		link: { mapping: "u" },
		published: { 
			mapping: "dt",
			format: function(str){
				var date = new Date(str);
				return [
					date.getFullYear(), 
					(1+date.getMonth()),
					date.getDate()
				].join("/");
			}
		}
	};
	DeliciousFeed.prototype.render = function(resp){
		var getter = bind(this, function(item, name){
				return this.getItemValue(item, name, "");
			});

		var tmpl = this.tmpl, 
			content = '', 
			items = resp || [];

		for(var i=0; i<Math.min(this.maxItems, items.length); i++){
			content += tmpl.replace(/\$\{([^\}]+)\}/g, function(m, name){
				return getter(items[i], name);
			});
		}
		this.domNode.innerHTML = '<ul class="entries">'+content+'</ul>';
	};
	
	return exports;
})(jQuery);

