// JavaScript Document
var CALC = new Object;
CALC.error = new Object;
CALC.error.cap = false;
CALC.error.perf = false;
	
/********************** CALCULATOR ********************************************************************

- Constants are listed first in each object.
- Requirements are calculated next.
- Delivery is calculated from the constants and the requirements
- The Avere Tiered Network (ATN) object is defined first. The Traditional NAS (TN) is defined second.
- Finally, numbers for the graphs (savings) are calculated from the delivered numbers of the ATN and TN objects.
- The rest of the script is for display purposes only.

*/	

function doCalc() {
	CALC.atn = new Object;
	
	CALC.atn.mass = new Object; // MASS disk
		CALC.atn.mass.cap = 0.7; // 0.7 * 1 TB per disk
		CALC.atn.mass.cost = 1200; // end-user cost per TB of MASS SATA disk in an enterprise-class system
		CALC.atn.mass.power = 29; // power per MASS disk
		CALC.atn.mass.space = 0.17;
		
	CALC.atn.node = new Object;
		CALC.atn.node.perf = 21933; // ops / second
		CALC.atn.node.fxt = new Object; // FXT disk
			CALC.atn.node.fxt.perf = CALC.atn.node.perf / 8;
			CALC.atn.node.fxt.cost = 5000; // end-user cost per FXT disk
			CALC.atn.node.fxt.power = 75; // power per FXT disk
			CALC.atn.node.fxt.space = 0.25; // space per FXT disk (RU)
			
		
	CALC.atn.reqs = new Object; // requirements
		CALC.atn.reqs.perf = new Object;
			CALC.atn.reqs.perf.nodes = Math.ceil(CALC.inputs.perf / CALC.atn.node.perf);
			// Disks required for performance
			CALC.atn.reqs.perf.fxt = CALC.atn.reqs.perf.nodes * 8;
	
		CALC.atn.reqs.cap = new Object;
			// Disks required for capacity
			CALC.atn.reqs.cap.mass = Math.ceil(CALC.inputs.cap / CALC.atn.mass.cap);
	
	CALC.atn.deliv = new Object;
		CALC.atn.deliv.perf = CALC.atn.reqs.perf.nodes * CALC.atn.node.perf; // Performance delivered in ops / sec. Javascript does not have a built-in function for rounding beyond the decimal place.
		CALC.atn.deliv.cap = CALC.atn.mass.cap * CALC.atn.reqs.cap.mass; // Capacity delivered in TB
		CALC.atn.deliv.disks = CALC.atn.reqs.perf.fxt + CALC.atn.reqs.cap.mass; // Disks required
		CALC.atn.deliv.capex = Math.round((CALC.atn.reqs.perf.fxt * CALC.atn.node.fxt.cost + CALC.atn.reqs.cap.mass * CALC.atn.mass.cost) / 1000); // Capital Equipment Cost in $thousands
		CALC.atn.deliv.power = Math.round((CALC.atn.reqs.perf.fxt * CALC.atn.node.fxt.power + CALC.atn.reqs.cap.mass * CALC.atn.mass.power) / 1000); // Power in kW
		CALC.atn.deliv.space = Math.round(CALC.atn.reqs.perf.fxt * CALC.atn.node.fxt.space + CALC.atn.reqs.cap.mass * CALC.atn.mass.space); // Space in rack units (RU)
		

		
	CALC.tn = new Object;
	
	CALC.tn.disk = new Object;
		CALC.tn.disk.perf = 270; // performance per disk (ops/sec/disk)
		CALC.tn.disk.cap = 210; // usable capacity per disk (0.7 * 300 GB)
		CALC.tn.disk.cost = 6000; // end-user cost per TB of 15k disk in an enterprise-class system
		CALC.tn.disk.power = 43; // power per 15k disk (watts/disk)
		CALC.tn.disk.space = 0.24; // space per 15k disk (RU/disk)


	CALC.tn.reqs = new Object;
		// Disks required for performance
		CALC.tn.reqs.perf = Math.ceil(CALC.inputs.perf / CALC.tn.disk.perf);
		// Disks required for capacity
		CALC.tn.reqs.cap = Math.ceil(CALC.inputs.cap / CALC.tn.disk.cap * 1000);
		
	CALC.tn.deliv = new Object;
		CALC.tn.deliv.perf = CALC.tn.disk.perf * CALC.tn.reqs.perf;
		CALC.tn.deliv.disks = Math.ceil(calcDisksRequired(CALC.tn.reqs.perf, CALC.tn.reqs.cap));
		CALC.tn.deliv.cap = CALC.tn.disk.cap * CALC.tn.deliv.disks / 1000;
		CALC.tn.deliv.capex = Math.round(CALC.tn.deliv.cap * CALC.tn.disk.cost / 1000);
		CALC.tn.deliv.power = Math.round(CALC.tn.deliv.disks * CALC.tn.disk.power / 1000);
		CALC.tn.deliv.space = Math.round(CALC.tn.deliv.disks * CALC.tn.disk.space);


	CALC.savings = new Object;
		CALC.savings.capex = new Object;
			CALC.savings.capex.int = Math.round(CALC.tn.deliv.capex - CALC.atn.deliv.capex);
		CALC.savings.power = new Object;
			CALC.savings.power.int = Math.round(CALC.tn.deliv.power - CALC.atn.deliv.power);
			CALC.savings.power.perc = Math.round(CALC.savings.power.int / CALC.tn.deliv.power * 100);
		CALC.savings.space = new Object;
			CALC.savings.space.int = Math.round(CALC.tn.deliv.space - CALC.atn.deliv.space);
			CALC.savings.space.perc = Math.round(CALC.savings.space.int / CALC.tn.deliv.space * 100);
		CALC.savings.disks = new Object;
			CALC.savings.disks.int = Math.round(CALC.tn.deliv.disks - CALC.atn.deliv.disks);
			CALC.savings.disks.perc = Math.round(CALC.savings.disks.int / CALC.tn.deliv.disks * 100);
}
/********************** END CALCULATOR ****************************************************************/	
	

