var elements, writer, cursor;

elements = [
	{vertical: false, size: 1, html: '<div class="single"><input type="checkbox" checked="true" /></div>'},
	{vertical: false, size: 1, html: '<div class="single"><input type="checkbox" /></div>'},
	{vertical: false, size: 1, html: '<div class="single"><input type="radio" checked="true" /></div>'},
	{vertical: false, size: 1, html: '<div class="single"><input type="radio" /></div>'},
	{vertical: false, size: 2, html: '<div class="double_horizontal"><input type="button" /></div>'},
	{vertical: false, size: 3, html: '<div class="triple_horizontal"><select><option></option><option></option><option></option></select></div>'},
	{vertical: false, size: 4, html: '<div class="quatro_horizontal"><span class="scrollbar"><span></span></span></div>'},
	{vertical: true, size: 4, html: '<div class="quatro_vertical"><span class="scrollbar"><span></span></span></div>'}
];

cursor_items = {points: [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [0, 7], [0, 8], [0, 9], [0, 10]]};

writer = {
	init: function() {
		this.text = [];
		this.cursor = document.createElement('div');
		this.cursor.className = 'cursor';
		this.fill(this.cursor, cursor_items);
		$('textfield').appendChild(this.cursor);
		
		var load_text = document.location.href.split('#');
		this.input = $('input');
		this.input.focus();
		this.input.value = load_text.length > 1 ? load_text[1] : '';
		observe(window, 'keypress', function(e) {
			writer.input.focus();
		});
		observe(this.input, 'keypress', function(e) {
			writer.keypress(e);
		});
		observe(this.input, 'keyup', function(e) {
			writer.keyup(e);
		});
		observe(this.input, 'blur', function(e) {
			writer.input.focus();
		});
		
		if (load_text.length > 1) {
			this.load(load_text[1]);
		}
		
		this.blink();
	},
	blink: function() {
		if (this.cursor.style.display == 'block') {
			this.cursor.style.display = 'none';
		} else {
			this.cursor.style.display = 'block';
		}
		
		setTimeout(function() {
			writer.blink();
		}, 700);
	},
	save: function() {
		document.location = '#' + encodeURI(this.text.join(''));
	},
	load: function(text) {
		text = decodeURI(text);
		var characters = text.split(''), result, code, character;
		for (var i=0, len=characters.length; i<len; i++) {
			character = characters[i];
			code = character.charCodeAt(0);
			
			if (code == 32) {
				this.space();
			} else {
				result = this.find_by_character(character, this.get_scope(code));
				if (result) {
					this.draw(result);
				}
			}
		}
	},
	keypress: function(e) {
		var code, scope, result, character;
		if (e.which) {
			code = e.which;
		} else if (e.keyCode) {
			code = e.keyCode;
		}
		
		if (!e.metaKey && !e.ctrlKey) {		
			character = String.fromCharCode(code);
			this.modifiers(e, code);
		
			if (code == 32) {
				this.space();
			} else {
				result = this.find_by_character(character, this.get_scope(code));
				if (result) {
					this.draw(result);
				}
			}
		}
	},
	keyup: function(e) {
		var d = this.text.length - this.input.value.length;
		for (var i=0; i<d; i++) {
			this.backspace();
		}
		setTimeout(function() {
			writer.save();
		}, 100);
	},
	get_scope: function(code) {
		if ([33, 44, 45, 46, 63].indexOf(code) > -1) {
			return punctuation;
		} else if (code > 47 && code < 58) {
			return digits;
		} else if (this.shift || this.capslock || (code >= 65 && code <= 90)) {
			return majuscule;
		} else {
			return minuscule;
		}
	},
	modifiers: function(e, code) {
		this.capslock = this.shift = false;
		this.shift = e.shiftKey ? e.shiftKey : ((code == 16) ? true : false);
		
		if (((code >= 65 && code <=  90) && !this.shift) || ((code >= 97 && code <= 122) && this.shift)) {
			this.capslock = true;
		} else {
			this.capslock = false;
		}
	},
	find_by_character: function(character, scope) {
		for (var i=0, len=scope.length; i<len; i++) {
			var s = scope[i];
			if (s.name == character) {
				return s;
			}
		}
		return false;
	},
	draw: function(src) {
		var symbol = {points: []};
		symbol.name = src.name;
		symbol.points = clone(src.points);
		symbol.width = src.width;
		
		var e = document.createElement('div');
		e.className = 'symbol';
		e.style.width = (symbol.width + 1) * 16 + 'px';
		e.style.height = 15 * 16 + 'px';
		
		this.fill(e, symbol);
		this.add(e, symbol.name);
	},
	fill: function(e, symbol) {
		for (var j=0, jlen=symbol.points.length; j<jlen; j++) {
			var point = symbol.points[j], element = this.random_element();
			if (point !== null) {
				while (this.space_test(symbol, point, element.vertical, element.size) != true) {
					element = this.random_element();
				}
				
				e.innerHTML += element.html;
				var divs = e.getElementsByTagName('div'), last = divs[divs.length-1];
				last.style.left = point[0] * 16 + 'px';
				last.style.top = point[1] * 16 + 'px';
			}
		}
	},
	add: function(e, character) {
		if (!this.words) {
			this.new_word();
		}
		
		if (character) {
			this.text.push(character);
		}
		
		var word = this.words[this.words.length-1];
		word.symbols.push(e);
		word.element.appendChild(e);
	},
	space: function() {
		var e = document.createElement('div');
		e.className = 'space';
		this.add(e, ' ');
		this.new_word();
	},
	backspace: function() {
		var word = this.words[this.words.length-1];
		
		if (word.symbols.length == 0 && this.words.length > 1) {
			word.element.parentNode.removeChild(word.element);
			this.words.pop();
		} else {
			var e = word.symbols[word.symbols.length-1];
			if (e) {
				e.parentNode.removeChild(e);
				word.symbols.pop();
				this.text.pop();
			}
		}
	},
	new_word: function() {
		var w = document.createElement('div'),
			o = {element: w, symbols: []};
		w.className = 'word';
		$('textfield').insertBefore(w, this.cursor);
		
		if (!this.words) {
			this.words = [o];
		} else {
			this.words.push(o);
		}
	},
	space_test: function(s, point, is_vertical, size) {
		var points = [], v = 0, h = 0;
		if (is_vertical) {v = 1;}
		else {h = 1;}

		for (var i=0; i<size; i++) {
			var test = [point[0] + h * i, point[1] + v * i], pos = this.indexof(s.points, test);
			if (pos >= 0) {points.push(pos);}
		}

		if (points.length == size) {
			this.lock_points(s, points);
			return true;
		}
		
		return false;
	},
	lock_points: function(s, points) {
		for (var i=0; i<points.length; i++) {
			s.points[points[i]] = null;
		}
	},
	indexof: function(a1, a2) {
		for (var i=0; i<a1.length; i++) {
			if (a1[i] !== null) {
				var p = a1[i];
				if (p[0] == a2[0] && p[1] == a2[1]) {
					return i;
				}
			}
		}
		return -1;
	},
	random_element: function() {
		return elements[Math.floor(random(0, elements.length))];
	}
}

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

function random(min, max) {
	return min + (max-min) * Math.random();
}

function clone(src) {
	return [].concat(src);
}

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

observe(window, 'load', function(e) {
	writer.init(e);
});