var unitType = { cm:0, m:1, inches:2 }; // Use like this: unitType.cm will give 0
var customFieldsUsed = false; // when set to true, this will cause doctorFields to ignore the writing of certain variables.
var debuggingOutput = "<br>";

var comparisonchart = false;

var overheatflag = false;

var exampleMotor;
var exampleBattery;
var exampleWheelSize;
var exampleController;
var exampleThrottle;
var exampleWeight;
var exampleCdA;
var exampleCf;
var exampleWeight;

var exampleMotor_2;
var exampleBattery_2;
var exampleWheelSize_2;
var exampleController_2;
var exampleThrottle_2;
var exampleWeight_2;
var exampleCdA_2;
var exampleCf_2;
var exampleWeight_2;

var staticgrade1;
var staticgrade2;

var global_maxS = 0;

///////////////////////////////////
//                               //
//     DATA INITIALIZATION       //
//                               //
///////////////////////////////////

function init_data()
{
	exampleMotor = new motor("M406", "406", 1, 0.6, 0.6, 0, 0, 0, 0, 0.001, 8);
	exampleBattery = new battery("B3612MH", "36V 12Ah NiMH", 36, "MH", 8, 36, 0.2);
	exampleWheelSize = new wheelSize(26, unitType.inches);
	exampleController = new controller("C20", "Generic 20A Controller", 20, 0.03, 0.9);
	exampleThrottle = 1.0 // This is a percentage of total, from 0 to 1
// The next 3 items should initialize to form data, rather than numeric values here
	exampleWeight = 90;
	exampleCdA = 0.8;
	exampleCf = 0.006;
	
	exampleMotor_2 = new motor("M406", "406", 1, 0.6, 0.6, 0, 0, 0, 0, 0.001, 8);
	exampleBattery_2 = new battery("B3612MH", "36V 12Ah NiMH", 36, "MH", 8, 36, 0.2);
	exampleWheelSize_2 = new wheelSize(26, unitType.inches);
	exampleController_2 = new controller("C20", "Generic 20A Controller", 20, 0.03, 0.9);
	exampleThrottle_2 = 1.0 // This is a percentage of total, from 0 to 1
// The next 3 items should initialize to form data, rather than numeric values here
	exampleWeight_2 = 90;
	exampleCdA_2 = 0.8;
	exampleCf_2 = 0.006;
	return true;
}

///////////////////////////////////
//                               //
//        DATA STRUCTURES        //
//                               //
///////////////////////////////////

// Although these look like functions, they are actually something like constructors.
function motor(id, name, K, Rmotor, A0, A1, A2, FW, T1, L, poles)
{
	this._id = id;
	this._name = name; // motor name, eg. 404
	// The following parameters should be kept on the database rather than out in the open.
	// Once the motor is defined as above, the database request should
	// fill in the rest.
	this._K = K;						// Motor constant in N-m/A
	this._Rmotor = Rmotor;				// Winding resistance in Ohms
	this._A0 = A0;						// Quadratic coefficients for the motor cogging torque in N-m
	this._A1 = A1;
	this._A2 = A2;
	this._FW = FW;
	this._T1 = T1;
	this._L = L;
	this._Poles = poles;
	return this;
}

function battery(id, name, voltage, type, amph, Voc, Rbatt)
{
	this._id = id;						// From DB - first call (non-AJAX)
	this._name = name;					// From DB - first call
	this._voltage = voltage; 			// in Volts
	this._type = type; 					// string, one of MH, CD for now
	this._amph = amph;		 	// in A-h
	// The following parameters should be kept on the database rather than out in the open.
	// Same caveat as for motor data
	this._Voc = Voc; // The open circuit battery voltage at 50% SOC
	this._Rbatt = Rbatt; // The battery's internal resistance at 50% SOC
	return this;
}

function datafeedin(_exampleMotor, _exampleBattery, _exampleController, _exampleCf, _exampleWheelSize, _exampleCdA, _exampleWeight, _exampleThrottle, _staticgrade)
{
	this.exampleMotor = _exampleMotor;						// From DB - first call (non-AJAX)
	this.exampleBattery = _exampleBattery;					// From DB - first call
	this.exampleController = _exampleController; 			// in Volts
	this.exampleCf = _exampleCf; 					// string, one of MH, CD for now
	this.exampleWheelSize = _exampleWheelSize;		 	// in A-h
	this.exampleCdA = _exampleCdA; // The open circuit battery voltage at 50% SOC
	this.exampleWeight = _exampleWeight; // The battery's internal resistance at 50% SOC
	this.exampleThrottle = _exampleThrottle;
	this.staticgrade = _staticgrade;
	return this;
}

function wheelSize(size, units)
{
	// The diameter of the wheel is to be stored in metres.
	if (size)
	{
		switch(units) {
			case unitType.cm :
				this._size = ( size / 100.0 );
				break;
			case unitType.m :
				this._size = size;
				break;
			case unitType.inches :
				this._size = (size * 0.0254);
				break;
			default : alert("Strange unit type");
		}
	}
	return this;
}

function controller(id, name, maxCurrent, Rcont, Vdiode)
{
	this._id = id;
	this._name = name;
	this._maxCurrent = maxCurrent; // This is either 20 or 35, public data
	// The following parameters should be kept on the database rather than out in the open.
	// Same caveat as for battery data	
	this._Rcont = Rcont;
	this._Vdiode = Vdiode;
	return this;
}

///////////////////////////////////
//                               //
//     INTERPRET FORM DATA       //
//                               //
///////////////////////////////////