/*
	Don't touch anything down here unless you know what you're doing.
*/
$(document).ready(function() {
	captureFormSubmit();
	hideInputValues();
});

function hideInputValues() {
	$("#fs_calc #fs_calc_wizard #fs_cap_row input").blur(function() {
		if ($(this).attr("value") == "") {
			$(this).attr("value", "15");
			$(this).addClass("default");
		}
	});
	$("#fs_calc #fs_calc_wizard #fs_cap_row input").focus(function() {
		$(this).attr("value", "");
		$(this).removeClass("default");
	});
	$("#fs_calc #fs_calc_wizard #fs_perf_row input").blur(function() {
		if ($(this).attr("value") == "") {
			$(this).attr("value", "130,000");
			$(this).addClass("default");
		}
	});
	$("#fs_calc #fs_calc_wizard #fs_perf_row input").focus(function() {
		$(this).attr("value", "");
		$(this).removeClass("default");
	});
}

function validateInputs() {
	// strip non-numeric characters
	sanitizeInputs();
	// only allow numbers between 1-1000 for capacity and 20,000 and 1,000,000 for performance
	checkBounds();
	$("#fs_calc #fs_calc_wizard input").removeClass("default");
}

function captureFormSubmit() {
	$("#fs_q").submit( function () {

		CALC.inputs = new Object;
		CALC.inputs.cap = document.fs_q.fs_cap.value; // in terabytes
		CALC.inputs.perf = document.fs_q.fs_perf.value; // in operations per second		
		
		validateInputs();
		
		if (!CALC.error.cap && !CALC.error.perf) {
	
			logQuery();
	
			if (exists($("#fs_calc_results"))) {
				updateHTML();
			}
			else {	
				insertHTML();
			}
			removeOldWarnings();
		}
		else {
			addWarnings();
			removeOldWarnings();
		}
		return false;
	});
}

function logQuery() {
	$.ajax({
	  type: "GET",
	  data: CALC.inputs,
	  url: "scripts/log_calc.php"
	});
}

