// Mark A. Ziesemer, http://www.ziesemer.com

// https://developer.mozilla.org/en/New_in_JavaScript_1.6#Array_extras
// https://developer.mozilla.org/en/New_in_JavaScript_1.8#More_Array_extras
if(!Array.prototype.every){Array.prototype.every=function(b){if(typeof b!="function"){throw new TypeError()}var a=this.length,d=arguments[1],c;for(c=0;c<a;c++){if(c in this&&!b.call(d,this[c],c,this)){return false}}return true}};
if(!Array.prototype.filter){Array.prototype.filter=function(b){if(typeof b!="function"){throw new TypeError()}var a=this.length,e=new Array(),d=arguments[1],c,f;for(c=0;c<a;c++){if(c in this){f=this[c];if(b.call(d,f,c,this)){e.push(f)}}}return e}};
if(!Array.prototype.forEach){Array.prototype.forEach=function(b){if(typeof b!="function"){throw new TypeError()}var a=this.length,d=arguments[1],c;for(c=0;c<a;c++){if(c in this){b.call(d,this[c],c,this)}}}};
if(!Array.prototype.indexOf){Array.prototype.indexOf=function(b){var a=this.length,c=Number(arguments[1])||0;c=(c<0)?Math.ceil(c):Math.floor(c);if(c<0){c+=a}for(;c<a;c++){if(c in this&&this[c]===b){return c}}return -1}};
if(!Array.prototype.lastIndexOf){Array.prototype.lastIndexOf=function(b){var a=this.length,c=Number(arguments[1]);if(isNaN(c)){c=a-1}else{c=(c<0)?Math.ceil(c):Math.floor(c);if(c<0){c+=a}else{if(c>=a){c=a-1}}}for(;c>-1;c--){if(c in this&&this[c]===b){return c}}return -1}};
if(!Array.prototype.map){Array.prototype.map=function(b){if(typeof b!="function"){throw new TypeError()}var a=this.length,e=new Array(a),d=arguments[1],c;for(c=0;c<a;c++){if(c in this){e[c]=b.call(d,this[c],c,this)}}return e}};
if(!Array.prototype.reduce){Array.prototype.reduce=function(b){var a=this.length>>>0,c,d;if(typeof b!="function"){throw new TypeError()}if(a==0&&arguments.length==1){throw new TypeError()}c=0;if(arguments.length>=2){d=arguments[1]}else{do{if(c in this){d=this[c++];break}if(++c>=a){throw new TypeError()}}while(true)}for(;c<a;c++){if(c in this){d=b.call(null,d,this[c],c,this)}}return d}};
if(!Array.prototype.reduceRight){Array.prototype.reduceRight=function(b){var a=this.length>>>0,c,d;if(typeof b!="function"){throw new TypeError()}if(a==0&&arguments.length==1){throw new TypeError()}c=a-1;if(arguments.length>=2){d=arguments[1]}else{do{if(c in this){d=this[c--];break}if(--c<0){throw new TypeError()}}while(true)}for(;c>=0;c--){if(c in this){d=b.call(null,d,this[c],c,this)}}return d}};
if(!Array.prototype.some){Array.prototype.some=function(b){if(typeof b!="function"){throw new TypeError()}var a=this.length,d=arguments[1],c;for(c=0;c<a;c++){if(c in this&&b.call(d,this[c],c,this)){return true}}return false}};
if(!String.prototype.trim){String.prototype.trim=function(){return this.trimLeft().trimRight()}};
if(!String.prototype.trimLeft){String.prototype.trimLeft=function(){return this.replace(/^\s+/,"")}};
if(!String.prototype.trimRight){String.prototype.trimRight=function(){var a=this.length;while(/\s/.test(this.charAt(--a))){}return this.slice(0,a+1)}};
// http://blogger.ziesemer.com/2008/05/javascript-namespace-function.html
var namespace=function(c,f,b){var e=c.split(f||"."),g=b||window,d,a,h;for(d=0,a=e.length;d<a;d++){h=e[d];if(h.length){g=g[h]=g[h]||{}}}return g};

