// Resizeable box to select all bricks inside a volume.
// -------------------------------------------------------------------

//Create a new selection box
function ND_SelectionBox(%shapeName)
{
	ND_ServerGroup.add(
		%this = new ScriptObject(ND_SelectionBox)
	);

	%this.innerBox = new StaticShape(){datablock = ND_SelectionBoxInner;};
	%this.outerBox = new StaticShape(){datablock = ND_SelectionBoxOuter;};
	%this.shapeName = new StaticShape(){datablock = ND_SelectionBoxShapeName;};

	%this.corner1 = new StaticShape(){datablock = ND_SelectionBoxOuter;};
	%this.corner2 = new StaticShape(){datablock = ND_SelectionBoxOuter;};
	%this.selectedCorner = true;

	%this.innerBox.setScopeAlways();
	%this.outerBox.setScopeAlways();
	%this.shapeName.setScopeAlways();
	%this.corner1.setScopeAlways();
	%this.corner2.setScopeAlways();

	for(%i = 0; %i < 4; %i++)
	{
		%this.border_x[%i] = new StaticShape(){datablock = ND_SelectionBoxBorder;};
		%this.border_y[%i] = new StaticShape(){datablock = ND_SelectionBoxBorder;};
		%this.border_z[%i] = new StaticShape(){datablock = ND_SelectionBoxBorder;};

		%this.border_x[%i].setScopeAlways();
		%this.border_y[%i].setScopeAlways();
		%this.border_z[%i].setScopeAlways();
	}

	%this.boxName = %shapeName;
	%this.setNormalMode();

	return %this;
}

//Destroy static shapes when selection box is removed
function ND_SelectionBox::onRemove(%this)
{
	%this.innerBox.delete();
	%this.outerBox.delete();
	%this.shapeName.delete();

	%this.corner1.delete();
	%this.corner2.delete();

	for(%i = 0; %i < 4; %i++)
	{
		%this.border_x[%i].delete();
		%this.border_y[%i].delete();
		%this.border_z[%i].delete();
	}
}

//Set normal color values and borders
function ND_SelectionBox::setNormalMode(%this)
{
	%this.innerColor  = "0 0 0 0.60";
	%this.outerColor  = "0 0 0 0.35";

	%this.borderColor = "1 0.84 0 0.99";
	%this.borderColorSelected = "0 0 1 0.99";

	%this.cornerColor1 = "0.8 0.74 0 0.99";
	%this.cornerColor2 = "1 0.94 0.1 0.99";

	%this.cornerColorSelected1 = "0 0.2 1 0.99";
	%this.cornerColorSelected2 = "0 0.1 0.9 0.99";

	%this.isNormalMode = true;

	//Unhide the corners and inner/outer box (hidden in disabled mode)
	%this.innerBox.unHideNode("ALL");
	%this.corner1.unHideNode("ALL");
	%this.corner2.unHideNode("ALL");

	if(%this.hasVolume())
		%this.outerBox.unHideNode("ALL");

	//Apply changes
	%this.applyColors();
	%this.setSize(%this.point1, %this.point2);
	%this.shapeName.setShapeName(%this.boxName);
}

//Set grayscale color values and slightly smaller border
function ND_SelectionBox::setDisabledMode(%this)
{
	%this.borderColor = "0.1 0.1 0.1 0.4";
	%this.borderColorSelected = "0.1 0.1 0.1 0.4";

	%this.isNormalMode = false;

	//Hide the corners and inner/outer box (looks better)
	%this.innerBox.hideNode("ALL");
	%this.outerBox.hideNode("ALL");
	%this.corner1.hideNode("ALL");
	%this.corner2.hideNode("ALL");

	//Apply changes
	%this.applyColors();
	%this.setSize(%this.point1, %this.point2);
	%this.shapeName.setShapeName("");
}