function insertHTML() {
	doCalc();
	var results = makeResults();
	var contact = makeContact();
	var tos = makeTOS();
	$(results).css("display", "none");
	$(contact).css("display", "none");
	$(tos).css("display", "none");
	$("#fs_calc_contact").css("display", "none");
	$("#fs_calc").append(results);
	$("#fs_calc #fs_calc_results #fs_calc_print a").click( function(event) {															
		window.print();
		event.preventDefault();
	});
	$("#fs_calc #fs_calc_results .link a").click( function(event) {
		scrollToContact();
		event.preventDefault();
	});
	$("#fs_calc_results").fadeIn(2500);
	scrollToResults();
	$("#fs_calc").append(contact);
	$(contact).fadeIn(2500);
	$("#fs_calc").append(tos);
	$(tos).fadeIn(2500);
	// re-init UniTip to work with graphs
	init();
}

function updateHTML() {
	doCalc();
	var results = updateResults();
	$(results.p).css("display", "none");
	$(results.graphs).css("display", "none");
	scrollToResults();
	$("#fs_calc_results .fs_calc_summary p:first").fadeOut(1000, function() {
		$(".fs_calc_summary p:first").replaceWith(results.p);
		$(".fs_calc_summary p:first").fadeIn(1500);
	});
	$("#fs_calc_graphs").fadeOut(1000, function() {
		$("#fs_calc_graphs").remove();
		$("#fs_calc_results").append(results.graphs);
		$("#fs_calc_graphs").fadeIn(1500);
		init();
	});																	
	// re-init UniTip to work with graphs
}

	
function calcDisksRequired(perf, cap) { 
	if (perf > cap) {
		return perf;
	} 
	else {
		return cap;
	}
}

function makeResults() {						
	CALC.savings.capex.int = addCommas(CALC.savings.capex.int * 1000);
	CALC.savings.disks.int = addCommas(CALC.savings.disks.int);
	CALC.savings.space.int = addCommas(CALC.savings.space.int);
	CALC.savings.power.int = addCommas(CALC.savings.power.int);

	var results = $("<div id=\"fs_calc_results\"></div>");
	var print_results = $("<div id=\"fs_calc_print\"><a href=\"#\">Print your results</a></div>");
	var summary = $("<div class=\"fs_calc_summary\"><p>By choosing Avere over traditional NAS, you'll save <strong>" + CALC.savings.disks.int + " disks</strong>, <strong>" + CALC.savings.power.int + " kilowatts</strong> of power, <strong>" + CALC.savings.space.int + " rack units</strong>, and, most importantly, <strong>$" + CALC.savings.capex.int + "</strong>.<a href=\"#fs_tos\" class=\"ignore\">*</a></p><p class=\"link\">For a more detailed analysis, <a href=\"#\">complete the form below</a>.</p></div>");
	$(results).append(print_results);
	$(results).append(summary);
	$(results).append(makeGraphs());
	return results;
}

function updateResults() {
	var results = new Object;
	results.p = document.createElement("p");
	CALC.savings.capex.int = addCommas(CALC.savings.capex.int * 1000);
	CALC.savings.disks.int = addCommas(CALC.savings.disks.int);
	CALC.savings.space.int = addCommas(CALC.savings.space.int);
	CALC.savings.power.int = addCommas(CALC.savings.power.int);
	$(results.p).append("By choosing Avere over traditional NAS, you'll save <strong>" + CALC.savings.disks.int + " disks</strong>, <strong>" + CALC.savings.power.int + " kilowatts</strong> of power, <strong>" + CALC.savings.space.int + " rack units</strong>, and, most importantly, <strong>$" + CALC.savings.capex.int + "</strong>.<a href=\"#fs_tos\" class=\"ignore\">*</a>");
	results.graphs = makeGraphs();
	return results;
}

function makeContact() {	
	var contact = 	document.createElement("div");
	contact.id = "fs_calc_contact";
	$(contact).append("<div class=\"fs_calc_contact_msg\"><p>For a more detailed analysis of your storage environment and how Avere can help you achieve cost savings, please fill out the form below. An Avere representative will contact you shortly.</p></div>");
	$.ajax({
	  type: "GET",
	  url: "inc/contact_form.html",
	  success: function(data) {
		  $(contact).append(data);
	  }
	});
	return contact;
}

