﻿(function ($) {
	var resultsId = 'results'
	$.fn.weightCalculator = function (options) {
		var settings = jQuery.extend({
			formulaTypeId: null,
			materialTypeId: null,
			dimensionsPlaceHolderId: null,
			definitionsUrl: null
		}, options);

		$.ajax({
			async: true,
			cache: true,
			context: { element: this, settings: settings },
			dataType: 'xml',
			error: weightCalculator_ajaxError,
			success: weightCalculator_ajaxSuccess,
			url: settings.definitionsUrl
		});

		return this;
	};

	function weightCalculator_ajaxError(request, status, error) {
		alert('Status: ' + status + '\nError: ' + error);
	}

	function weightCalculator_ajaxSuccess(data, request, status) {
		var context = this;

		var shapeTypes = $('#' + this.settings.formulaTypeId)
				.empty()
				.change(function () { displayDimensions(context); });

		var materialTypes = $('#' + this.settings.materialTypeId)
				.empty()
				.change(function () { recalculateDimensions(context); });

		$(data).find("shapes[type=3d] shape").each(function () {
			var shape = $(this);

			appendOptionToSelect(shapeTypes, shape.attr('type'), shape.attr('volume'));
		});

		$(data).find("material").each(function () {
			var material = $(this);

			appendOptionToSelect(materialTypes, material.attr('type'), material.attr('units'));
		});

		displayDimensions(context);
	}

	function displayDimensions(context) {
		var dimensionsPlaceholder = $('#' + context.settings.dimensionsPlaceHolderId).empty();

		var option = $('#' + context.settings.formulaTypeId + ' option:selected').each(function () {
			var dimensions = getVariablesFromFormula(this.value);
			for (var index = 0; index < dimensions.length; index++) {
				var inputId = getInputIdFromVariableName(dimensions[index], context);

				dimensionsPlaceholder
					.append('<div class="dimension"><label for="' + inputId + '">' + dimensions[index] + ': </label><input id="' + inputId + '" /></div>')
						.find('input')
							.keyup(function () { recalculateDimensions(context); });
			}
		});

		dimensionsPlaceholder.append('<div id="' + getInputIdFromVariableName(resultsId, context) + '"></div>');
	}

	function getVariablesFromFormula(formula) {
		var variablesRegex = /\{\w+\}/g;

		var match, matches = new Array(), index = 0;
		while (match = variablesRegex.exec(formula)) {
			match = match[0].substring(1, match[0].length - 1);
			matches[index++] = match;
		}

		return matches;
	}

	function getInputIdFromVariableName(variableName, context) {
		return context.settings.formulaTypeId + '_' + variableName;
	}

	function recalculateDimensions(context) {
		var formula = $('#' + context.settings.formulaTypeId + ' option:selected').val();

		var variables = getVariablesFromFormula(formula);

		for (var index = 0; index < variables.length; index++) {
			var variableName = variables[index];
			var value = $('#' + getInputIdFromVariableName(variableName, context)).val();

			var parameterName = '{' + variableName + '}';
			var indexOfParameterName = formula.indexOf(parameterName);
			formula =
				formula.substring(0, indexOfParameterName) +
				value +
				formula.substring(indexOfParameterName + variableName.length + 2, formula.length);
		}

		var materialWeight = parseFloat($('#' + context.settings.materialTypeId).val());

		try {
			var volume = eval(formula).toFixed(3);
			var weight = (volume * materialWeight).toFixed(3);

			setWeight(context, '<div>volume = ' + volume + ' inches<sup>2</sup></div><div>weight = ' + weight + ' pounds</div>');
		}
		catch (e) {
			setWeight(context, formula + ' = invalid');
		}
	}

	function setWeight(context, result) {
		var results = $('#' + getInputIdFromVariableName(resultsId, context)).html(result);
	}
})(jQuery);