function customFields2(batteryVoltage, batteryResistance, batteryAmphours, customWheelSize, controllerAmperage, controllerResistance, motorText, batteryText, wheelText, controllerText, throttleText, weightText, bicycleType, netWeight, batteryVoltage_2, batteryResistance_2, batteryAmphours_2, customWheelSize_2, controllerAmperage_2, controllerResistance_2, motorText_2, batteryText_2, wheelText_2, controllerText_2, throttleText_2, weightText_2, bicycleType_2, netWeight_2, _staticgrade1, _staticgrade2, customcda, customcr, customcda_2, customcr_2) 
{
	// Need to do sanity checking on new data - user types in weird stuff sometimes.
	var newbatteryText;
	var newcontrollerText;
	var dummybiketype, dummybicycletype_2;
	exampleMotor = new motor(motorText, 1, 0.6, 0.6, 0, 0, 0, 0, 0.001, 8);
	// Sanity check here?
	exampleThrottle = throttleText / 100.0;
	exampleWeight = weightText / 1.0001;

	exampleMotor_2 = new motor(motorText_2, 1, 0.6, 0.6, 0, 0, 0, 0, 0.001, 8);
	// Sanity check here?
	exampleThrottle_2 = throttleText_2 / 100.0;
	exampleWeight_2 = weightText_2 / 1.0001;

	staticgrade1 = _staticgrade1;
	staticgrade2 = _staticgrade2;

	if (custombattery)
	{
		if (isNaN(batteryVoltage))
		{
			alert("Error: Pack voltage must be a number.");
			document.getElementById('packVoltageField').focus();
			return;
		}
		if (isNaN(batteryResistance))
		{
			alert("Error: Battery resistance must be a number.");
			document.getElementById('batteryResistanceField').focus();		
			return;
		}
		if (isNaN(batteryAmphours))
		{
			alert("Error: First Battery amp hours must be a number.");
			document.getElementById('batteryAmphField').focus();		
			return;
		}
		exampleBattery = new battery("BCust", "Custom Battery", 36, "CD", parseFloat(batteryAmphours), parseFloat(batteryVoltage), parseFloat(batteryResistance));
		newbatteryText = "B3612MH";
	}
	else
	{
	exampleBattery = new battery(batteryText, "Generic Name", 
									 99, "Fe",
									 98, 99, // voc
									 0.2); // rbatt
		newbatteryText = batteryText;
	}
	if(customframe)
	{
		if (isNaN(customcda))
		{
			alert("Error: Custom CdA must be a number.");
			document.getElementById('CdAList').focus();		
			return;
		}
		if (isNaN(customcr))
		{
			alert("Error: Custom Cr must be a number.");
			document.getElementById('CdAList').focus();		
			return;
		}
	exampleCf = parseFloat(customcr);
	exampleCdA = parseFloat(customcda);
	dummybiketype = "mountain";
	}
	else
	{
	dummybiketype = bicycleType;
	}
	if (customwheel)
	{
		if (isNaN(customWheelSize))
		{
			alert("Error: Wheel size must be in inches (example: \"26\")");
			document.getElementById('customWheelSizeField').focus();		
			return;
		}
		exampleWheelSize = new wheelSize(parseFloat(customWheelSize), unitType.inches);
	}
	else
	{
	var textUnitType;
		switch(wheelText.substring(wheelText.length - 1,wheelText.length))
		{
			case('i'):
				textUnitType = unitType.inches;
				break;
			case('c'):
				textUnitType = unitType.cm;
				break;
			case('m'):
				textUnitType = unitType.m;
				break;
			default:
				alert("Improper wheel diameter; it should be one of inches, cm, or m.");
		}
		
		exampleWheelSize = new wheelSize(wheelText.substring(0, wheelText.length - 1), textUnitType);
	}
	if (customcontroller)
	{
		if (isNaN(controllerAmperage))
		{
			alert("Error: Controller amperage must be a number.");	
			document.getElementById('controllerAmperageField').focus();		
			return;
		}
		if (isNaN(controllerResistance))
		{
			alert("Error: Controller resistance must be a number.");	
			document.getElementById('controllerResistanceField').focus();		
			return;
		}
		exampleController = new controller("CCust", "CCust", parseFloat(controllerAmperage), parseFloat(controllerResistance), 0.9);
		newcontrollerText = "C20";
	}
	else
	{
	exampleController = new controller(controllerText, "Replaceable Name", 20, 0.03, 0.9);
	newcontrollerText = exampleController._id;	
	}


var postVars = 'action=loadjson&motorid=' + encodeURIComponent(exampleMotor._id) +
						'&batteryid=' + encodeURIComponent(newbatteryText) + 
					   '&controllerid=' + encodeURIComponent(newcontrollerText) + 
					   '&biketypeid=' + encodeURIComponent(dummybiketype);
					   
	if(comparisonchart)
	{
	if (custombattery_2)
	{
		if (isNaN(batteryVoltage_2))
		{
			alert("Error: Pack voltage must be a number.");
			document.getElementById('packVoltageField_2').focus();
			return;
		}
		if (isNaN(batteryResistance_2))
		{
			alert("Error: Battery resistance must be a number.");
			document.getElementById('batteryResistanceField_2').focus();		
			return;
		}
		if (isNaN(batteryAmphours_2))
		{
			alert("Error: First Battery amp hours must be a number.");
			document.getElementById('batteryAmphField_2').focus();		
			return;
		}
		exampleBattery_2 = new battery("BCust", "Custom Battery", 36, "CD", parseFloat(batteryAmphours_2), parseFloat(batteryVoltage_2), parseFloat(batteryResistance_2));
		newbatteryText = "B3612MH";
	}
	else
	{
	exampleBattery_2 = new battery(batteryText_2, "Generic Name", 
									 99, "Fe",
									 98, 99, // voc
									 0.2); // rbatt
		newbatteryText = batteryText_2;
	}
	if(customframe_2)
	{
		if (isNaN(customcda_2))
		{
			alert("Error: Second custom CdA must be a number." + customcda_2);
			document.getElementById('CdAList_2').focus();	
			return;
		}
		if (isNaN(customcr_2))
		{
			alert("Error: Second custom Cr must be a number."  + customcr_2);
			document.getElementById('CdAList_2').focus();		
			return;
		}
	exampleCf_2 = parseFloat(customcr_2);
	exampleCdA_2 = parseFloat(customcda_2);
	dummybiketype_2 = "mountain";
	
	}
	else
	{
	dummybiketype_2 = bicycleType_2;
	}
	if (customwheel_2)
	{
		if (isNaN(customWheelSize_2))
		{
			alert("Error: Second wheel size must be in inches (example: \"26\")");
			document.getElementById('customWheelSizeField_2').focus();		
			return;
		}
		exampleWheelSize_2 = new wheelSize(parseFloat(customWheelSize_2), unitType.inches);
	}
	else
	{
	var textUnitType_2;
		switch(wheelText_2.substring(wheelText_2.length - 1,wheelText_2.length))
		{
			case('i'):
				textUnitType_2 = unitType.inches;
				break;
			case('c'):
				textUnitType_2 = unitType.cm;
				break;
			case('m'):
				textUnitType_2 = unitType.m;
				break;
			default:
				alert("Improper wheel diameter; it should be one of inches, cm, or m.");
		}
		
		exampleWheelSize_2 = new wheelSize(wheelText_2.substring(0, wheelText_2.length - 1), textUnitType_2);
	}
	if (customcontroller_2)
	{
		if (isNaN(controllerAmperage_2))
		{
			alert("Error: Second controller amperage must be a number.");	
			document.getElementById('controllerAmperageField_2').focus();		
			return;
		}
		if (isNaN(controllerResistance_2))
		{
			alert("Error: Second Controller resistance must be a number.");	
			document.getElementById('controllerResistanceField_2').focus();		
			return;
		}
		exampleController_2 = new controller("CCust", "CCust", parseFloat(controllerAmperage_2), parseFloat(controllerResistance_2), 0.9);
		newcontrollerText = "C20";
	}
	else
	{
	exampleController_2 = new controller(controllerText_2, "Replaceable Name", 20, 0.03, 0.9);
	newcontrollerText = exampleController_2._id;	
	}


var postVars_2 = 'action=loadjson&motorid=' + encodeURIComponent(exampleMotor_2._id) +
						'&batteryid=' + encodeURIComponent(newbatteryText) + 
					   '&controllerid=' + encodeURIComponent(newcontrollerText) + 
					   '&biketypeid=' + encodeURIComponent(dummybiketype_2);
	}
	// The data below is encoded according to a simplification of the standard SKU scheme.
	// examples: B365CD, M404

	ajaxObj.call(postVars, respJSON_1);

	if(comparisonchart)
	{
		ajaxObj.call(postVars_2, respJSON_2);
	}
	//draw_all_charts();	
	return false;
}