function makeGraphs() {
	var graph_types = [ ["disks", "Disks", "Disk", "disks"], ["power", "Power (kW)", "Power", "kW"], ["space", "Space (rack units)", "Space", "rack units"], ["capex", "Capital Equipment Cost (thousands)", "Cost", "$"]];
	
	var graphs = document.createElement("div");
	graphs.className = "fs_calc_graphs";
	graphs.id = "fs_calc_graphs";
		
	for (i=0;i<graph_types.length;i++) {
		if (graph_types[i][0] == "capex") {
			var savings = "$" + CALC.savings[graph_types[i][0]].int;
		}
		else {
			var savings = CALC.savings[graph_types[i][0]].perc + "%";
		}
		// create elements and assign attributes
		var container = document.createElement("div");
		container.className = "fs_calc_graph_container";
		container.id = "fs_calc_graph_" + graph_types[i][0];
			
		var graph = document.createElement("div");
		graph.className = "fs_calc_graph";	
		
		var base_interval = 5;
		var intervals = 4;
		var graph_height = 200;
		var multiplier = makeScale(graph_types[i][0], base_interval, intervals);

		var gridline_measurements = [];
		for (j=0; j<intervals; j++) {
			gridline_measurements.push(base_interval * (j + 1) * multiplier);
		}

		var gridlines = [];
		
		for (j=0;j<gridline_measurements.length;j++) {
			var gridline = document.createElement("div");
			gridline.className = "fs_calc_gridline";
			$(gridline).css({
				"bottom": ((graph_height / intervals) * (j + 1)) - 2
			 });
			$(gridline).append(gridline_measurements[j]);
			gridlines.push(gridline);
		}
				
		var title = document.createElement("h3");
		title.className = "fs_calc_graph_title";
		$(title).append(graph_types[i][1]);
	
						
		var col_1 = document.createElement("div");
		col_1.className = "fs_calc_graph_col_1 fs_calc_graph_col fs_calc_tip";
		if (graph_types[i][0] == "capex") {
			$(col_1).attr("title", graph_types[i][3] + CALC.atn.deliv[graph_types[i][0]]);
		}
		else {
			$(col_1).attr("title", CALC.atn.deliv[graph_types[i][0]] + " " + graph_types[i][3]);
		}
		$(col_1).animate({
			"height": (CALC.atn.deliv[graph_types[i][0]] / (multiplier * base_interval * intervals) ) * graph_height
		}, 2000);
		$(col_1).append(CALC.atn.deliv[graph_types[i][0]]);
		
		var col_2 = document.createElement("div");
		col_2.className = "fs_calc_graph_col_2 fs_calc_graph_col fs_calc_tip";
		if (graph_types[i][0] == "capex") {
			$(col_2).attr("title", graph_types[i][3] + CALC.tn.deliv[graph_types[i][0]]);
		}
		else {
			$(col_2).attr("title", CALC.tn.deliv[graph_types[i][0]] + " " + graph_types[i][3]);
		}
		$(col_2).animate({
			"height": (CALC.tn.deliv[graph_types[i][0]] / (multiplier * base_interval * intervals) ) * graph_height
		}, 4000);
		$(col_2).append(CALC.tn.deliv[graph_types[i][0]]);
		
		var note = document.createElement("div");
		note.className = "fs_calc_graph_note";
		$(note).append(graph_types[i][2] + " Savings with Avere: <strong>" + savings + "</strong>");
				
		for (j=0; j<gridlines.length;j++) {
			$(graph).append(gridlines[j]);	
		}		
				
		$(graph).append(title);
		$(graph).append(col_1);
		$(graph).append(col_2);
		$(container).append(graph);
		$(container).append(note);
		$(graphs).append(container);		
	}
	return graphs;
}

function makeTOS() {
	var tos = $("<div class=\"fs_tos\" id=\"fs_tos\" name=\"fs_tos\">*The savings calculator is intended for informational and illustration purposes only.  Any results generated by the savings calculator do not represent a guarantee of performance for any particular customer or use.  Please see the <a href=\"TermsOfUse.aspx\">Terms of Use</a> for more information.</div>");
	return tos;
}

