var rowBEW = 1;
var rowFrontSeats = 2;
var rowRearSeats = 3;
var rowTakeoffFuel = 4;
var rowLandingFuel = 5;
var rowBaggage1 = 6;
var rowBaggage2 = 7;
var rowTakeoffWeight = 8;
var rowLandingWeight = 9;

var colArm = 1;
var colWeight = 2;
var colMoment = 3;

var errGoodToGo			= "<p class=\"wbok\">Weight and balance is within limits.</p>";
var errOverGross		= "<p class=\"wberr\">Maximum take off weight exceeded.</p>";
var errOverGrossBaggage = "<p class=\"wberr\">Baggage weight exceeds limitations.</p>";
var errTakeoffCGBad		= "<p class=\"wberr\">Take off CG is out of the envelope.</p>";
var errLandingCGBad		= "<p class=\"wberr\">Landing CG is out of the envelope.</p>";
var errLandingTooHeavy	= "<p class=\"wberr\">Landing weight over maximum allowed.</p>";
var errExceedMaxZeroFuel= "<p class=\"wberr\">Maximum zero fuel weight exceeded.</p>";
var errTooMuchFuel		= "<p class=\"wberr\">Fuel exceeds maximum amount.</p>";

var envelope_width = 200;
var envelope_height = 200;
var envelope_top = 0;
var envelope_left = 0;

function GetWBTable()
{
	return document.getElementById('wbTable');
}

function GetTableCellData(table, row, column)
{
	return table.rows[row].cells[column].childNodes[0].data;
}

function GetTableCellInt(table, row, column)
{
	return parseIntOrNull(GetTableCellData(table, row, column));
}

function GetTableCellFloat(table, row, column)
{
	return parseFloatOrNull(GetTableCellData(table, row, column));
}

function SetTableCellData(table, row, column, data)
{
	table.rows[row].cells[column].childNodes[0].data = data;
}

function ShowHideElement(element, visibility)
{
	var elementObject = document.getElementById(element);
	if (elementObject == null) alert(element);
	elementObject.className = visibility;
}

function InitializeAirplaneData()
{
	var i;
	for (i = 0; i < airplaneDescriptions.length; i++)
	{
		var tail = airplaneDescriptions[i].tail;
		var newOption = document.createElement("OPTION");
		newOption.text = tail;
		newOption.value = tail;
		document.wb.airplaneList.options.add(newOption);
	}
}

function InitilizedAirplaneWB(i)
{
	// set all the arms
	var wbTable = GetWBTable();
	SetTableCellData(wbTable, rowBEW, colArm, airplaneDescriptions[i].armBEW);
	SetTableCellData(wbTable, rowFrontSeats, colArm, airplaneDescriptions[i].armFront);
	SetTableCellData(wbTable, rowRearSeats, colArm, airplaneDescriptions[i].armRear);
	SetTableCellData(wbTable, rowTakeoffFuel, colArm, airplaneDescriptions[i].armFuel);
	SetTableCellData(wbTable, rowLandingFuel, colArm, airplaneDescriptions[i].armFuel);
	SetTableCellData(wbTable, rowBaggage1, colArm, airplaneDescriptions[i].armBaggage1);
	SetTableCellData(wbTable, rowBaggage2, colArm, airplaneDescriptions[i].armBaggage2);
	
	// set the known weights - just the BEW
	SetTableCellData(wbTable, rowBEW, colWeight, airplaneDescriptions[i].BEW);

	// Hide the rear seats on the 152 - FAA won't be happy if they found out about them
	if (airplaneDescriptions[i].armRear == null || airplaneDescriptions[i].armRear == 0)
	{
		ShowHideElement("RRightSpan", "hide");
		ShowHideElement("RLeftSpan", "hide");
		
		document.getElementById("RLeft").value = "";
		document.getElementById("RRight").value = "";
		SetTableCellData(wbTable, rowRearSeats, colWeight, 0);
	}
	else
	{
		ShowHideElement("RRightSpan", "lbs");
		ShowHideElement("RLeftSpan", "lbs");
	}
	
	// Hide the second baggage area on pa-28
	if (airplaneDescriptions[i].armBaggage2 == null || airplaneDescriptions[i].armBaggage2 == 0)
	{
		ShowHideElement("Baggage2Span", "hide");
		
		document.getElementById("Baggage2").value = "";
		SetTableCellData(wbTable, rowBaggage2, colWeight, 0);
	}
	else
	{
		ShowHideElement("Baggage2Span", "lbs");
	}
}