function findgradezerocrossing(inputdata)
{
var secondary;
	for (var j = 0; j < inputdata["grade"].length; j++) 
	{
		if(Math.abs(inputdata["grade"][j]/20) < 0.1) 
		{
			return j;
		}
	}
	for (var j = 0; j < inputdata["grade"].length; j++) //Settle for not 0, if there is some some crazy point compression due to massively differing scales
	{
	if(Math.abs(inputdata["grade"][j]/20) <= 0.15) 
	{
		
		return j;
	}
	}
	return 0;
}

function findintersect(inputdata)
{
var changes, changes2, changes3;
	for (var j = 0; j < inputdata["power"].length; j++) 
	{
	changes2 = Math.abs(inputdata["power"][j]-inputdata["load"][j]);
	//if((changes2 < 1) && (j > 10))
	if((changes3 >0) && (changes-changes2 < 0) && (changes < 50) && (j > 5))
	{
		return j-1;
	}
	changes3 = changes-changes2;
	/*	if((Math.abs(inputdata["power"][j]-inputdata["load"][j]) < 0.5) && (inputdata["power"][j] > 0.1)) 
		{
			return j;
		}*/
		changes = changes2;
	}
	/*for (var j = 0; j < inputdata["power"].length; j++) //Settle for not 0, if there is some some crazy point compression due to massively differing scales
	{
	if((Math.abs(inputdata["power"][j]-inputdata["load"][j]) <= 2) && (inputdata["power"][j] > 0.1)) 
	{
		
		return j;
	}
	}*/
	return 0;
}
					
function setzeroandfields(inputdata, loadnotgrade)
{
var crossing;
if(loadnotgrade) //If Load line selected
{
crossing = findintersect(inputdata);
}
else
{
crossing = findgradezerocrossing(inputdata);
}

var diststring;
var torquestring;

	var setdivvalues = function()
	{
	var torquestring;
	var diststring;
	var speedstring;
	
		if($("#torqueUnitFlag").val() == "N-m")
		{ torquestring = "N-m"; }
		else { torquestring = "Lbs"; }
		
		if($("#speedUnitFlag").val() == "kph")
		{
			diststring = "km";
			speedstring = "kph";
		}
		else if($("#speedUnitFlag").val() == "mph")
		{
				diststring = "mi";
				speedstring = "mph";
		}
		else
		{
				diststring = "kR";
				speedstring = "RPM";
		}
		
		// Set the preview values on mousemove.
		$("#tablepowerA").html(operatingValues["power"][whichDataPoint].toFixed(0) + "W");
		$("#tabletorqueA").html(operatingValues["torque"][whichDataPoint].toFixed(1) + torquestring);
		$("#tablemtrampsA").html(operatingValues["motorCurrent"][whichDataPoint].toFixed(1) + "A");
		if((operatingValues["efficiency"][whichDataPoint] * 100).toFixed(1) == 0) { $("#tableefficiencyA").html("NaN"); }
		else { $("#tableefficiencyA").html((operatingValues["efficiency"][whichDataPoint] * 100).toFixed(1) + "%"); }
		$("#tablebattvoltsA").html(operatingValues["batteryVoltage"][whichDataPoint].toFixed(1) + "V");
		$("#tablebattampsA").html(operatingValues["batteryCurrent"][whichDataPoint].toFixed(1) + "A");
		$("#tableeconomyA").html(operatingValues["whKm"][whichDataPoint].toFixed(1) + "Wh/" + diststring);
		$("#tablerangeA").html(operatingValues["range"][whichDataPoint]);
		if($("#gradeloadflag").val() == "grade") { $("#tablegradeloadA").html((operatingValues["grade"][whichDataPoint] / 20.0).toFixed(1)+"%"); }
		else { $("#tablegradeloadA").html((operatingValues["load"][whichDataPoint]).toFixed(0)+"W"); }
		$("#tableoverheatA").html(operatingValues["overheatIn"][whichDataPoint]);
		$("#battpowerA").html((operatingValues["batteryVoltage"][whichDataPoint]*operatingValues["batteryCurrent"][whichDataPoint]).toFixed(0)+"W");
		if(speedstring == "kph") $("#accelerationA").html((operatingValues["acceleration"][whichDataPoint]).toFixed(3)+"m/s<sup>2</sup>");
		else if (speedstring == "mph") $("#accelerationA").html((operatingValues["acceleration"][whichDataPoint]*3.2808399).toFixed(3)+"ft/s<sup>2</sup>");
		else $("#accelerationA").html((operatingValues["acceleration"][whichDataPoint]/(exampleWheelSize._size*3.14159265)).toFixed(3)+"R/s<sup>2</sup>");
		
		if(comparisonchart)
		{
			$("#tablepowerB").html(operatingValues_2["power"][whichDataPoint].toFixed(0) + "W");
			$("#tabletorqueB").html(operatingValues_2["torque"][whichDataPoint].toFixed(1) + torquestring);
			$("#tablemtrampsB").html(operatingValues_2["motorCurrent"][whichDataPoint].toFixed(1) + "A");
			if((operatingValues_2["efficiency"][whichDataPoint] * 100).toFixed(1) == 0) { $("#tableefficiencyB").html("NaN"); }
			else { $("#tableefficiencyB").html((operatingValues_2["efficiency"][whichDataPoint] * 100).toFixed(1) + "%"); }
			$("#tablebattvoltsB").html(operatingValues_2["batteryVoltage"][whichDataPoint].toFixed(1) + "V");
			$("#tablebattampsB").html(operatingValues_2["batteryCurrent"][whichDataPoint].toFixed(1) + "A");
			$("#tableeconomyB").html(operatingValues_2["whKm"][whichDataPoint].toFixed(1) + "Wh/" + diststring);
			$("#tablerangeB").html(operatingValues_2["range"][whichDataPoint]);
			if($("#gradeloadflag").val() == "grade") { $("#tablegradeloadB").html((operatingValues_2["grade"][whichDataPoint] / 20.0).toFixed(1)+"%"); }
			else { $("#tablegradeloadB").html((operatingValues_2["load"][whichDataPoint]).toFixed(0)+"W"); }
			$("#tableoverheatB").html(operatingValues_2["overheatIn"][whichDataPoint]);
			$("#battpowerB").html((operatingValues_2["batteryVoltage"][whichDataPoint]*operatingValues_2["batteryCurrent"][whichDataPoint]).toFixed(0)+"W");
			if(speedstring == "kph") $("#accelerationB").html((operatingValues_2["acceleration"][whichDataPoint]).toFixed(3)+"m/s<sup>2</sup>");
			else if (speedstring == "mph") $("#accelerationB").html((operatingValues_2["acceleration"][whichDataPoint]*3.2808399).toFixed(3)+"ft/s<sup>2</sup>");
			else $("#accelerationB").html((operatingValues_2["acceleration"][whichDataPoint]/(exampleWheelSize_2._size*3.14159265)).toFixed(3)+"R/s<sup>2</sup>");
		}
		
		$("#performance_speed").html(operatingValues["speed"][whichDataPoint].toFixed(1)+speedstring);
	};

	
	whichDataPoint = crossing;
	crossing = Math.round((operatingValues["speed"][whichDataPoint] / operatingValues["speed"][NUMBER_OF_POINTS-1]) * $('#silkscreen').width()) +183;

	$("#crosshairs").css('left', crossing).show(); //Move cursor to that spot
	$("#performance_speed").css('left',crossing-183).show();
	setdivvalues();

}

