var WB_xStart;	// X and Y coord of starting values on the graph
var WB_yStart;
var WB_xNoFuel;	// X and Y coord of values when fuel is 0
var WB_yNoFuel;
var WB_boundingCoords = new Array(14);	// points that describe the valid weight balance polygon

WB_boundingCoords[0] = 97.5;
WB_boundingCoords[1] = 19.29;
WB_boundingCoords[2] = 59.7;
WB_boundingCoords[3] = 192.86;
WB_boundingCoords[6] = 46.89;
WB_boundingCoords[7] = 250.71;
WB_boundingCoords[8] = 232.5;
WB_boundingCoords[9] = 19.29;
WB_boundingCoords[10] = 266.25;
WB_boundingCoords[11] = 192.86;
WB_boundingCoords[12] = 97.5;
WB_boundingCoords[13] = 19.29;



function updateMoments(momentID) {
	// Load up data for this row and update the values
	var weight = $F('WEIGHT_' + momentID);
	var longArm = $F('LONGARM_' + momentID);
	var latArm = $F('LATARM_' + momentID);

	var longMoment = round(weight * longArm, 2);
	var latMoment = round(weight * latArm, 2);

	Element.update('LATMOMENT_' + momentID, String(latMoment));	
	Element.update('LONGMOMENT_' + momentID, String(longMoment));

	updateTotals();

}

function updateAllMoments() {
	for (var i=0; i < NUM_MOMENTS; i++) {
		updateMoments(i);
	}
}

// MAX_MOMENTS is the highest moment index on the page
// this should be set by the calling page (weightBalance.php)
function updateTotals() {
	var weightTotal = round(getTotalOfFields("WEIGHT_"), 2);
	var longMomentTotal = round(getTotalOfDivs("LONGMOMENT_"), 2);
	var latMomentTotal = round(getTotalOfDivs("LATMOMENT_"), 2);

	var longCG = round(longMomentTotal / weightTotal, 2);
	var latCG = round(latMomentTotal / weightTotal, 2);

	Element.update('weightTotal', String(weightTotal));
	Element.update('longMomentTotal', String(longMomentTotal));
	Element.update('latMomentTotal', String(latMomentTotal));
	
	Element.update('longcg', String(longCG));
	Element.update('latcg', String(latCG));

	// Draw the CG on the graph
	clearArea();

	// Draw coordinate when fuel is full
	wb_xStart = getRealXCoord(latCG);
	wb_yStart = getRealYCoord(longCG);
	drawPoint(wb_xStart, wb_yStart, "#000000", "");

	// Calculate our values without fuel
	// TODO: make this not hardcoded		
	weightTotal = round(getTotalOfFields("WEIGHT_") - $F('WEIGHT_3'), 2);	
	longMomentTotal = round(getTotalOfDivs("LONGMOMENT_") - $('LONGMOMENT_3').innerHTML, 2);
	latMomentTotal = round(getTotalOfDivs("LATMOMENT_") - $('LATMOMENT_3').innerHTML, 2);

	longCG = round(longMomentTotal / weightTotal, 2);
	latCG = round(latMomentTotal / weightTotal, 2);

	// Draw coordinate when fuel is empty
	wb_xNoFuel = getRealXCoord(latCG);
	wb_yNoFuel = getRealYCoord(longCG);
	//alert(wb_xNoFuel + " " + wb_yNoFuel);
	drawPoint(wb_xNoFuel, wb_yNoFuel, "#FF0000", "");

	var g = new jsGraphics("wbchart");
	g.setPrintable(true);
	g.drawLine(wb_xStart, wb_yStart, wb_xNoFuel, wb_yNoFuel);
	g.paint();

	checkLimits();
}

function drawPoint(x, y, color, label) {
	var g = new jsGraphics("wbchart");	
	g.setPrintable(true);
	g.setColor(color);
	if (x > 0 && y > 0 && x < 300 && y < 300) {
		g.fillEllipse(x - 3, y - 3, 6, 6);

		if (label) {
			g.setFont("arial", "12px", Font.BOLD);
			g.drawString(label, x, y);
		}

		g.paint();
	}
}


function clearArea() {
	$('wbchart').innerHTML = "";
	renderWBChart();
	
}


function checkLimits() {
	var currWeight = $('weightTotal').innerHTML - 0;
	var currLongCG = $('longcg').innerHTML - 0;
	var currLatCG = $('latcg').innerHTML - 0;	
	
	// Check weight
	if (currWeight > MAX_WEIGHT) {
		showWarning("The current weight (" + currWeight + ") exceeds the max weight of " + MAX_WEIGHT);
		return;
	}

	// Check initial bounds of chart
	if (! (wb_xStart > 0 && wb_yStart > 0 && wb_xStart < 300 && wb_yStart < 300) ) {
		showWarning("CG values are outside safe limits");
		return;
	}

	// Check if drawn start point is within polygon
	/*
	if (! inPoly(WB_boundingCoords, wb_xStart, wb_yStart)) {
		showWarning("CG values are outside safe limits");
		return;
	}
	*/
	

	// No warnings, hide the warning message
	Element.hide('warningDisplay');
}