//Apply color changes to the selection box
function ND_SelectionBox::applyColors(%this)
{
	%this.innerBox.setNodeColor("ALL", %this.innerColor);
	%this.outerBox.setNodeColor("ALL", %this.outerColor);

	%this.shapeName.setShapeNameColor(%this.borderColor);

	for(%i = 0; %i < 4; %i++)
	{
		%this.border_x[%i].setNodeColor("ALL", %this.borderColor);
		%this.border_y[%i].setNodeColor("ALL", %this.borderColor);
		%this.border_z[%i].setNodeColor("ALL", %this.borderColor);
	}

	%bColor = %this.borderColorSelected;

	if(%this.selectedCorner)
	{
		%this.border_x2.setNodeColor("ALL", %bColor);
		%this.border_y2.setNodeColor("ALL", %bColor);
		%this.border_z2.setNodeColor("ALL", %bColor);

		%corner1 = %this.corner1;
		%corner2 = %this.corner2;
	}
	else
	{
		%this.border_x0.setNodeColor("ALL", %bColor);
		%this.border_y0.setNodeColor("ALL", %bColor);
		%this.border_z0.setNodeColor("ALL", %bColor);

		%corner1 = %this.corner2;
		%corner2 = %this.corner1;
	}

	%corner1.setNodeColor("out+X", %this.borderColor);
	%corner1.setNodeColor("out-X", %this.borderColor);
	%corner1.setNodeColor("out+Y", %this.cornerColor1);
	%corner1.setNodeColor("out-Y", %this.cornerColor1);
	%corner1.setNodeColor("out+Z", %this.cornerColor2);
	%corner1.setNodeColor("out-Z", %this.cornerColor2);

	//Illusion of shaded box
	%corner2.setNodeColor("out+X", %this.borderColorSelected);
	%corner2.setNodeColor("out-X", %this.borderColorSelected);
	%corner2.setNodeColor("out+Y", %this.cornerColorSelected1);
	%corner2.setNodeColor("out-Y", %this.cornerColorSelected1);
	%corner2.setNodeColor("out+Z", %this.cornerColorSelected2);
	%corner2.setNodeColor("out-Z", %this.cornerColorSelected2);
}

//Return current size of selection box
function ND_SelectionBox::getSize(%this)
{
	%x1 = getWord(%this.point1, 0);
	%y1 = getWord(%this.point1, 1);
	%z1 = getWord(%this.point1, 2);

	%x2 = getWord(%this.point2, 0);
	%y2 = getWord(%this.point2, 1);
	%z2 = getWord(%this.point2, 2);

	%min = getMin(%x1, %x2) SPC getMin(%y1, %y2) SPC getMin(%z1, %z2);
	%max = getMax(%x1, %x2) SPC getMax(%y1, %y2) SPC getMax(%z1, %z2);

	return vectorSub(%max, %min);
}

//Return current world box of selection box
function ND_SelectionBox::getWorldBox(%this)
{
	%x1 = getWord(%this.point1, 0);
	%y1 = getWord(%this.point1, 1);
	%z1 = getWord(%this.point1, 2);

	%x2 = getWord(%this.point2, 0);
	%y2 = getWord(%this.point2, 1);
	%z2 = getWord(%this.point2, 2);

	%min = getMin(%x1, %x2) SPC getMin(%y1, %y2) SPC getMin(%z1, %z2);
	%max = getMax(%x1, %x2) SPC getMax(%y1, %y2) SPC getMax(%z1, %z2);

	return %min SPC %max;
}