function makeScale(graph, base_interval, intervals) {
	// get column heights
	var col_1 = CALC.atn.deliv[graph];
	var col_2 = CALC.tn.deliv[graph];
	// find highest one per chart
	if (col_1 > col_2) {
		var height = col_1;
	}
	else {
		var height = col_2;
	}
	// divide the height by 50 (my original interval), divide that number by 4 (number of intervals), round up to determine how many times to multiply original interval, multiply original interval by new multiplier
	var multiplier = Math.ceil(height / base_interval / intervals);
	return multiplier;
}

function exists(el) {
	if ($(el).length > 0) {
		return true;
	}
	else {
		return false;
	}
}

function sanitizeInputs() {
	// remove anything that is not a digit or decimal
	var pattern = /[^\d\.]*/g;
	CALC.inputs.cap = CALC.inputs.cap.replace(pattern, "");
	CALC.inputs.perf = CALC.inputs.perf.replace(pattern, "");
	updateInputs();
}

function updateInputs() {
	document.fs_q.fs_cap.value = addCommas(CALC.inputs.cap); // in terabytes
	document.fs_q.fs_perf.value = addCommas(CALC.inputs.perf); // in operations per second			
}

function checkBounds() {
	pattern = /\./;
	var str = CALC.inputs.cap;
	var cap = str.split(pattern);

	if (CALC.inputs.cap < 1 || CALC.inputs.cap > 1000 || cap.length > 2) {
		CALC.error.cap = true;
	}
	else {
		CALC.error.cap = false;
	}

	str = CALC.inputs.perf;
	var perf = str.split(pattern);
	if (CALC.inputs.perf < 20000 || CALC.inputs.perf > 1000000 || perf.length > 2) {
		CALC.error.perf = true;
	}
	else {
		CALC.error.perf = false;
	}
}

function addWarnings() {
	if (CALC.error.cap) {
		if (!exists($("#fs_cap_row .fs_calc_msg"))) {
			$("#fs_cap_row").addClass("fs_calc_warning");
			$("#fs_cap_row").append("<span class=\"fs_calc_msg\">Please enter a number between 1 and 1,000</span>");
			$("#fs_cap_row .fs_calc_msg").fadeIn(1500);
		}
	}
	if (CALC.error.perf) {
		if (!exists($("#fs_perf_row .fs_calc_msg"))) {
			$("#fs_perf_row").addClass("fs_calc_warning");
			$("#fs_perf_row").append("<span class=\"fs_calc_msg\">Please enter a number between 20,000 and 1,000,000</span>");
			$("#fs_perf_row .fs_calc_msg").fadeIn(1500);
		}
	}
}

function removeOldWarnings() {
	if (!CALC.error.cap && exists($("#fs_cap_row .fs_calc_msg"))) {
		$("#fs_cap_row .fs_calc_msg").fadeOut("slow", function() {
			$("#fs_cap_row").removeClass("fs_calc_warning");
			$("#fs_cap_row .fs_calc_msg").remove();
		});
	}
	if (!CALC.error.perf && exists($("#fs_perf_row .fs_calc_msg"))) {
		$("#fs_perf_row .fs_calc_msg").fadeOut("slow", function() {
			$("#fs_perf_row").removeClass("fs_calc_warning");
			$("#fs_perf_row .fs_calc_msg").remove();
		});
	}
}

function scrollToResults() {
	var offset = $("#fs_calc_results .fs_calc_summary").offset();
	$("html, body").animate({ scrollTop: offset.top}, 1500);
}

function scrollToContact() {
	var offset = $("#fs_calc_contact").offset();
	$("html, body").animate({ scrollTop: offset.top}, 1500);
}

// borrowed from http://www.mredkj.com/javascript/nfbasic.html
function addCommas(nStr)
{
	nStr += '';
	x = nStr.split('.');
	x1 = x[0];
	x2 = x.length > 1 ? '.' + x[1] : '';
	var rgx = /(\d+)(\d{3})/;
	while (rgx.test(x1)) {
		x1 = x1.replace(rgx, '$1' + ',' + '$2');
	}
	return x1 + x2;
}