function showWarning(message) {
	Element.update('warningDisplay', message);
	Element.show('warningDisplay');
	new Effect.Highlight('warningDisplay');
}

function getTotalOfFields(fieldName) {
	var total = 0;

	for (var i=0; i < MAX_MOMENTS; i++) {
		total += ($F(String(fieldName) + String(i)) - 0);
	}

	return total;
}

function getTotalOfDivs(fieldName) {
	var total = 0;

	for (var i=0; i < MAX_MOMENTS; i++) {
		total += ($(String(fieldName) + String(i)).innerHTML - 0);
	}

	return total;
}

function round(decimal, numPlaces) {
	var rounder = Math.pow(10, numPlaces);

	return Math.round(decimal * rounder) / rounder;
}

function getMaxAppliesAt() {
	var maxVal = 0;

	for (var i=0; i < LIMIT_DATA.length; i++) {		
		if (LIMIT_DATA[i].appliesAt - 0 > maxVal) {
			maxVal = LIMIT_DATA[i].appliesAt;
		}
	}

	return maxVal;
}

function getMinAppliesAt() {
	var minVal = 10000;
	
	for (var i=0; i < LIMIT_DATA.length; i++) {		
		// Skip 0 values
		if (LIMIT_DATA[i].appliesAt == 0) {
			continue;
		}

		if (LIMIT_DATA[i].appliesAt - 0 < minVal) {			
			minVal = LIMIT_DATA[i].appliesAt;
		}
	}

	return minVal;
}


function getLimit(limitType, lowerOrUpper, appliesAt) {
	// We need to search the array backwards
	for (var i=LIMIT_DATA.length-1; i >= 0; i--) {		
		if (LIMIT_DATA[i].limitType == limitType) {						
			if (LIMIT_DATA[i].appliesAt - 0 >= appliesAt) {	
				if (lowerOrUpper == 'lower') {
					return LIMIT_DATA[i].lowerVal;
				} else {
					return LIMIT_DATA[i].upperVal;
				}
			}
		}		
	}

	return 0;
}

function getLowestLimit(limitType) {
	var minLimit = 10000;

	for (var i=0; i < LIMIT_DATA.length; i++) {		
		if (LIMIT_DATA[i].limitType == limitType) {				
			if (LIMIT_DATA[i].lowerVal - 0 < minLimit) {				
				minLimit = LIMIT_DATA[i].lowerVal;
			}
		}
	}

	if (minLimit >= 0) {
		return Math.ceil(minLimit);
	} else {
		return Math.floor(minLimit);
	}
}

function getHighestLimit(limitType) {
	var maxLimit = 0;

	for (var i=0; i < LIMIT_DATA.length; i++) {		
		if (LIMIT_DATA[i].limitType == limitType) {	
			if (LIMIT_DATA[i].upperVal > maxLimit) {
				maxLimit = LIMIT_DATA[i].upperVal;
			}
		}
	}

	if (maxLimit >= 0) {
		return Math.ceil(maxLimit);
	} else {
		return Math.floor(maxLimit);
	}
}


//
// Weight and Balance chart rendering functions
//

// Draws the initial state of the chart, reading from the
// LIMIT_DATA array
var WB_MARGIN_X = 0;
var WB_MARGIN_Y = 0;
var WB_SCALE_X = 0;
var WB_SCALE_Y = 0;
var WB_MIN_X = 0;
var WB_MIN_Y = 0;