//Resize the selection box
function ND_SelectionBox::setSize(%this, %point1, %point2)
{
	if(getWordCount(%point1) == 6)
	{
		%point2 = getWords(%point1, 3, 5);
		%point1 = getWords(%point1, 0, 2);
	}

	%this.point1 = %point1;
	%this.point2 = %point2;

	%x1 = getWord(%point1, 0);
	%y1 = getWord(%point1, 1);
	%z1 = getWord(%point1, 2);

	%x2 = getWord(%point2, 0);
	%y2 = getWord(%point2, 1);
	%z2 = getWord(%point2, 2);

	%len_x = mAbs(%x2 - %x1);
	%len_y = mAbs(%y2 - %y1);
	%len_z = mAbs(%z2 - %z1);

	%center_x = (%x1 + %x2) / 2;
	%center_y = (%y1 + %y2) / 2;
	%center_z = (%z1 + %z2) / 2;

	%rot_x = "0 1 0 1.57079";
	%rot_y = "1 0 0 1.57079";
	%rot_z = "0 0 1 0";

	%this.innerBox.setTransform(%center_x SPC %center_y SPC %center_z);
	%this.outerBox.setTransform(%center_x SPC %center_y SPC %center_z);
	%this.shapeName.setTransform(%center_X SPC %center_y SPC %z2);

	%this.border_x0.setTransform(%center_x SPC %y1 SPC %z1 SPC %rot_x);
	%this.border_x1.setTransform(%center_x SPC %y2 SPC %z1 SPC %rot_x);
	%this.border_x2.setTransform(%center_x SPC %y2 SPC %z2 SPC %rot_x);
	%this.border_x3.setTransform(%center_x SPC %y1 SPC %z2 SPC %rot_x);

	%this.border_y0.setTransform(%x1 SPC %center_y SPC %z1 SPC %rot_y);
	%this.border_y1.setTransform(%x2 SPC %center_y SPC %z1 SPC %rot_y);
	%this.border_y2.setTransform(%x2 SPC %center_y SPC %z2 SPC %rot_y);
	%this.border_y3.setTransform(%x1 SPC %center_y SPC %z2 SPC %rot_y);

	%this.border_z0.setTransform(%x1 SPC %y1 SPC %center_z SPC %rot_z);
	%this.border_z1.setTransform(%x2 SPC %y1 SPC %center_z SPC %rot_z);
	%this.border_z2.setTransform(%x2 SPC %y2 SPC %center_z SPC %rot_z);
	%this.border_z3.setTransform(%x1 SPC %y2 SPC %center_z SPC %rot_z);

	%this.corner1.setTransform(%x1 SPC %y1 SPC %z1);
	%this.corner2.setTransform(%x2 SPC %y2 SPC %z2);

	%this.innerBox.setScale(%len_x - 0.02 SPC %len_y - 0.02 SPC %len_z - 0.02);
	%this.outerBox.setScale(%len_x + 0.02 SPC %len_y + 0.02 SPC %len_z + 0.02);

	if(%this.isNormalMode)
	{
		//Normal mode (box with two colored corners)
		%maxLen = getMax(getMax(%len_x, %len_y), %len_z);
		%width = (7/1024) * %maxLen + 1;

		for(%i = 0; %i < 4; %i++)
		{
			%this.border_x[%i].setScale(%width SPC %width SPC %len_x + %width * 0.05);
			%this.border_y[%i].setScale(%width SPC %width SPC %len_y + %width * 0.05);
			%this.border_z[%i].setScale(%width SPC %width SPC %len_z + %width * 0.05);
		}

		if(%this.selectedCorner)
		{
			%width1 = %width;
			%width2 = %width + 0.02;
		}
		else
		{
			%width1 = %width + 0.02;
			%width2 = %width;
		}

		//The borders touching the two corners are thicker to prevent Z fighting
		//with the highlight box if it covers the same area as the selection
		%this.border_x0.setScale(%width1 SPC %width1 SPC %len_x - %width * 0.05);
		%this.border_y0.setScale(%width1 SPC %width1 SPC %len_y - %width * 0.05);
		%this.border_z0.setScale(%width1 SPC %width1 SPC %len_z - %width * 0.05);

		%this.border_x2.setScale(%width2 SPC %width2 SPC %len_x - %width * 0.05);
		%this.border_y2.setScale(%width2 SPC %width2 SPC %len_y - %width * 0.05);
		%this.border_z2.setScale(%width2 SPC %width2 SPC %len_z - %width * 0.05);

		//Corners scale with the border width
		%cs1 = 0.35 * %width1;
		%cs2 = 0.35 * %width2;

		%this.corner1.setScale(%cs1 SPC %cs1 SPC %cs1);
		%this.corner2.setScale(%cs2 SPC %cs2 SPC %cs2);
	}
	else
	{
		//Disabled mode (transparent greyscale box)
		%maxLen = getMax(getMax(%len_x, %len_y), %len_z);
		%width = (21/5120) * %maxLen + 1;

		for(%i = 0; %i < 4; %i++)
		{
			//Horizontal borders are a bit shorter to prevent z fighting
			%this.border_x[%i].setScale(%width SPC %width SPC %len_x - %width * 0.05);
			%this.border_y[%i].setScale(%width SPC %width SPC %len_y - %width * 0.05);

			%this.border_z[%i].setScale(%width SPC %width SPC %len_z + %width * 0.05);
		}
	}
}

//Resize the selection box and align it to a player
function ND_SelectionBox::setSizeAligned(%this, %point1, %point2, %player)
{
	//Set the selection box to correct orientation
	%x1 = getWord(%point1, 0);
	%y1 = getWord(%point1, 1);
	%z1 = getWord(%point1, 2);

	%x2 = getWord(%point2, 0);
	%y2 = getWord(%point2, 1);
	%z2 = getWord(%point2, 2);

	switch(getAngleIDFromPlayer(%player))
	{
		case 0:
			%p1 = %x1 SPC %y2 SPC %z1;
			%p2 = %x2 SPC %y1 SPC %z2;

		case 1:
			%p1 = %x1 SPC %y1 SPC %z1;
			%p2 = %x2 SPC %y2 SPC %z2;

		case 2:
			%p1 = %x2 SPC %y1 SPC %z1;
			%p2 = %x1 SPC %y2 SPC %z2;

		case 3:
			%p1 = %x2 SPC %y2 SPC %z1;
			%p2 = %x1 SPC %y1 SPC %z2;
	}

	//Select first corner
	if(!%this.selectedCorner)
	{
		%this.selectedCorner = true;
		%this.applyColors();
	}

	%this.setSize(%p1, %p2);
}