(function(){
	
	var $D = YAHOO.util.Dom,
		$ = $D.get,
		$E = YAHOO.util.Event,
		pub = namespace("com.ziesemer");
	
	pub.jsDemo = function(ns){
		var html = document.getElementById(ns + "html");
		var output = document.getElementById(ns + "htmlOutput");
		if(html && output){
			output.innerHTML = html.textContent || html.innerText;
		}
		
		var code = document.getElementById(ns + "code");
		if(code){
			eval(code.textContent || code.innerText);
		}
	};
	
	var objToArray = function(obj, sortFn){
		var result = [];
		for(var x in obj){
			result.push({key: x, value: obj[x]});
		}
		
		if(sortFn){
			result.sort(function(x, y){
				return sortFn(x.key, y.key);
			});
		}
		
		return result;
	};
	
	var caseInsensitiveSort = function(x, y){
		var x1 = String(x).toUpperCase();
		var y1 = String(y).toUpperCase();
		if(x1 > y1) return 1;
		if(x1 < y1) return -1;
		return 0;
	};
	
	var caseInsensitiveSortReverse = function(x, y){
		return -caseInsensitiveSort(x,y);
	};
	
	var findPageLink = function(links){
		for(var i=0; i<links.length; i++){
			var link = links[i];
			if(link.rel == "alternate" && link.type == "text/html"){
				return link;
			}
		}
	};
	
	var makeTreeNodeForEntry = function(entry, config){
		var skipYear = 0;
		if(config && config.skipYear){
			skipYear = 5;
		}
		
		var link = findPageLink(entry.link);
		var titleHtml = entry.title.$t;
		if(link){
			titleHtml = "<a href=\"" + link.href + "\">" + titleHtml + "</a>";
		}
		titleHtml += " <span style=\"font-size:75%;\">("
			+ entry.published.$t.substr(skipYear, 10 - skipYear)
			+ ")</span>";
		var node = {type:"html", html:titleHtml};
		return node;
	};
	
	var htmlLinkClickHandler = function(event){
		var target = event.event.target // Standards-compliant
			|| event.event.srcElement; // For IE
		if(target.nodeType == 3){
			target = target.parentNode; // For Safari
		}
		return target.tagName != "A";
	};
	
	var buildDateTree = function(json){
		var entries = json.feed.entry;
		var years = {};
		
		// First, gather all the entries into year / month groups.
		// (The incoming data is not currently guaranteed to be sorted.)
		entries.forEach(function(entry){
			var entryYear = entry.published.$t.substr(0, 4);
			var year = years[entryYear];
			if(!year){
				year = {};
				year.months = {};
				year.recursiveCount = 0;
				years[entryYear] = year;
			}
			year.recursiveCount++;
			
			var entryMonth = entry.published.$t.substr(5, 2);
			var month = year.months[entryMonth];
			if(!month){
				month = {};
				month.dayTimes = {};
				month.recursiveCount = 0;
				year.months[entryMonth] = month;
			}
			month.recursiveCount++;
			
			var entryDayTime = entry.published.$t.substr(8);
			month.dayTimes[entryDayTime] = entry;
		});
		
		var monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
		var blogDate, monthAccurate = true;
		(function(){
			var dateFromUrl = /^https?:\/\/[^\/]+\/(\d{4})_(\d{2})_\d{2}_archive.html(?:[?#\/].*|$)/.exec(document.location);
			if(!dateFromUrl){
				dateFromUrl = /^https?:\/\/[^\/]+\/search\?(?:.+&)?updated-min=(\d{4})-(\d{2})/.exec(document.location);
				if(dateFromUrl){
					monthAccurate = false;
				}
			}
			if(dateFromUrl){
				blogDate = new Date(dateFromUrl[1], dateFromUrl[2] - 1);
			}else{
				blogDate = new Date();
			}
		})();
		
		var treeRootNode = {type:"html", html:"<b>Posts by Date</b> (" + entries.length + ")", children:[], expanded:true};
		
		// Then, for each year / month group, sort and add to tree.
		var sortedYears = objToArray(years, caseInsensitiveSortReverse),
			yearExpanded, monthExpanded;
		sortedYears.forEach(function(year){
			var yearNum = Number(year.key);
			var caption = "<a class=\"post-count-link\" href=\""
				+ "/search?updated-min=" + year.key + "-01-01T00%3A00%3A00-06%3A00&updated-max=" + (yearNum + 1) + "-01-01T00%3A00%3A00-06%3A00\">" + year.key + "</a>"
				+ " <span class=\"post-count\">(" + year.value.recursiveCount + ")</span>";
			
			var yearNode = {type:"html", html:caption, children:[], expanded:(blogDate.getFullYear() == yearNum)};
			if(!yearExpanded && yearNode.expanded){
				yearExpanded = yearNode;
			}
			treeRootNode.children.push(yearNode);
			
			var sortedMonths = objToArray(year.value.months, caseInsensitiveSortReverse);
			sortedMonths.forEach(function(month){
				var monthNum = Number(month.key) - 1;
				var caption = "<a class=\"post-count-link\" href=\""
					+ '/' + year.key + '_' + month.key + "_01_archive.html\">" + monthNames[monthNum] + "</a>"
					+ " <span class=\"post-count\">(" + month.value.recursiveCount + ")</span>";
				
				var monthNode = {type:"html", html:caption, children:[], expanded:(yearNode.expanded && monthAccurate && blogDate.getMonth() == monthNum)};
				if(!monthExpanded && monthNode.expanded){
					monthExpanded = monthNode;
				}
				yearNode.children.push(monthNode);
				
				var sortedDayTimes = objToArray(month.value.dayTimes, caseInsensitiveSortReverse);
				sortedDayTimes.forEach(function(dayTime){
					var dayTimeNode = makeTreeNodeForEntry(dayTime.value, {skipYear:true});
					monthNode.children.push(dayTimeNode);
				});
			});
		});
		
		if(!yearExpanded && treeRootNode.children.length){
			yearExpanded = treeRootNode.children[0];
			yearExpanded.expanded = true;
		}
		if(!monthExpanded && yearExpanded && yearExpanded.children.length){
			monthExpanded = yearExpanded.children[0];
			monthExpanded.expanded = true;
		}
		
		var tree = new YAHOO.widget.TreeView("ziesemerDateTree", treeRootNode);
		tree.subscribe("clickEvent", htmlLinkClickHandler);
		tree.render();
	};
	
	var buildLabelsTree = function(json){
		var entries = json.feed.entry;
		var labels = {};
		entries.forEach(function(entry){
			entry.category.forEach(function(category){
				var term = category.term;
				var labelArr = labels[term];
				if(!labelArr){
					labelArr = [];
					labels[term] = labelArr;
				}
				labelArr.push(entry);
			});
		});
		
		var sortedLabels = objToArray(labels, caseInsensitiveSort);
		
		// Expand to current search label, if one is being viewed.
		var searchLabelMatch = /^https?:\/\/[^\/]+\/search\/label\/([^\/]+)(?:[?#\/].*|$)/.exec(unescape(document.location));
		
		var treeRootNode = {type:"html", html:"<b>Labels</b> (" + sortedLabels.length + ")", children:[], expanded:(searchLabelMatch != null)};
		
		sortedLabels.forEach(function(label){
			var caption = "<a class=\"post-count-link\" href=\""
				+ "/search/label/" + label.key + "\">" + label.key + "</a>"
				+ " <span class=\"post-count\">(" + label.value.length + ")</span>";
			var labelNode = {type:"html", html:caption, children:[], expanded:(searchLabelMatch && searchLabelMatch[1] == label.key)};
			treeRootNode.children.push(labelNode);
			
			label.value.forEach(function(entry){
				var titleNode = makeTreeNodeForEntry(entry);
				labelNode.children.push(titleNode);
			});
		});
		
		var tree = new YAHOO.widget.TreeView("ziesemerLabelTree", treeRootNode);
		tree.subscribe("clickEvent", htmlLinkClickHandler);
		tree.render();
	};
	
	pub.bloggerJSONData = function(json){
		buildDateTree(json);
		buildLabelsTree(json);
	};
	
	$E.onDOMReady(function(){
		// Unfortunately, as of 2010-07-10, the Blogger GData API does not yet support partial responses: http://code.google.com/apis/gdata/docs/2.0/reference.html#PartialResponse
		YAHOO.util.Get.script("http://blogger.ziesemer.com/feeds/posts/default?alt=json-in-script&max-results=999&callback=com.ziesemer.bloggerJSONData");
	});
	
	pub.search = function(){
		var googleSearch = document.forms["googleSearch"],
			opts = googleSearch.sitesearch,
			i, selected;
		for(i=0; i < opts.length && !selected; i++){
			if(opts[i].checked){
				selected = opts[i];
			}
		}
		if(selected && selected.value == "blogger.ziesemer.com"){
			var blogSearch = document.forms["googleBlogSearch"];
			blogSearch.as_q.value = googleSearch.q.value;
			blogSearch.submit();
			return false;
		}
		return true;
	}
	
})();