///////////////////////////////////
//                               //
//     JAVASCRIPT CALLBACK       //
//                               //
///////////////////////////////////

// Check myBic to see if we can have a flag enter here. Then, check it and only set the appropriate values.

function respJSON_1(resp) {
	if(resp) 
	{

		exampleMotor._name = resp.motorname;
		exampleMotor._K = parseFloat(resp.motork);
		exampleMotor._Rmotor = parseFloat(resp.motorrmotor);
		exampleMotor._A0 = parseFloat(resp.motora0);
		exampleMotor._A1 = parseFloat(resp.motora1);
		exampleMotor._A2 = parseFloat(resp.motora2);
		exampleMotor._FW = resp.motorfw;
		exampleMotor._T1 = resp.motort1;
		exampleMotor._L = resp.motorl;
		exampleMotor._Poles = resp.motorpoles;
		exampleMotor._heat_cap = parseInt(resp.heat_cap);
		exampleMotor._therm_cond = parseFloat(resp.therm_cond);

		if(!customframe)
		{
		exampleCf = parseFloat(resp.bicycletypecf);
		exampleCdA = parseFloat(resp.bicycletypecda);
		}
		//if (!customLook)
		if(!custombattery)
		{
			// Set the rest of battery stuff here.
			// Added: battery name, battery voltage,
			exampleBattery._name = resp.batteryname;
			exampleBattery._voltage = resp.batteryvoltage;
			exampleBattery._type = resp.batterytype;
			exampleBattery._amph = resp.batteryamph;
			exampleBattery._Voc = parseFloat(resp.batteryvoc);
			exampleBattery._Rbatt = parseFloat(resp.batteryrbatt);
		}
		if(!customcontroller)
		{
			exampleController._name = resp.controllername;
			exampleController._maxCurrent = parseFloat(resp.controllermaxcur);
			exampleController._Rcont = parseFloat(resp.controllerrcont);
			exampleController._Vdiode = parseFloat(resp.controllervdiode);
		}
	} else {
		alert('json error');
	}

	if(!comparisonchart) //If we're going to be comparing, make sure we find our max speed indice and put it into the global register before assuming calculations.
	{

	var datafeedins = new datafeedin(exampleMotor, exampleBattery, exampleController, exampleCf, exampleWheelSize, exampleCdA, exampleWeight, exampleThrottle, staticgrade1);

	var datafeedins2 = new datafeedin(exampleMotor_2, exampleBattery_2, exampleController_2, exampleCf_2, exampleWheelSize_2, exampleCdA_2, exampleWeight_2, exampleThrottle_2, staticgrade2);

	findmaxspeed(datafeedins, datafeedins2);

	calculateAll(datafeedins, operatingValues);

	draw_all_charts();	
	
	var truefalse = true;
	if($("#gradeloadflag").val() == "grade") truefalse = false;
	
	
		setzeroandfields(operatingValues, truefalse); //True if load line selected

	}

	//draw_all_charts();
		
	return true;
}

function respJSON_2(resp) {
	if(resp) 
	{
		exampleMotor_2._name = resp.motorname;
		exampleMotor_2._K = parseFloat(resp.motork);
		exampleMotor_2._Rmotor = parseFloat(resp.motorrmotor);
		exampleMotor_2._A0 = parseFloat(resp.motora0);
		exampleMotor_2._A1 = parseFloat(resp.motora1);
		exampleMotor_2._A2 = parseFloat(resp.motora2);
		exampleMotor_2._FW = resp.motorfw;
		exampleMotor_2._T1 = resp.motort1;
		exampleMotor_2._L = resp.motorl;
		exampleMotor_2._Poles = resp.motorpoles;
		exampleMotor_2._heat_cap = parseInt(resp.heat_cap);
		exampleMotor_2._therm_cond = parseFloat(resp.therm_cond);
		if(!customframe_2)
		{
			exampleCf_2 = parseFloat(resp.bicycletypecf);
			exampleCdA_2 = parseFloat(resp.bicycletypecda);
		}
		if(!custombattery_2)
		{
			// Set the rest of battery stuff here.
			// Added: battery name, battery voltage,
			exampleBattery_2._name = resp.batteryname;
			exampleBattery_2._voltage = resp.batteryvoltage;
			exampleBattery_2._type = resp.batterytype;
			exampleBattery_2._amph = resp.batteryamph;
			exampleBattery_2._Voc = parseFloat(resp.batteryvoc);
			exampleBattery_2._Rbatt = parseFloat(resp.batteryrbatt);
		}
		if(!customcontroller_2)
		{
			exampleController_2._name = resp.controllername;
			exampleController_2._maxCurrent = parseFloat(resp.controllermaxcur);
			exampleController_2._Rcont = parseFloat(resp.controllerrcont);
			exampleController_2._Vdiode = parseFloat(resp.controllervdiode);
		}
	} else {
		alert('json error');
	}

	var datafeedins = new datafeedin(exampleMotor, exampleBattery, exampleController, exampleCf, exampleWheelSize, exampleCdA, exampleWeight, exampleThrottle, staticgrade1);

	var datafeedins2 = new datafeedin(exampleMotor_2, exampleBattery_2, exampleController_2, exampleCf_2, exampleWheelSize_2, exampleCdA_2, exampleWeight_2, exampleThrottle_2, staticgrade2);
	
	findmaxspeed(datafeedins, datafeedins2);

	calculateAll(datafeedins, operatingValues);

	calculateAll(datafeedins2, operatingValues_2);

	draw_all_charts();			
	var truefalse = true;
	if($("#gradeloadflag").val() == "grade") truefalse = false;
	
	
		setzeroandfields(operatingValues, truefalse); //True if load line selected

			
	return true;
}

///////////////////////////////////
//                               //
//     MAIN CALCULATIONS         //
//                               //
///////////////////////////////////

