/hacks/Labyrinth/Labyrinth.js
/* Copyright 2011 The Dominion of Awesome
 * See COPYING for licensing information */
enyo.kind({
	name: "Labyrinth",
	kind: "Hack",
	style: "background-color: blue",
	preferences: [
		{name: "speed", label: "Speed", kind: "Slider", maximum: 20, minimum: 1, snap: 1},
		{name: "handedness", label: "Left/Right Bias", kind: "Slider", maximum: 1, minimum: 0, snap: 0.01},
		{name: "foregroundColor", label: "Foreground Color", kind: "ListSelector", items: colorList},
		{name: "backgroundColor", label: "Background Color", kind: "ListSelector", items: colorList}
	],
	speed: 5,
	handedness: 0.5,
	foregroundColor: 'white',
	backgroundColor: 'blue',
	grid: null,
	boundary: null,
	count: 0,
	rest: 0,
	components: [
		{name: "viewport", nodeTag: "canvas"}
	],
	rendered: function() {
		this.viewport = this.$.viewport.hasNode();
		this.ctx = this.viewport.getContext('2d');
		this.init();
	},
	start: function() {
		if (!this.timer)
			this.timer = setInterval(this.draw.bind(this), 50);
	},
	stop: function() {
		clearInterval(this.timer);
		this.timer = null;
	},
	resize: function(w, h) {
		this.viewport.width = this.w = w;
		this.viewport.height = this.h = h;

		this.ctx.fillStyle = this.backgroundColor;
		this.ctx.strokeStyle = this.foregroundColor;

		this.ctx.fillRect(0, 0, w, h);

		this.gw = Math.ceil(w / 8);
		this.gh = Math.ceil(h / 8);
		this.grid = new Array(this.gw);
		for (var i = 0; i < this.gw; i++) {
			this.grid[i] = new Array(this.gh);
		}

		var x = Math.floor(Math.random() * this.gw);
		var y = Math.floor(Math.random() * this.gh);
		this.grid[x][y] = Math.random() > this.handedness ? false : true;
		this.boundary = [{x: x, y: y}];
		this.count = 1;
		this.render(x, y);
	},
	preferencesChanged: function() {
		this.init();
	},
	init: function() {
		this.resize(window.innerWidth, window.innerHeight);
	},
	pick: function() {
		var c = this.boundary[Math.floor(Math.random() * this.boundary.length)];
		var possibilities = [];
		for (var x = -1; x <= 1; x++) {
			for (var y = -1; y <= 1; y++) {
				if (y == 0 && x == 0)
					continue;
				if (c.x + x < 0 || c.x + x >= this.gw || c.y + y < 0 || c.y + y >= this.gh)
					continue;
				if (typeof(this.grid[c.x + x][c.y + y]) == 'undefined') {
					possibilities.push({x: c.x + x, y: c.y + y});
				}
			}
		}
		if (possibilities.length == 0) {
			for (var i = 0; i < this.boundary.length; i++) {
				if (this.boundary[i].x == c.x && this.boundary[i].y == c.y) {
					this.boundary.splice(i, 1);
					break;
				}
			}
			return this.pick();
		}

		var nc = possibilities[Math.floor(Math.random() * possibilities.length)];
		this.grid[nc.x][nc.y] = Math.random() > this.handedness ? false : true;
		this.boundary.push(nc);
		return nc;
	},
	render: function(x, y) {
		this.ctx.beginPath();
		if (this.grid[x][y] === true) {
			this.ctx.moveTo(x * 8 + 8, y * 8);
			this.ctx.lineTo(x * 8, y * 8 + 8);
		} else if (this.grid[x][y] === false) {
			this.ctx.moveTo(x * 8, y * 8);
			this.ctx.lineTo(x * 8 + 8, y * 8 + 8);
		}
		this.ctx.stroke();
	},
	draw: function() {
		if (this.rest > 0) {
			if (this.rest == 1)
				this.init();
			this.rest--;
			return;
		}

		for (var i = 0; i < this.speed; i++) {
			var c = this.pick();
			this.render(c.x, c.y);
			this.count++;
			if (this.count == this.gw * this.gh) {
				this.rest = 60;
				return;
			}
		}
	}
});