function PositionGraphics()
{
	positionDiv("egraph", envelope_left, envelope_top);
	positionDiv("landingdot", envelope_left, envelope_top);
	positionDiv("takeoffdot", envelope_left, envelope_top);
}

function CalculateMoments()
{
	var wbTable = GetWBTable();
	var i;
	for (i = 1; i <= 7; i++)
	{
		var momentum = GetTableCellFloat(wbTable, i, colArm) * GetTableCellFloat(wbTable, i, colWeight);
		SetTableCellData(wbTable, i, colMoment, parseInt(momentum));
	}
	
	var takeoffMomentum =
		GetTableCellInt(wbTable, rowBEW, colMoment) +
		GetTableCellInt(wbTable, rowFrontSeats, colMoment) +
		GetTableCellInt(wbTable, rowRearSeats, colMoment) +
		GetTableCellInt(wbTable, rowTakeoffFuel, colMoment) +
		GetTableCellInt(wbTable, rowBaggage1, colMoment) +
		GetTableCellInt(wbTable, rowBaggage2, colMoment);

	var landingMomentum =
		GetTableCellInt(wbTable, rowBEW, colMoment) +
		GetTableCellInt(wbTable, rowFrontSeats, colMoment) +
		GetTableCellInt(wbTable, rowRearSeats, colMoment) +
		GetTableCellInt(wbTable, rowLandingFuel, colMoment) +
		GetTableCellInt(wbTable, rowBaggage1, colMoment) +
		GetTableCellInt(wbTable, rowBaggage2, colMoment);

	SetTableCellData(wbTable, rowTakeoffWeight, colMoment, takeoffMomentum);
	SetTableCellData(wbTable, rowLandingWeight, colMoment, landingMomentum);
}

function CalculateTotalWeights()
{
	var wbTable = GetWBTable();
	var takeoffWeight = 
		GetTableCellInt(wbTable, rowBEW, colWeight) +
		GetTableCellInt(wbTable, rowFrontSeats, colWeight) +
		GetTableCellInt(wbTable, rowRearSeats, colWeight) +
		GetTableCellInt(wbTable, rowTakeoffFuel, colWeight) +
		GetTableCellInt(wbTable, rowBaggage1, colWeight) +
		GetTableCellInt(wbTable, rowBaggage2, colWeight);
	
	var landningWeight =
		GetTableCellInt(wbTable, rowBEW, colWeight) +
		GetTableCellInt(wbTable, rowFrontSeats, colWeight) +
		GetTableCellInt(wbTable, rowRearSeats, colWeight) +
		GetTableCellInt(wbTable, rowLandingFuel, colWeight) +
		GetTableCellInt(wbTable, rowBaggage1, colWeight) +
		GetTableCellInt(wbTable, rowBaggage2, colWeight);
	
	SetTableCellData(wbTable, rowTakeoffWeight, colWeight, takeoffWeight);
	SetTableCellData(wbTable, rowLandingWeight, colWeight, landningWeight);
}

function CalculateTotalArms()
{
	var wbTable = GetWBTable();
	var takeoffArm = GetTableCellFloat(wbTable, rowTakeoffWeight, colMoment) / GetTableCellFloat(wbTable, rowTakeoffWeight, colWeight);
	var landingArm = GetTableCellFloat(wbTable, rowLandingWeight, colMoment) / GetTableCellFloat(wbTable, rowLandingWeight, colWeight);
		
	// Round the numbers
	takeoffArm = Math.round(takeoffArm * 10) / 10;
	landingArm = Math.round(landingArm * 10) / 10;
	SetTableCellData(wbTable, rowTakeoffWeight, colArm, takeoffArm);
	SetTableCellData(wbTable, rowLandingWeight, colArm, landingArm);
}

function RecalculateWeightAndBalance()
{
	CalculateTotalWeights();
	CalculateMoments();
	CalculateTotalArms();
	validateWeightAndBalance();
}

function parseIntOrNull(number)
{
	return parseInt(number ? number : 0);
}

function parseFloatOrNull(number)
{
	return parseFloat(number ? number : 0.0);
}