function findmaxspeed(inputdata, inputdata_2)
{
var maxS;
var maxCalcS;
var globwsize;
var voc = inputdata.exampleBattery._Voc;
var wsize = inputdata.exampleWheelSize._size;
var k = inputdata.exampleMotor._K;

var kmhflag, mphflag, rpmflag;

var maxS_2;
var maxCalcS_2;
var voc_2 = inputdata_2.exampleBattery._Voc;
var wsize_2 = inputdata_2.exampleWheelSize._size;
var k_2 = inputdata_2.exampleMotor._K;

var maxSfinal, tempMax;

/*
	kmhflag = document.getElementById('speedUnitFlag').getElementsByTagName('input')[0].checked; //Needs to be spec'd in header
	mphflag = document.getElementById('speedUnitFlag').getElementsByTagName('input')[1].checked;
	rpmflag = document.getElementById('speedUnitFlag').getElementsByTagName('input')[2].checked;
	*/
	if($("#speedUnitFlag").val() == "kph") {kmhflag =true; mphflag =false;  rpmflag = false;}
	else if($("#speedUnitFlag").val() == "mph") {mphflag =true; kmhflag = false;  rpmflag = false;}
	else  {kmhflag = false; mphflag =false;  rpmflag = true;}
	
	maxS = 60; // wsize is always in metres, and we need to get from km/h back to units of (1/s).
	maxCalcS = ((voc * 1.1) / k) * (1.8 * wsize);
	if (maxCalcS > maxS)
	{
		maxS = maxCalcS; // Don't think we need to round since that is happening later.
	}

if(comparisonchart)
{		
	maxS_2 = 60; // wsize is always in metres, and we need to get from km/h back to units of (1/s).
	maxCalcS_2 = ((voc_2 * 1.1) / k_2) * (1.8 * wsize_2);
	if (maxCalcS_2 > maxS_2)
	{
		maxS_2 = maxCalcS_2; // Don't think we need to round since that is happening later.
	}
}
else
{
maxS_2 = 0;
}
	if(maxS > maxS_2)
	{
		//maxS = maxS;
		globwsize = wsize;
	}	
	else
	{
		maxS = maxS_2;
		globwsize = wsize_2;
	}

if(kmhflag)	maxS = (Math.floor(maxS / 5) + 1) * 5; //Round to nearest 5
else if(mphflag) maxS = (Math.floor((maxS * 1.125/1.8) / 5) + 1) * 5; //Converts to mph, rounds to nearest 5
else maxS = (Math.floor((maxS * 9.54929659/(1.8*globwsize)) / 10) + 1) * 10; //Converts to RPM, rounds to nearest 10
	global_maxS = maxS;
}

