/*jslint browser:true, nomen:true, plusplus:true, devel:true */
/*globals $, utils */

(function () {
	'use strict';
	
	var jCanvas = $('#canvas'), canvas = jCanvas[0], context = canvas.getContext('2d'),
		chaos = new window.Worker('js/chaos.js'), button = $('#pt-gen'), count = $('#pt-num'),
		size_input = $('#pt-size'), render = $('#pt-render'), render_link = render.find('a'),
		vertices_count = $('#pt-vertices'), factor_top = $('#pt-frac-top'), factor_bottom = $('#pt-frac-bottom'),
		form_inputs = $('#parameters form p :input'), padding = 10, verticesColors = [],
		zoom = 1, zoom_out = $('#zoom-out'), zoom_in = $('#zoom-in');
	
	// presets
	$('.setting').click(function (e) {
		var id = parseInt($(this).attr('data-setting-id'), 10);
		
		if ($('#parameters form').prop('disabled')) {
			return;
		}
		
		switch (id) {
		case 1:
			vertices_count.val(3);
			factor_top.val(1);
			factor_bottom.val(2);
			break;
		case 2:
			vertices_count.val(5);
			factor_top.val(3);
			factor_bottom.val(8);
			break;
		case 3:
			vertices_count.val(6);
			factor_top.val(1);
			factor_bottom.val(3);
			break;
		case 4:
			vertices_count.val(5);
			factor_top.val(1);
			factor_bottom.val(3);
			break;
		}
		
		button.click();
	});
	
	// zoom level
	function updateZoomLevel() {
		jCanvas.css({
			width: canvas.width * zoom,
			height: canvas.height * zoom
		});
	}
	
	function setZoomLevel(level) {
		zoom = level;
		
		updateZoomLevel();
	}
	
	zoom_in.click(function () {
		if (zoom < 2) {
			setZoomLevel(zoom + 0.1);
		}
	});
	
	zoom_out.click(function () {
		if (zoom > 0.1) {
			setZoomLevel(zoom - 0.1);
		}
	});
	
	// returns the position of the vertices of a regular polygon with n angles
	// the width and height parameter specifies the radius of the inscripting circle
	function getRegularVertices(width, height, vertices) {
		var i = 0, shapeVerts = [], angle, x = width / 2, y = height / 2,
			rx = width / 2 - padding, ry = height / 2 - padding,
			frac = Math.PI * 2 / vertices;
		
		for (i = 0; i < vertices; i++) {
			angle = frac * i + Math.PI / 2;
			shapeVerts.push([
				Math.cos(angle) * rx + x,
				Math.sin(angle) * ry + y
			]);
		}
		
		return shapeVerts;
	}
	
	// updates rendering button which allows to download the image
	function updateRender() {
		render_link.attr('href', canvas.toDataURL());
	}
	
	// draw the vertices of the current polygon - wth the lines
	function canvasDrawVertices() {
		var width = canvas.width, height = canvas.height,
			vertices = getRegularVertices(width, height, parseInt(vertices_count.val(), 10)),
			vertices_num = vertices.length, i, vertex,
			lastVertex = vertices[vertices_num - 1];
		
		context.clearRect(0, 0, width, height);
		
		// one color per vertex
		verticesColors = [];
		
		for (i = 0; i < vertices_num; i++) {
			verticesColors.push(utils.getRandomColor());
		}
		
		// draw lines
		context.beginPath();
		context.moveTo(lastVertex[0], height - lastVertex[1]);
		
		for (i = 0; i < vertices_num; i++) {
			vertex = vertices[i];
			context.lineTo(vertex[0], height - vertex[1]);
		}
		
		context.stroke();
		
		// draw vertices
		for (i = 0; i < vertices_num; i++) {
			vertex = vertices[i];
			context.fillStyle = utils.rgbToHex(verticesColors[i]);
			
			context.beginPath();
			context.arc(vertex[0], height - vertex[1], 3, 0, Math.PI * 2, true);
			context.fill();
		}
		
		updateRender();
	}
	
	function enableForm(enabled) {
		form_inputs.prop('disabled', !enabled);
		$('#parameters form').prop('disabled', !enabled);
	}
	
	// on generate response from the worker
	$(chaos).on('message', function (e) {
		var points = e.originalEvent.data, length = points.length, i,
			data, pdata, point, index, width = canvas.width,
			vertexColor, height = canvas.height,
			vertices = parseInt(vertices_count.val(), 10);
		
		if (!Array.isArray(points[0])) {
			console.error('Error: ' + points);
			return;
		}
		
		// about the fastest way to draw points array on a canvas:
		// http://jsperf.com/filling-a-bunch-of-points-in-canvas
		data = context.getImageData(0, 0, width, height);
		
		for (i = 0; i < length; i++) {
			point = points[i];
			pdata = point[0];
			vertexColor = verticesColors[point[1]];
			
			index = (parseInt(pdata[0], 10) + (height - parseInt(pdata[1], 10)) * width) * 4;
			
			data.data[index] = vertexColor[0];
			data.data[index + 1] = vertexColor[1];
			data.data[index + 2] = vertexColor[2];
			data.data[index + 3] = 255;
		}
		
		context.putImageData(data, 0, 0);
		enableForm(true);
		updateRender();
	});
	
	// set input size
	size_input.change(function () {
		var size = parseInt($(this).val(), 10);
		
		canvas.width = size + 2 * padding;
		canvas.height = size + 2 * padding;
		
		canvasDrawVertices();
		updateZoomLevel();
	});
	
	// generate
	button.click(function (e) {
		var width = canvas.width, height = canvas.height, shape,
			vertices = parseInt(vertices_count.val(), 10),
			frac = parseInt(factor_top.val(), 10) / parseInt(factor_bottom.val(), 10);
		
		// reset environment
		enableForm(false);
		canvasDrawVertices();
		
		// regular polygon
		shape = getRegularVertices(width, height, vertices);
		
		chaos.postMessage([
			parseInt(count.val(), 10) * width,
			[width, height],
			shape,
			frac
		]);
		
		e.preventDefault();
	});
	
	vertices_count.change(canvasDrawVertices);
	canvasDrawVertices();
}());