function PopulateData(form)
{
	// front and rear seats
	var front = parseIntOrNull(form.FRight.value) + parseIntOrNull(form.FLeft.value);
	var rear = parseIntOrNull(form.RRight.value) + parseIntOrNull(form.RLeft.value);
	
	var wbTable = GetWBTable();
	SetTableCellData(wbTable, rowFrontSeats, colWeight, front);
	SetTableCellData(wbTable, rowRearSeats, colWeight, rear);
	
	// Fuel amounts
	SetTableCellData(wbTable, rowTakeoffFuel, colWeight, 6 * parseIntOrNull(form.Fuel.value)); // Take off fuel as entered by the user
	SetTableCellData(wbTable, rowLandingFuel, colWeight, 6 * parseIntOrNull(form.Burn.value)); // Minimum fuel 
	
	// Baggage area
	SetTableCellData(wbTable, rowBaggage1, colWeight, parseIntOrNull(form.Baggage1.value));
	SetTableCellData(wbTable, rowBaggage2, colWeight, parseIntOrNull(form.Baggage2.value));
}

function GetAirplaneByTailNumber(tail)
{
	var definitionsCount = airplaneDescriptions.length;
	var result;
	var i;
	for (i = 0; i < definitionsCount; i++)
	{
		if (airplaneDescriptions[i].tail == tail)
		{
			result = airplaneDescriptions[i];
		}
	}
	
	return result;
}

function InitializeAirplane(airplane)
{
	var definitionsCount = airplaneDescriptions.length;
	var i;
	for (i = 0; i < definitionsCount; i++)
	{
		if (airplaneDescriptions[i].tail == airplane)
		{
			InitilizedAirplaneWB(i);
		}
	}
	
	var selectedAirplane = GetAirplaneByTailNumber(airplane);
	var envelope = GetAirplaneEnvelope(selectedAirplane);
	var imageElement = document.getElementById("envelope_graph");
	imageElement.setAttribute("src", envelope.graph);
}

function getEnvelopeBoundaries(envelope)
{
	var boundaries =
	{
		'minx' : 10000,
		'maxx' : 0,
		'miny' : 10000,
		'maxy' : 0
	}
	for (i = 0; i < envelope.x.length; i++)
	{
		if (envelope.x[i] > boundaries.maxx)
			boundaries.maxx = envelope.x[i];
		if (envelope.y[i] > boundaries.maxy)
			boundaries.maxy = envelope.y[i];
		if (envelope.x[i] < boundaries.minx)
			boundaries.minx = envelope.x[i];
		if (envelope.y[i] < boundaries.miny)
			boundaries.miny = envelope.y[i];
	}
	
	return boundaries;
}

function pointInsideConvex(point, vertices)
{
	var vcount = vertices.x.length;
	var inside = true;
	var i;
	for (i = 0; i < vcount-1; i++)
	{
		var pos = (point.y - vertices.y[i]) * (vertices.x[i+1] - vertices.x[i]) -
			(point.x - vertices.x[i]) * (vertices.y[i+1] - vertices.y[i]);
		if (pos < 0)
		{
			inside = false;
			break;
		}
	}
	
	return inside;
}

function GetAirplaneType(airplane)
{
	var i;
	var type;
	
	for (i = 0; i < airplaneEnvelopes.length; i++)
	{
		if (airplane.type == airplaneEnvelopes[i].type)
		{
			type = airplaneEnvelopes[i];
			break;
		}
	}
	
	return type;
}

function GetAirplaneEnvelope(airplane)
{
	var i;
	var envelope;
	
	for (i = 0; i < airplaneEnvelopes.length; i++)
	{
		if (airplane.type == airplaneEnvelopes[i].type)
		{
			envelope = airplaneEnvelopes[i].envelope;
			break;
		}
	}
	
	return envelope;
}