function calculateAll(inputdata, outputdata)
{
	
	var voc = inputdata.exampleBattery._Voc,
	    k = inputdata.exampleMotor._K,
	    wsize = inputdata.exampleWheelSize._size,
	    vdiode = inputdata.exampleController._Vdiode,
	    rcont = inputdata.exampleController._Rcont,
	    rmotor = inputdata.exampleMotor._Rmotor,
	    rbatt = inputdata.exampleBattery._Rbatt,
	    a0 = inputdata.exampleMotor._A0,
	    a1 = inputdata.exampleMotor._A1,
	    a2 = inputdata.exampleMotor._A2,
	    fw = inputdata.exampleMotor._FW,
	    t1 = inputdata.exampleMotor._T1,
	    lmotor = inputdata.exampleMotor._L,
	    poles = inputdata.exampleMotor._Poles,
	    heat_cap = inputdata.exampleMotor._heat_cap,
	    therm_cond = inputdata.exampleMotor._therm_cond,
	    maxcur = inputdata.exampleController._maxCurrent,
	    dutycycle,
	    maxW;
	
	
	var imotorfreewheel, ibattfreewheel;
	var freewheelcalculationdone = false;
	
	var kmhflag, mphflag, rpmflag, nmflag, lbsflag;
	var aboveChart;//, aboveChart2;
	if($("#speedUnitFlag").val() == "kph") {kmhflag =true; mphflag =false;  rpmflag = false;}
	else if($("#speedUnitFlag").val() == "mph") {mphflag =true; kmhflag = false;  rpmflag = false;}
	else  {kmhflag = false; mphflag =false;  rpmflag = true;}
	if($("#torqueUnitFlag").val() == "N-m") { nmflag = true; lbsflag = false;}
	else { nmflag = false; lbsflag = true; }
	
	if (!((kmhflag) ||
	     (mphflag) ||
	     (rpmflag))) kmhflag = true;
	if (!(nmflag || lbsflag)) nmflag = true;
	

	if(kmhflag) maxW = global_maxS / (1.8*wsize);
	else if(mphflag) maxW = global_maxS / (1.125*wsize);
	else maxW = global_maxS / (9.54929659);

	
	if (nmflag) {
		aboveChart = "Newton-Metres";
	} else {
		aboveChart = "Pounds Thrust";
	}

    var a_term,b_term,c_term, inot;
	var exp_term,alpha,deltaI,Tperiod,Tcommutation,Trise,iavg,ibatt,velocity,imotor,vcont;
	var datadump = "Data Stream <br>";
	for (plotIndex = 0; plotIndex < NUMBER_OF_POINTS; plotIndex++)
	// If we have the index from 0 to MAX, just divide the index by MAX, then multiply by voc / k
	{
		w = (plotIndex * maxW) / (NUMBER_OF_POINTS - 1);
		velocity = w*wsize/2; 
		
		//outputdata["load"][plotIndex] = velocity*(inputdata.exampleCdA*0.646*velocity*velocity +inputdata.exampleWeight*9.8*inputdata.exampleCf);
		//Changed per adjustments from Justin WRT grade
		outputdata["load"][plotIndex] = velocity*(inputdata.exampleCdA*0.646*velocity*velocity +inputdata.exampleWeight*9.8*(inputdata.exampleCf+Math.sin(Math.atan(inputdata.staticgrade/100))));
		
		// First calculation for stall torque is done ignoring motor inductance
		// This equation is also used if the commutation period is greater than 12 L/R time constants
		if ((plotIndex < 5)||poles<=1)//||(Tperiod > 15*lmotor/(rmotor+rcont)))
		{
			var a = ((parseFloat(voc) + parseFloat(vdiode)) - (maxcur * rbatt));
			var a = ((parseFloat(voc) + parseFloat(vdiode)) - (maxcur * rbatt));
    		var b = 0 - (vdiode +  (w * k));
    		var c = 0 - ((rcont + rmotor) * maxcur);
    		//debuggingOutput = debuggingOutput + "a = " + a + "  b = " + b.toFixed(2) + "  c = " + c.toFixed(2) + "<br>";
    		outputdata["dutyCycle"][plotIndex] = computePositiveQuadratic(a , b, c);
    		//debuggingOutput = debuggingOutput + "D (before testing against throttle): " + outputdata["dutyCycle"][plotIndex].toFixed(3) + "<br>";
    		if (!((outputdata["dutyCycle"][plotIndex] > 0) && (outputdata["dutyCycle"][plotIndex] < inputdata.exampleThrottle))) {
    		    // Either the throttle limits the duty cycle, or the duty cycle is calculated to be negative, so use the throttle value
    			outputdata["dutyCycle"][plotIndex] = inputdata.exampleThrottle;
            }
    		dutycycle = outputdata["dutyCycle"][plotIndex];
    
    		// Now that the duty cycle is known, calculate motor outputs
    		if (w < (voc / k)) {
    			imotor = dutycycle * voc - ((1 - dutycycle) * vdiode) - (w * k);
    			imotor = Math.max(imotor / (rcont + rmotor + (dutycycle * dutycycle * rbatt)), 0);
    		} else {
    			imotor = voc + ((1 - dutycycle) * vdiode) - (w * k);
    			imotor = Math.min(imotor / (rcont + rmotor + rbatt), 0);
    		}
    		outputdata["torque"][plotIndex] = (imotor*k)*(1-t1) - (a0 + (a1 * w) + (a2 * w * w));
    		outputdata["power"][plotIndex] = outputdata["torque"][plotIndex] * w;
			outputdata["pIn"][plotIndex] = (voc - (imotor*dutycycle*rbatt))*imotor*dutycycle
    		if (outputdata["torque"][plotIndex] > 0) { // This is to avoid having negative infinity spoil the graph.
    			outputdata["efficiency"][plotIndex] = outputdata["power"][plotIndex] / outputdata["pIn"][plotIndex];
    		} else {
    			outputdata["efficiency"][plotIndex] = 0;
    		}
    
			Tcommutation = 0; // Do this because Tcommutation needs to be defined when using inductance model
			if(w != 0)
			    Tperiod = 2*Math.PI/(6*parseFloat(poles)*w); 
			else
				Tperiod = 100;
					
			ibatt = imotor*dutycycle;		
		} else { // Otherwise, we do the calcualtions based on inductive model
		    var duty_cnt=0;
			do	// Outer do loop to iteratively hone in on Duty cycle value
			{
    			var i=0, delta_ibatt;
    			do	// We do the calculation loop multiple times to iteratively get closer to solution values
    			{
      			    vcont = dutycycle*(voc-ibatt*rbatt)-vdiode*(1-dutycycle)// This uses previously stored value for ibatt
      			    alpha = k*w/vcont;  // 
                    Tperiod = 2*Math.PI/(6*parseFloat(poles)*w); // Calcuation of Commutation Period
                    Trise = Tperiod - Tcommutation;  // Use previous iteration value for Tcommutation
      			    exp_term = Math.exp((rmotor+rcont)*Trise/lmotor);  // Store result of e^Rm/Rl*Tr,  since it is used a lot
      		
      			    // Determine effective motor phase winding resistance, half the motor and controller resistance
      	
          			rwinding = (rcont + rmotor)/2; 
      			    // Calculations of a, b, and c terms for solving quadratic
          			a_term = -3*(rwinding)*(exp_term+1);
          			b_term = vcont*(2-4*alpha-(exp_term-1)*(0.5+3.5*alpha));
          			c_term = vcont*vcont*(1-alpha*alpha)*(exp_term-1)/rwinding;
          			// inot is the solution to this quadratic, and represents the peak motor phase current
          			// MRVASS - Noted that this equation can exceed floating point exponent size when wheel size is large and battery voltage small (i.e. 
					// 38V battery at 60 inch wheeel -> *10^160), which can result in "infinity" results, which kills the approximation
					// Divided top and bottom of equation by b_term to find following "ceiling-friendly" equation:
					inot = (-b_term-Math.sqrt(1-4*(a_term/b_term)*(c_term/b_term))*Math.abs(b_term))/(2*a_term);
					
					//Original below:
					//inot = (-b_term -Math.sqrt(b_term*b_term - 4*a_term*c_term))/(2*a_term);
          			// The current drop at each commutation (deltaI) is a function of inot
          			deltaI = inot*(vcont*(2-4*alpha)-6*inot*rwinding)/(2*vcont*(1+alpha)+3*inot*rwinding);
      			
          			// The time that is required for commutation to complete
          			Tcommutation = Math.abs(3*inot*lmotor/(2*vcont*(1+alpha)+3*inot*rwinding));		
          			Trise = Tperiod - Tcommutation;  // Get new value for Trise based on recently calculated Tcommutation
      			
          			// Average motor current is a function of inot, deltaI, and exponential time constant
          			i_infinity = vcont*(1-alpha)/(2*rwinding);
          			imotor = (Tcommutation/Tperiod)*(2*inot+deltaI)/2;
          			imotor = imotor +(Trise/Tperiod)*(-lmotor*(inot+deltaI-i_infinity)*(Math.exp(-(rmotor+rcont)*Trise/lmotor)-1)/((rmotor+rcont)*Trise) +i_infinity);

      			    // For now, battery current is the motor current, scaled slighlty by commutation time
      			    delta_ibatt = Math.abs(ibatt-imotor*(1-0.5*(Tcommutation/Tperiod))*dutycycle); //record change in ibatt since last iteration
    				ibatt = 0.5*ibatt +0.5*(imotor*(1-0.5*(Tcommutation/Tperiod))*dutycycle); // The 0.5 factor is to reduce feedback gain
      			    i++;
    			} while((i<50)&&(delta_ibatt>0.01))//repeat up to 50 times to hone in on solution
				// Now we have honed in value for ibatt, imotor, etc. for a particular duty cycle, so
				// hone in to make battery current match the controller current
					
				dutycycle = dutycycle-0.2*(ibatt-maxcur)/maxcur;
				if(dutycycle > inputdata.exampleThrottle)
					dutycycle = inputdata.exampleThrottle;
			} while(duty_cnt++ < 3); // while(Math.abs(ibatt-maxcur)>0.1)
			// Don't allow graph to go into regen display unless voc> w/k
	  	    if (imotor<0) {	
				imotor = voc + ((1 - dutycycle) * vdiode) - (w * k);
    			imotor = Math.min(imotor / (rcont + rmotor + rbatt), 0);
    		}
    		outputdata["torque"][plotIndex] = (imotor*k)*(1-t1) - (a0 + (a1 * w) + (a2 * w * w));
			outputdata["power"][plotIndex] = outputdata["torque"][plotIndex]*w;
			outputdata["pIn"][plotIndex] = (voc -ibatt*rbatt)*ibatt;
			if (outputdata["torque"][plotIndex]<0)
				outputdata["efficiency"][plotIndex]=0;
			else		
				outputdata["efficiency"][plotIndex] = outputdata["power"][plotIndex]/((voc-ibatt*rbatt)*ibatt);
		}
		 
		if (outputdata["torque"][plotIndex] < 0 && fw == 1)
		{
				outputdata["torque"][plotIndex] = 0;
				outputdata["power"][plotIndex] = 0;
				outputdata["efficiency"][plotIndex] = 0;

				if(!freewheelcalculationdone) //Will only make this calculation on the first time through, locks values
				{
				imotorfreewheel = (a0 + (a1 * w) + (a2 * w * w))/k;
				ibattfreewheel = imotor*dutycycle;
				freewheelcalculationdone = true;
				}
				imotor = imotorfreewheel;
				ibatt = ibattfreewheel;
				
		}
		// Now calculate the % grade that can be climbed, given that we know the torque output of the hub
		// Grade = (Motor Thrust - Air Drag - Rolling Drag) / mg
		var drag = (inputdata.exampleCdA*0.646*velocity*velocity)+(inputdata.exampleWeight*9.8*inputdata.exampleCf);
		
		// Scaling by 2000 is because "grade" has to scale up to show up properly with the other lines.
		// We could change the graphing code instead if we felt like it. Check Chart.prototype.add in chart.js
		
		outputdata["grade"][plotIndex] = 2000*(outputdata["torque"][plotIndex]/(wsize/2) - drag)/(9.8*inputdata.exampleWeight);
		
		outputdata["motorCurrent"][plotIndex] = imotor;
		outputdata["batteryVoltage"][plotIndex] = voc - (ibatt*rbatt);
		outputdata["batteryCurrent"][plotIndex] = ibatt;
		
        // Avoid divide-by-zero errors... pretty unlikely, but could happen:
        if (ibatt == 0) ibatt = 0.001;
		// The speed, hard coded in km/h: (3.6 * pi / 2 * pi) * w * wsize
		if (kmhflag) { // kph
			outputdata["speed"][plotIndex] = 1.8 * w * wsize;
    		var range = parseFloat((outputdata["speed"][plotIndex] * inputdata.exampleBattery._amph) / ibatt);
    		if(range < 0) outputdata["range"][plotIndex] = "infinity";
			else if (range < 10) outputdata["range"][plotIndex] = range.toFixed(1) + " km";
    		else outputdata["range"][plotIndex] = parseInt(range) + " km";
    		outputdata["whKm"][plotIndex] = outputdata["pIn"][plotIndex] / outputdata["speed"][plotIndex]; // speed always in km/h
    		//$('#performance_wh_km div').first().html("Wh/km");

		} else if (mphflag) { // mph
			outputdata["speed"][plotIndex] = 1.125 * w * wsize;
    		var range = parseFloat((outputdata["speed"][plotIndex] * inputdata.exampleBattery._amph) / ibatt);
    		if(range < 0) outputdata["range"][plotIndex] = "infinity";
			else if (range < 10) outputdata["range"][plotIndex] = range.toFixed(1) + " mi";
    		else outputdata["range"][plotIndex] = parseInt(range) + " mi";
    		outputdata["whKm"][plotIndex] = outputdata["pIn"][plotIndex] / outputdata["speed"][plotIndex]; // speed always in km/h
    		//$('#performance_wh_km div').first().html("Wh/mi");
		} else { // rpm
			outputdata["speed"][plotIndex] = w * 9.54929659 // This looks like a hack, but it's faster. 60 / 2 * pi
    		if(range < 0) outputdata["range"][plotIndex] = "infinity";
			else outputdata["range"][plotIndex] = (outputdata["speed"][plotIndex] * inputdata.exampleBattery._amph * 60 / ibatt /1000).toFixed(1) + "kR";
    		//outputdata["whKm"][plotIndex] = outputdata["pIn"][plotIndex] * 1000 / outputdata["speed"][plotIndex]; // speed always in km/h
			outputdata["whKm"][plotIndex] = outputdata["pIn"][plotIndex] * 1000 / (outputdata["speed"][plotIndex] *60); // speed in rev/m, should be rev/h
    		//$('#performance_wh_km div').first().html("Wh/kR");
		}

		// Calculate overheating here		
		var Tmax = 150;  // (motor temp we counsider 'overheated')
        var Tamb = 25;  // (ambient temperature)

        var Ptherm = imotor * imotor * rmotor;
        if (Ptherm / therm_cond + Tamb <= Tmax) {
           outputdata["overheatIn"][plotIndex] = "never"; // (Motor will never get to the temperature of Tmax at this current level)
        } else {
            var overheat_seconds = -(heat_cap / therm_cond) * Math.log([1 -(Tmax - Tamb) * (therm_cond / Ptherm)]);
            if (overheat_seconds > 60) {
                var overheat_minutes = (overheat_seconds / 60.0);
                if (overheat_minutes > 60) {
                    outputdata["overheatIn"][plotIndex] = parseInt(overheat_minutes / 60) + " hour(s)";
                }
				else {
			        // If over ten minutes, show an integer, otherwise one decimal place
                    outputdata["overheatIn"][plotIndex] = ((overheat_minutes > 10) ? parseInt(overheat_minutes) : overheat_minutes.toFixed(1))+ " minutes";
                }
            } else {
			     outputdata["overheatIn"][plotIndex] = ((overheat_seconds > 10) ? parseInt(overheat_seconds) : overheat_seconds.toFixed(1)) + " seconds";
            }
	    }
		//(mtr pwr - load pwr) = W = N*m/s, /mass -> m^2/s^3, /m/s = m/s^2
		// m/s = omega / (2*pi) * wsize(diameter)*pi = omega/2*wsize = w/2*wsize
		outputdata["acceleration"][plotIndex] = (outputdata["power"][plotIndex] - outputdata["load"][plotIndex])/inputdata.exampleWeight/(w/2*wsize);
		
		
		if (!nmflag) // We are in Lbs
		{
			outputdata["torque"][plotIndex] = (outputdata["torque"][plotIndex] * 0.22449) * 2/ wsize; // Divide by radius; this explains the scaling factor of 2.
		}
//		debuggingOutput = debuggingOutput + "<br>" +"w: " + w.toFixed(2) + "\tSpeed: " + outputdata["speed"][plotIndex].toFixed(1) + "\ti_batt: " + ibatt.toFixed(2) + "\ti_motor: " + imotor.toFixed(2) + "\tTorque: " + outputdata["torque"][plotIndex].toFixed(2) + "\tPout: " + outputdata["power"][plotIndex].toFixed(1) + "\tMotor Eff'y: " + outputdata["efficiency"][plotIndex].toFixed(3);
	}

    // printDiags();
	// document.getElementById("debugOutput").innerHTML = debuggingOutput;
	document.getElementById("aboveChart").innerHTML = aboveChart;
	//document.getElementById("aboveChart2").innerHTML = aboveChart2;
	return true;
}

