(function(){

    var DomReady = window.DomReady = {};

	// Everything that has to do with properly supporting our document ready event. Brought over from the most awesome jQuery. 

    var userAgent = navigator.userAgent.toLowerCase();

    // Figure out what browser is being used
    var browser = {
    	version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
    	safari: /webkit/.test(userAgent),
    	opera: /opera/.test(userAgent),
    	msie: (/msie/.test(userAgent)) && (!/opera/.test( userAgent )),
    	mozilla: (/mozilla/.test(userAgent)) && (!/(compatible|webkit)/.test(userAgent))
    };    

	var readyBound = false;	
	var isReady = false;
	var readyList = [];

	// Handle when the DOM is ready
	function domReady() {
		// Make sure that the DOM is not already loaded
		if(!isReady) {
			// Remember that the DOM is ready
			isReady = true;
        
	        if(readyList) {
	            for(var fn = 0; fn < readyList.length; fn++) {
	                readyList[fn].call(window, []);
	            }
            
	            readyList = [];
	        }
		}
	};

	// From Simon Willison. A safe way to fire onload w/o screwing up everyone else.
	function addLoadEvent(func) {
	  var oldonload = window.onload;
	  if (typeof window.onload != 'function') {
	    window.onload = func;
	  } else {
	    window.onload = function() {
	      if (oldonload) {
	        oldonload();
	      }
	      func();
	    }
	  }
	};

	// does the heavy work of working through the browsers idiosyncracies (let's call them that) to hook onload.
	function bindReady() {
		if(readyBound) {
		    return;
	    }
	
		readyBound = true;

		// Mozilla, Opera (see further below for it) and webkit nightlies currently support this event
		if (document.addEventListener && !browser.opera) {
			// Use the handy event callback
			document.addEventListener("DOMContentLoaded", domReady, false);
		}

		// If IE is used and is not in a frame
		// Continually check to see if the document is ready
		if (browser.msie && window == top) (function(){
			if (isReady) return;
			try {
				// If IE is used, use the trick by Diego Perini
				// http://javascript.nwbox.com/IEContentLoaded/
				document.documentElement.doScroll("left");
			} catch(error) {
				setTimeout(arguments.callee, 0);
				return;
			}
			// and execute any waiting functions
		    domReady();
		})();

		if(browser.opera) {
			document.addEventListener( "DOMContentLoaded", function () {
				if (isReady) return;
				for (var i = 0; i < document.styleSheets.length; i++)
					if (document.styleSheets[i].disabled) {
						setTimeout( arguments.callee, 0 );
						return;
					}
				// and execute any waiting functions
	            domReady();
			}, false);
		}

		if(browser.safari) {
		    var numStyles;
			(function(){
				if (isReady) return;
				if (document.readyState != "loaded" && document.readyState != "complete") {
					setTimeout( arguments.callee, 0 );
					return;
				}
				if (numStyles === undefined) {
	                var links = document.getElementsByTagName("link");
	                for (var i=0; i < links.length; i++) {
	                	if(links[i].getAttribute('rel') == 'stylesheet') {
	                	    numStyles++;
	                	}
	                }
	                var styles = document.getElementsByTagName("style");
	                numStyles += styles.length;
				}
				if (document.styleSheets.length != numStyles) {
					setTimeout( arguments.callee, 0 );
					return;
				}
			
				// and execute any waiting functions
				domReady();
			})();
		}

		// A fallback to window.onload, that will always work
	    addLoadEvent(domReady);
	};

	// This is the public function that people can use to hook up ready.
	DomReady.ready = function(fn, args) {
		// Attach the listeners
		bindReady();
    
		// If the DOM is already ready
		if (isReady) {
			// Execute the function immediately
			fn.call(window, []);
	    } else {
			// Add the function to the wait list
	        readyList.push( function() { return fn.call(window, []); } );
	    }
	};
    
	bindReady();
	
})();