function validateWeightAndBalance()
{
	var wbTable = GetWBTable();
	var tailNumber = GetSelectedAirplane().value;
	var selectedAirplane = GetAirplaneByTailNumber(tailNumber);
	var resolution;
	var cg = { 'x' : 0, 'y' : 0};
	
	// Check takeoff max gross
	var totalTakeoff = GetTableCellInt(wbTable, rowTakeoffWeight, colWeight);
	if (totalTakeoff > selectedAirplane.maxgross)
	{
		resolution = errOverGross;
	}
	
	// Check landing weight
	var totalLanding = GetTableCellInt(wbTable, rowLandingWeight, colWeight);
	if (selectedAirplane.maxland != null && totalLanding > selectedAirplane.maxland)
	{
		resolution = resolution ? resolution + errLandingTooHeavy : errLandingTooHeavy;
	}
	
	// Check maximum zero fuel weight
	if (selectedAirplane.mzfw != null)
	{
		var fuel = GetTableCellInt(wbTable, rowTakeoffFuel, colWeight);
		var zerofuelweight = totalTakeoff - fuel;
		if (zerofuelweight > selectedAirplane.mzfw)
		{
			resolution = resolution ? resolution + errExceedMaxZeroFuel : errExceedMaxZeroFuel;
		}
	}
	
	// Check any baggag max totals
	var totalBaggage = GetTableCellInt(wbTable, rowBaggage1, colWeight) + GetTableCellInt(wbTable, rowBaggage2, colWeight);
	if (totalBaggage > selectedAirplane.maxTotalBaggage)
	{
		resolution = resolution ? resolution + errOverGrossBaggage : errOverGrossBaggage; 
	}
	
	// Check that the CG is within the envelope for takeoff and landing
	cg.x = GetTableCellFloat(wbTable, rowTakeoffWeight, colArm);
	cg.y = GetTableCellInt(wbTable, rowTakeoffWeight, colWeight);
	
	var type = GetAirplaneType(selectedAirplane);
	var envelope = GetAirplaneEnvelope(selectedAirplane);

	if (!pointInsideConvex(cg, envelope))
	{
		resolution = resolution ? resolution + errTakeoffCGBad : errTakeoffCGBad;
	}
	
	drawCg(envelope, cg, "takeoffdot");
	
	cg.x = GetTableCellFloat(wbTable, rowLandingWeight, colArm);
	cg.y = GetTableCellInt(wbTable, rowLandingWeight, colWeight);
	if (!pointInsideConvex(cg, envelope))
	{
		resolution = resolution ? resolution + errLandingCGBad : errLandingCGBad;
	}
	
	drawCg(envelope, cg, "landingdot");
	
	// Check if fuel is within limits
	var takeoffFuel = GetTableCellInt(wbTable, rowTakeoffFuel, colWeight);
	var landingFuel = GetTableCellInt(wbTable, rowLandingFuel, colWeight);
	
	if (type.maxfuel != null && (type.maxfuel * 6 < takeoffFuel || type.maxfuel * 6 < landingFuel))
	{
		resolution = resolution ? resolution + errTooMuchFuel : errTooMuchFuel;
	}
	
	if (!resolution)
	{
		resolution = errGoodToGo;
	}
	
	setResolution(resolution);
}

function drawCg(envelope, cg, divname)
{
	boundaries = getEnvelopeBoundaries(envelope);
	scalex = 1.0 * envelope_width / (boundaries.maxx - boundaries.minx);
	scaley = 1.0 * envelope_height / (boundaries.maxy - boundaries.miny);
	cgx = (cg.x - boundaries.minx) * scalex;
	cgy = (cg.y - boundaries.miny) * scaley;
	
	positionDiv(divname, envelope_left + cgx, envelope_top + envelope_height - cgy);	
}

function onChangeValue(form)
{
	PopulateData(form);
	RecalculateWeightAndBalance();
}

function initPage()
{
	InitializeAirplaneData();
	updateSelectedAirplane();
	PopulateData(document.getElementById('wb'));
	PositionGraphics();
	RecalculateWeightAndBalance();
}

function GetSelectedAirplane()
{
	var airplanesCount = document.wb.airplaneList.length;
	var i, result;
	for (i = 0; i < airplanesCount; i++)
	{
		if (document.wb.airplaneList[i].selected)
		{
			result = document.wb.airplaneList[i];
			break;
		}
	}
	
	return result;
}

function updateSelectedAirplane()
{
	var selected = GetSelectedAirplane();
	InitializeAirplane(selected.value);
	RecalculateWeightAndBalance();
}

function setResolution(text)
{
	document.getElementById("resolution").innerHTML = text;
}

function drawPoint(x,y)
{
	text = "<div style='position:absolute;left:"+x+"px;top:"+y+"px;width:1px;height:1px;background:#C0C0C0></div>";
	document.body.innerHTML += text;
}

function positionDiv(name, x, y)
{
	div = document.getElementById(name);
	xs = x + "px";
	ys = y + "px";
	div.style.top = ys;
	div.style.left = xs;
	div.style.position = "absolute";
}