function findchart(series, label)
{
	for(var i = 0;i<series.length;i++)
	{
		if(series[i].label == label)
		{
			return i;
		}
	}
	
	return "fail";
}

function chartaxesadjust(chart)
{
	var torquemax, axesRatio;

torque1num = findchart(chart._series, torqueLabel);
power1num = findchart(chart._series, "Power A");
eff1num = findchart(chart._series, "Efficiency A");

if($("#gradeloadflag").val() == "grade")
{
	gradeload1num = findchart(chart._series, "Grade A");
}
else
{
	gradeload1num = findchart(chart._series, "Load A");
}

if(comparisonchart)
{
	torque2num = findchart(chart._series, torqueLabel2);
	power2num = findchart(chart._series, "Power B");
	eff2num = findchart(chart._series, "Efficiency B");

	if($("#gradeloadflag").val() == "grade")
	{
		gradeload2num = findchart(chart._series, "Grade B");
	}
	else
	{
		gradeload2num = findchart(chart._series, "Load B");
	}
}

	chart._series[torque1num].ymin = -10;
	chart._series[power1num].ymin = 20 * chart._series[torque1num].ymin;

	chart._series[torque1num].ymax = (Math.floor(chart._series[torque1num].ymax / 10) + 1) * 10; //Nearest 10
	chart._series[power1num].ymax = (Math.floor(chart._series[power1num].ymax / 100) + 1) * 100; //Nearest 100


	if(chart._series[torque1num].ymax < 50) { chart._series[torque1num].ymax = 50; }


	if(comparisonchart)
	{
		chart._series[torque2num].ymin = -10;
		chart._series[power2num].ymin = 20 * chart._series[torque1num].ymin;

	chart._series[torque2num].ymax = (Math.floor(chart._series[torque2num].ymax / 10) + 1) * 10; //Nearest 10
	chart._series[power2num].ymax = (Math.floor(chart._series[power2num].ymax / 100) + 1) * 100; //Nearest 100
	
		if(chart._series[torque2num].ymax < 50) { chart._series[torque2num].ymax = 50; }
		
		if(chart._series[torque2num].ymax > chart._series[torque1num].ymax)
		{
			chart._series[torque1num].ymax = chart._series[torque2num].ymax;
		}
		else
		{
			chart._series[torque2num].ymax = chart._series[torque1num].ymax;
		}
	}


	if(comparisonchart)
	{
		if(chart._series[power1num].ymax > chart._series[power2num].ymax)
		{
			torquemax = chart._series[power1num].ymax;
			chart._series[power2num].ymax = chart._series[power1num].ymax;

		}
		else
		{
			torquemax = chart._series[power2num].ymax;
			chart._series[power1num].ymax = chart._series[power2num].ymax;
		}
		
	}
	else
	{
	torquemax = chart._series[power1num].ymax;
	}


	if (torquemax > chart._series[torque1num].ymax * 20) //If our Ymax is beyond 20 times the other torque ymax, adjust ther other ymax to compensate
	{
		chart._series[torque1num].ymax = torquemax / 20;
		if(comparisonchart) chart._series[torque2num].ymax = torquemax / 20;
	}
	else
	{
		chart._series[power1num].ymax = chart._series[torque1num].ymax * 20;
		if(comparisonchart)
		{
			chart._series[power2num].ymax = chart._series[torque1num].ymax * 20;
		}
		
	}
	
if($("#gradeloadflag").val() == "grade")
{
	chart._series[gradeload1num].ymin = 20 * chart._series[torque1num].ymin;
	chart._series[gradeload1num].ymax = chart._series[torque1num].ymax * 20;
	if(comparisonchart)
	{
		chart._series[gradeload2num].ymin = 20 * chart._series[torque1num].ymin;
		chart._series[gradeload2num].ymax = chart._series[torque1num].ymax * 20;
	}
}
else
{
	chart._series[gradeload1num].ymin = chart._series[power1num].ymin;
	chart._series[gradeload1num].ymax = chart._series[power1num].ymax;
	if(comparisonchart)
	{
		chart._series[gradeload2num].ymin = chart._series[power1num].ymin;
		chart._series[gradeload2num].ymax = chart._series[power1num].ymax;
	}
}
	
	

	chart._series[torque1num].range = chart._series[torque1num].ymax - chart._series[torque1num].ymin;
	chart._series[power1num].range = chart._series[power1num].ymax - chart._series[power1num].ymin;
	chart._series[gradeload1num].range = chart._series[gradeload1num].ymax - chart._series[gradeload1num].ymin;
	
	chart._series[eff1num].ymax = 1; //We want 100% to be the top of the graph for efficiency
	axesRatio = (chart._series[eff1num].ymax / chart._series[torque1num].ymax);
	chart._series[eff1num].ymin = chart._series[torque1num].ymin * axesRatio;
	chart._series[eff1num].range = chart._series[eff1num].ymax - chart._series[eff1num].ymin;

	if(comparisonchart)
	{
	chart._series[eff2num].ymax = 1;
	axesRatio = (chart._series[eff2num].ymax / chart._series[torque1num].ymax);
	chart._series[eff2num].ymin = chart._series[torque1num].ymin * axesRatio;
	
	chart._series[power2num].range = chart._series[power2num].ymax - chart._series[power2num].ymin;
	chart._series[gradeload2num].range = chart._series[gradeload2num].ymax - chart._series[gradeload2num].ymin;
	chart._series[eff2num].range = chart._series[eff2num].ymax - chart._series[eff2num].ymin;
	chart._series[torque2num].range = chart._series[torque2num].ymax - chart._series[torque2num].ymin;
	}

	for(var i =0;i<chart._series.length;i++) //Catch all graphs not spec'd, scale them to torque
	{
		if((i != power1num) && (i != torque1num) && (i != eff1num) && (i != gradeload1num))
		{
		
			if(comparisonchart)
			{
				
				if((i != power2num) && (i != torque2num) && (i != eff2num) && (i != gradeload2num))
				{
				axesRatio = chart._series[i].ymax / chart._series[power1num].ymax;
				chart._series[i].ymax = chart._series[power1num].ymax * axesRatio;
				chart._series[i].ymin = chart._series[power1num].ymin * axesRatio;
				chart._series[i].range = chart._series[i].ymax - chart._series[i].ymin;
				}
			}
			else
			{
				axesRatio = chart._series[i].ymax / chart._series[power1num].ymax;
				chart._series[i].ymax = chart._series[power1num].ymax * axesRatio;
				chart._series[i].ymin = chart._series[power1num].ymin * axesRatio;
				chart._series[i].range = chart._series[i].ymax - chart._series[i].ymin;
			}
		}
		//else do nothing
	}
	
	
		chart._yGridDensity = (chart._series[torque1num].range / 5) + 1;	
// Sets ymax to nearest 10 of values unless < 50, and sets ymin to -10 regardless. Assumes input values. will adjust current or first series to match	

// Sets ymin to a set -200, finds ymax and rounds to nearest 100. If exceeding ymax*20 of first graph, sets first graph ymax to value and resets range and grid
		
}