/*
Copyright (c) 2008 Stefan Lange-Hegermann

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

function microAjax(url, callbackFunction)
{
	this.bindFunction = function (caller, object) {
		return function() {
			return caller.apply(object, [object]);
		};
	};

	this.stateChange = function (object) {
		if (this.request.readyState==4)
			this.callbackFunction(this.request.responseText);
	};

	this.getRequest = function() {
		if (window.ActiveXObject)
			return new ActiveXObject('Microsoft.XMLHTTP');
		else if (window.XMLHttpRequest)
			return new XMLHttpRequest();
		return false;
	};

	this.postBody = (arguments[2] || "");

	this.callbackFunction=callbackFunction;
	this.url=url;
	this.request = this.getRequest();
	
	if(this.request) {
		var req = this.request;
		req.onreadystatechange = this.bindFunction(this.stateChange, this);

		if (this.postBody!=="") {
			req.open("POST", url, true);
			req.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
			req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			req.setRequestHeader('Connection', 'close');
		} else {
			req.open("GET", url, true);
		}

		req.send(this.postBody);
	}
}


var tween = {
	add: function(from, to, duration, callback) {
		if (!this.objects) {
			this.objects = [];
		}
		
		var object = {
			from: from,
			change: to - from,
			to: to,
			start: (new Date() - 0),
			duration: duration * 1000,
			callback: callback,
			now: 0
		}
		
		setTimeout(function() {
			object.value = to;
			object.now = 2;
			tween.update();
		}, object.duration);
		
		this.objects.push(object);
		this.update();
	},
	update: function() {
		var self = this;
		
		for (var i=0, len=this.objects.length; i<len; i++) {
			var o = this.objects[i];
			
			if (o) {
				o.now = (new Date() - 0) - o.start;
				o.value = -o.change * (o.now /= o.duration) * (o.now - 2) + o.from;
				o.callback(o.value);
				
				if (o.now > 1) {
					o.value = o.to;
					o.callback(o.value);
					o = null;
					delete this.objects[i];
					this.objects.splice(i, 1);
				}
			}
		}
		
		if (this.objects.length == 0) {
			this.looping = false;
		} else {
			this.looping = true;
		}
		
		if (this.looping) {
			setTimeout(function() {self.update();}, 1);
		}
	}
}

function $(id) {
	return document.getElementById(id);
}

function add_class_name(element, class_name) {
	if (!has_class_name(element, class_name)) {
    	element.className += (element.className ? ' ' : '') + class_name;
	}
}

function remove_class_name(element, class_name) {
	element.className = element.className.replace(new RegExp("(^|\\s+)" + class_name + "(\\s+|$)"), ' ');
}

function has_class_name(element, class_name) {
    var element_class_name = element.className;
    return (element_class_name.length > 0 && (element_class_name == class_name ||
    	new RegExp("(^|\\s)" + class_name + "(\\s|$)").test(element_class_name)));
}

function child_elements(e) {
	var result = [], nodes = e.childNodes;
	for (var i=0, len=nodes.length; i<len; i++) {
		var node = nodes[i];
		if (node.nodeType != 3) {
			result.push(node);
		}
	}
	return result;
}

function get_elements_by_class_name(class_name, node, tag) {
	var class_elements = new Array();
	if (node == null) {node = document;}
	if (tag == null) {tag = '*';}
	if (document.getElementsByClassName) {
		var els = node.getElementsByClassName(class_name),
			els_len = els.length;
		for (i=0, j=0; i<els_len; i++) {
			class_elements[j] = els[i];
			j++;
		}
	}
	
	var els = node.getElementsByTagName(tag),
		els_len = els.length,
		pattern = new RegExp("(^|\\s)"+class_name+"(\\s|$)");

	for (var i=0, j=0; i<els_len; i++) {
		if (pattern.test(els[i].className)) {
			class_elements[j] = els[i];
			j++;
		}
	}
	
	return class_elements;
}

function observe(element, name, handler) {
	if (element.addEventListener) {
		element.addEventListener(name, handler, false);
	} else {
		element.attachEvent("on" + name, handler);
	}
}

function target(event) {
	var t;
	if (!event) {
		var event = window.event;
	}
	if (event.target) {
		t = event.target;
	} else if (event.srcElement) {
		t = event.srcElement;
		if (t.nodeType == 3) {
			t = t.parentNode;
		}
	}
	return t;
}

function stop_event(e) {
	if (e.preventDefault) {
		e.preventDefault();
	} else {
		e.returnValue = false;
	}
	if (e.stopPropagation) {
		e.stopPropagation();
	} else {
		e.cancelBubble = true;
	}
	return false;
}

function wheel(event) {
	var delta = 0;
	if (!event) {
		event = window.event;
	}
	if (event.wheelDelta) {
		delta = event.wheelDelta/120;
	} else if (event.detail) {
		delta = -event.detail/3;
	}
	
	return delta;
}

app = {
	init: function() {
		this.posts = $('posts');
		this.position = [0, 0];
		this.rows = [];
		this.keys = {
			top: {e: $('top'), key: 38}, right: {e: $('right'), key: 39},
			bottom: {e: $('bottom'), key: 40}, left: {e: $('left'), key: 37}
		};
		this.slides = [];
		this.stop_loading = has_class_name(this.posts, 'single');
		
		var elements = child_elements(this.posts);
		
		for (var i=0, len=elements.length; i<len; i++) {
			var s = get_elements_by_class_name('slide', elements[i], 'div');
			this.slides = this.slides.concat(s);
			this.rows.push(s.length);
		}
		
		observe(document, 'keydown', this.keypress);
		observe(document, 'click', this.click);
		observe(document, 'mousemove', this.mousemove);
		observe(document.body, 'mousewheel', this.mousewheel);
		observe(window, 'resize', this.resize);
		
		this.resize();
		this.update();
	},
	move: function(p) {
		var post_test = p[0] < this.rows.length && p[0] > -1,
			slide_test = p[1] < this.rows[p[0]] && p[1] > -1,
			self = this;
		
		if (post_test && slide_test && !tween.looping) {
			if (this.position[1] != p[1]) {
				tween.add(-this.position[1]*100, -p[1]*100, 0.5, function(v) {
					self.posts.style.left = v + '%';
				});
			}
			if (this.position[0] != p[0]) {
				tween.add(-this.position[0]*100, -p[0]*100, 0.5, function(v) {
					self.posts.style.top = v + '%';
				});
			}
			this.position = p;
			this.update();
		}
		
		if (this.text_block) {
			this.text_block.style.display = 'none';
			this.text_block = false;
		}
	},
	update: function() {
		var names = ['top', 'right', 'bottom', 'left'];
		for (var i=0; i<4; i++) {
			this.keys[names[i]].e.style.display = 'block';
		}
		
		if (this.position[0] == 0) {
			this.keys.top.e.style.display = 'none';
		}
		
		if (this.position[0] == this.rows.length - 1) {
			this.keys.bottom.e.style.display = 'none';
		}
		
		if (this.position[1] == 0) {
			this.keys.left.e.style.display = 'none';
		}
		
		if (this.position[1] == this.rows[this.position[0]] - 1) {
			this.keys.right.e.style.display = 'none';
		}
		
		if (!this.stop_loading && this.position[0] + 1 == this.rows.length - 1) {
			this.more();
		}
	},
	more: function() {
		var permalink = document.location.pathname,
			offset = this.position[0] + 2,
			url = '/more?permalink=' + permalink + '&offset=' + offset;
			
		add_class_name(app.keys.bottom.e, 'loading');
			
		microAjax(url, function(transport) {
			if (transport.length > 1) {
				var html = eval(transport),
					slides;
					
				for (var i=0; i<html.length; i++) {
					var div = document.createElement('div');
					
					div.className = 'post';
					app.posts.appendChild(div);
					div.innerHTML = html[i];
					slides = get_elements_by_class_name('slide', div, 'div');
					
					if (window.opera) {
						for (var j=0; j<slides.length; j++) {
							var slide = slides[j];
							slide.style.width = $('container').clientWidth + 'px';
						}
					}
					
					app.slides = app.slides.concat(slides);
					app.rows.push(slides.length);
				}
			} else {
				app.stop_loading = true;
			}
			
			remove_class_name(app.keys.bottom.e, 'loading');
		});
	},
	click: function(e) {
		var element = target(e);
		
		if (!element) {
			return;
		}
		
		if (has_class_name(element, 'button')) {
			app.keypress(e);
			return false;
		}
		
		if (has_class_name(element, 'spacebar') || has_class_name(element, 'show') || has_class_name(element, 'hide')) {
			app.toggle_text();
		}
	},
	keypress: function(e) {
		var element = target(e),
			moused = element && has_class_name(element, 'button'),
			code = moused ? app.keys[element.id].key : e.keyCode,
			direction, p;
			
		switch (code) {
			case 38:
				stop_event(e);
				direction = [-1, 0 - app.position[1]];
				break;
			case 40:
				stop_event(e);
				direction = [1, 0 - app.position[1]];
				break;
			case 37:
				stop_event(e);
				direction = [0, -1];
				break;
			case 39:
				stop_event(e);
				direction = [0, 1];
				break;
			case 32:
				stop_event(e);
				app.toggle_text();
				break;
		}
		
		if (!moused) {
			$('hint').style.display = 'none';	
		}
		
		if (direction) {
			p = [app.position[0] + direction[0], app.position[1] + direction[1]];
			app.move(p);
		}
		
		if (window.opera) {
			setTimeout(function() {window.scrollTo(0, 0);}, 1);
		}
		
		return false;
	},
	mousemove: function(e) {
		stop_event(e);
		diy.update(e);
		
		var element = target(e);
		
		if (!element) {
			return false;
		}
		
		if (element.className == 'slide_image') {
			var ns = element.nextSibling;
			var text = ns ? element.nextSibling.nextSibling : false;
			if (text) {
				if (text.className != 'text') {
					text = element.nextSibling;
				}
				if (text) {
					app.text_block = text;
					text.style.display = 'block';
				}
			}
		}
		
		if (element.className == 'slide') {
			if (app.text_block && app.previous_element && app.previous_element.className != 'slide') {
				app.text_block.style.display = 'none';
				app.text_block = false;
			}
		}
		
		if (app.active_menu_item) {
			if (element != app.active_menu_item && element.parentNode != app.active_menu_item) {
				remove_class_name(app.active_menu_item, 'active');
				app.active_menu_item = false;
			}
		}
		
		if (element.className == 'menu_item') {
			var li = element.parentNode;
			if (li.className != 'single') {
				app.active_menu_item = li;
				add_class_name(li, 'active');
			}
		}
		
		app.previous_element = element;
	},
	mousewheel: function(e) {
		var delta = wheel(e), direction, p;
		
		if (delta < -1) {
			direction = [1, 0 - app.position[1]];
		} else if (delta > 1) {
			direction = [-1, 0 - app.position[1]];
		}
		
		if (direction) {
			p = [app.position[0] + direction[0], app.position[1] + direction[1]];
			app.move(p);
		}
	},
	toggle_text: function() {
		var count = this.position[1], current_slide, buttons;
		
		for (var i=0; i<this.position[0]; i++) {
			count += this.rows[i];
		}
		
		current_slide = this.slides[count];
		buttons = current_slide.getElementsByTagName('span');
		
		if (!app.text_block) {
			app.text_block = get_elements_by_class_name('text', current_slide, 'div')[0];
			app.text_block.style.display = 'block';
			buttons[0].style.display = 'none';
			buttons[1].style.display = 'block';
		} else {
			app.text_block.style.display = 'none';
			app.text_block = false;
			buttons[1].style.display = 'none';
			buttons[0].style.display = 'block';
		}
	},
	resize: function(e) {
		var elements = child_elements(app.posts);
		for (var i=0, len=elements.length; i<len; i++) {
			var slides = get_elements_by_class_name('slides', elements[i], 'div')[0],
				s = get_elements_by_class_name('slide', elements[i], 'div');
			slides.style.width = app.posts.offsetWidth * s.length + 'px';
			for (var j=0, l=s.length; j<l; j++) {
				s[j].style.width = app.posts.offsetWidth + 'px';
			}
		}
	}
}

diy = {
	init: function() {
		this.element = $('diy');
		this.images = this.element.getElementsByTagName('img');
		this.path = 0;
		this.sx = 0;
		this.letter = 0;
	},
	update: function(e) {
		var mx = e.clientX;
		this.path = Math.abs(mx - this.sx);
		
		if (this.path > 300) {
			this.path = 0;
			this.sx = mx;
		}
		
		this.letter = Math.floor(this.path / 300 * 3);
		this.letter = this.letter > 2 ? 2 : this.letter;
		
		this.toggle();
	},
	toggle: function(e) {
		for (var i=0; i<3; i++) {
			this.images[i].style.display = 'none';
		}
		this.images[this.letter].style.display = 'block';
	}
}

DomReady.ready(function() {
	app.init();
	diy.init();
});