//Select one of the two corners
function ND_SelectionBox::switchCorner(%this)
{
	%this.selectedCorner = !%this.selectedCorner;

	if(%this.selectedCorner)
		serverPlay3d(BrickRotateSound, %this.point2);
	else
		serverPlay3d(BrickRotateSound, %this.point1);

	%this.setSize(%this.point1, %this.point2);
	%this.applyColors();
}

//Move the selected corner
function ND_SelectionBox::shiftCorner(%this, %offset, %limit)
{
	%oldP1 = %this.point1;
	%oldP2 = %this.point2;
	%limitReached = false;

	//Size of a plate in TU
	%unit[0] = 0.5;
	%unit[1] = 0.5;
	%unit[2] = 0.2;

	for(%dim = 0; %dim < 3; %dim++)
	{
		//Copy current
		%point1[%dim] = getWord(%this.point1, %dim);
		%point2[%dim] = getWord(%this.point2, %dim);

		//Get the size of the box in the current axis after resizing
		%size = getWord(%this.point2, %dim) - getWord(%this.point1, %dim);

		if(%this.selectedCorner)
		{
			//Update point2
			%size += getWord(%offset, %dim);
			%point2[%dim] += getWord(%offset, %dim);

			//Check limits
			if(mAbs(%size) > %limit)
			{
				%limitReached = true;
				%point2[%dim] -= %size - %limit * (mAbs(%size) / %size);
			}
		}
		else
		{
			//Update point1
			%size -= getWord(%offset, %dim);
			%point1[%dim] += getWord(%offset, %dim);

			//Check limits
			if(mAbs(%size) > %limit)
			{
				%limitReached = true;
				%point1[%dim] += %size - %limit * (mAbs(%size) / %size);
			}
		}
	}

	//Update corner positions
	%point1 = %point1[0] SPC %point1[1] SPC %point1[2];
	%point2 = %point2[0] SPC %point2[1] SPC %point2[2];
	%this.setSize(%point1, %point2);

	//Play sounds
	if(%this.selectedCorner)
		%soundPoint = %point2;
	else
		%soundPoint = %point1;

	if(%point1 !$= %oldP1 || %point2 !$= %oldP2)
		serverPlay3d(BrickMoveSound, %soundPoint);
	else
		serverPlay3d(errorSound, %soundPoint);

	//Hide outer box on selection boxes without volume
	if(%this.hasVolume())
		%this.outerBox.unHideNode("ALL");
	else
		%this.outerBox.hideNode("ALL");

	return %limitReached;
}

//Move the entire box
function ND_SelectionBox::shift(%this, %offset)
{
	%this.point1 = vectorAdd(%this.point1, %offset);
	%this.point2 = vectorAdd(%this.point2, %offset);

	%this.setSize(%this.point1, %this.point2);

	//Play sounds
	if(%this.selectedCorner)
		serverPlay3d(BrickMoveSound, %this.point1);
	else
		serverPlay3d(BrickMoveSound, %this.point2);
}

//Rotate the entire box
function ND_SelectionBox::rotate(%this, %direction)
{
	%point1 = %this.point1;
	%point2 = %this.point2;
	%center = vectorScale(vectorAdd(%point1, %point2), 0.5);

	%brickSizeX = mAbs(mFloatLength((getWord(%point2, 0) - getWord(%point1, 0)) * 2, 0));
	%brickSizeY = mAbs(mFloatLength((getWord(%point2, 1) - getWord(%point1, 1)) * 2, 0));

	%shiftCorrect = "0 0 0";

	if((%brickSizeX % 2) != (%brickSizeY % 2))
	{
		if(%brickSizeX % 2)
			%shiftCorrect = "-0.25 -0.25 0";
		else
			%shiftCorrect = "0.25 0.25 0";
	}

	%point1 = vectorAdd(ndRotateVector(vectorSub(%point1, %center), %direction), %center);
	%point2 = vectorAdd(ndRotateVector(vectorSub(%point2, %center), %direction), %center);
	%this.setSize(vectorAdd(%point1, %shiftCorrect), vectorAdd(%point2, %shiftCorrect));

	//Play sounds
	if(%this.selectedCorner)
		serverPlay3d(BrickRotateSound, %this.point1);
	else
		serverPlay3d(BrickRotateSound, %this.point2);
}

//Check if the box has a volume
function ND_SelectionBox::hasVolume(%this)
{
	if(mAbs(getWord(%this.point1, 0) - getWord(%this.point2, 0)) < 0.05
	|| mAbs(getWord(%this.point1, 1) - getWord(%this.point2, 1)) < 0.05
	|| mAbs(getWord(%this.point1, 2) - getWord(%this.point2, 2)) < 0.05)
		return false;

	return true;
}