function printDiags()
{
	debuggingOutput = debuggingOutput +"<br>" + "Motor:  id: " + exampleMotor._id + "   name: " + exampleMotor._name + "   K: " + exampleMotor._K + "   Rmotor: " + exampleMotor._Rmotor + "   A0: " + exampleMotor._A0 + " Poles: " + exampleMotor._Poles + "   L: " + exampleMotor._L + "<br>";
	debuggingOutput = debuggingOutput + "Battery:   id: " + exampleBattery._id + "   voltage: " + exampleBattery._voltage + "   amph: " + exampleBattery._amph + "   type: " + exampleBattery._type + "   Voc: " + exampleBattery._Voc + "   Rbatt: " + exampleBattery._Rbatt + "<br>";
	debuggingOutput = debuggingOutput + "Wheelsize:  size: " + exampleWheelSize._size.toFixed(2) + "<br>";
	debuggingOutput = debuggingOutput + "Controller:   id: " + exampleController._id + "   name: " + exampleController._name + "   maxCurrent: " + exampleController._maxCurrent + "   Rcont: " + exampleController._Rcont + "   Vdiode: " + exampleController._Vdiode + "<br>";
	debuggingOutput = debuggingOutput + "Throttle:   Percentage: " + exampleThrottle * 100 + "<br><br>";
	
	return true;
};