function renderWBChart() {
	var g = new jsGraphics("wbchart");	
	g.setPrintable(true);
	g.setFont("courier", "5px", Font.PLAIN);

	var canvasWidth = 300;
	var canvasHeight = 300;

	var marginX = 30;
	var marginY = 30;

	// Figure out our min and max scale
	var minY = getLowestLimit('LONG');
	var maxY = getHighestLimit('LONG');
	var linesY = (maxY - minY) * 2 + 2; // * 2 because we do half steps, +2 to draw X scale
	var lineDistanceY = (canvasHeight - marginY) / linesY;

	var minX = getLowestLimit('LAT');
	var maxX = getHighestLimit('LAT');
	//alert("Max: " + maxX + " Min: " + minX);
	var linesX = (maxX - minX) * 2 + 2; // * 2 because we do half steps, +2 to draw Y scale
	var lineDistanceX = (canvasWidth - marginX) / linesX;
	
	WB_MARGIN_X = 30;
	WB_MARGIN_Y = 30;
	WB_SCALE_X = lineDistanceX * 2;
	WB_SCALE_Y = lineDistanceY * 2;
	WB_MIN_X = minX;
	WB_MIN_Y = minY - .5;

	// Draw Y lines starting from the top and moving down	
	var currY = 0;
	var currYVal = Math.round(minY);
	for (var i=0; i < linesY; i++) {
		g.drawLine(marginX, currY, canvasWidth - lineDistanceX, currY);
		
		if (i % 2 == 0) {
			g.drawString(currYVal, 0, currY + lineDistanceY - 7);
			currYVal++;
		}		

		currY += lineDistanceY;
	}

	// Draw X lines starting from left and going right
	var currX = marginX;
	var currXVal = minX;
	for (var i=0; i < linesX; i++) {
		var lineHeight = canvasHeight - 20;
		if (i % 2 == 0) {
			var xShift = 4;
			if (currXVal < 0) {
				xShift = 12;
			}
			g.drawString(currXVal, currX - xShift, canvasHeight - 40);
			currXVal++;			
		} else {
			// Don't draw .5 lines
			lineHeight = canvasHeight - 20 - lineDistanceY;
		}

		// Override alternating line heights
		lineHeight = canvasHeight - 50;
		g.drawLine(currX, 0, currX, lineHeight);
		currX += lineDistanceX;
		
	}

	// Draw limit lines
	// Connect the lowest limit and the upper limit
	// connect the lower values and the upper values
	// forms a polygon of boundaries
	//
	// Move backward through our limits until we hit a longitudinal one
	g.setColor("#000000");
	g.setStroke(3);

	var polyidx = 0;
	// Connecting lower values
	for (var i=LIMIT_DATA.length - 1; i > 1; i--) {
		if (LIMIT_DATA[i].limitType == 'LONG') {
			break;
		}
		var x1 = getRealXCoord(LIMIT_DATA[i].lowerVal);
		var y1 = getRealYCoord(LIMIT_DATA[i].appliesAt);
		var x2 = getRealXCoord(LIMIT_DATA[i-1].lowerVal);
		var y2 = getRealYCoord(LIMIT_DATA[i-1].appliesAt);	

		g.drawLine(x1, y1, x2,y2);
	}

	// Connect max limits
	var maxAppliesAt = getMaxAppliesAt();
	var x1 = getRealXCoord(getLimit('LAT', 'lower', maxAppliesAt));
	var x2 = getRealXCoord(getLimit('LAT', 'upper', maxAppliesAt));
	var y1 = getRealYCoord(maxAppliesAt);
	var y2 = getRealYCoord(maxAppliesAt);	
	g.drawLine(x1, y1, x2, y2);

	// Connecting upper values
	for (var i=LIMIT_DATA.length - 1; i > 1; i--) {
		if (LIMIT_DATA[i].limitType == 'LONG') {
			break;
		}
		var x1 = getRealXCoord(LIMIT_DATA[i].upperVal);
		var y1 = getRealYCoord(LIMIT_DATA[i].appliesAt);
		var x2 = getRealXCoord(LIMIT_DATA[i-1].upperVal);
		var y2 = getRealYCoord(LIMIT_DATA[i-1].appliesAt);		

		g.drawLine(x1, y1, x2, y2);
	}    

	// Connect min limits
	var minAppliesAt = getMinAppliesAt();	
	var x1 = getRealXCoord(getLimit('LAT', 'lower', minAppliesAt));
	var x2 = getRealXCoord(getLimit('LAT', 'upper', minAppliesAt));	
	var y1 = getRealYCoord(minAppliesAt);
	var y2 = getRealYCoord(minAppliesAt);	
	g.drawLine(x1, y1, x2, y2);	
    
	g.paint();
}

function getRealXCoord(coord) {
	var realCoord = coord;
	coord -= WB_MIN_X;
	coord *= WB_SCALE_X;
	coord += WB_MARGIN_X;

	return coord;
}

function getRealYCoord(coord) {
	var realCoord = coord;
	coord -= WB_MIN_Y;
	coord *= WB_SCALE_Y;
	
	return coord;
}

/* inPoly()
Finds if a given point is within a polygon.

Based on Bob Stein's inpoly() function for C.
http://home.earthlink.net/~bobstein/inpoly/

Modified for JavaScript by Scott Andrew LePera.

Parameters:
poly: array containing x/y coordinate pairs that
  describe the vertices of the polygon. Format is
  indentical to that of HTML image maps, i.e. [x1,y1,x2,y2,...]
  
px: the x-coordinate of the target point.

py: the y-coordinate of the target point.

Return value:
true if the point is within the polygon, false if not.
*/

function inPoly(poly,px,py)
{
     var npoints = poly.length; // number of points in polygon
     var xnew,ynew,xold,yold,x1,y1,x2,y2,i;
     var inside=false;	 

     if (npoints/2 < 3) { // points don't describe a polygon
          return false;
     }
     xold=poly[npoints-2];
     yold=poly[npoints-1];
     
     for (i=0 ; i < npoints ; i=i+2) {
          xnew=poly[i];
          ynew=poly[i+1];
          if (xnew > xold) {
               x1=xold;
               x2=xnew;
               y1=yold;
               y2=ynew;
          }
          else {
               x1=xnew;
               x2=xold;
               y1=ynew;
               y2=yold;
          }
          if ((xnew < px) == (px <= xold) && ((py-y1)*(x2-x1) < (y2-y1)*(px-x1))) {
               inside=!inside;
          }
          xold=xnew;
          yold=ynew;
     }
	 
     return inside;
}

