#include "BoundingBox.h"

namespace cbk
{
	BoundingBox::BoundingBox(const Vector& one, const Vector& two)
	{
		setBoundaries(one, two);
	}

	void BoundingBox::adjust(void)
	{
		Vector t1;

		t1.X = max(one.X, two.X);
		t1.Y = max(one.Y, two.Y);
		t1.Z = max(one.Z, two.Z);

		one.X = min(one.X, two.X);
		one.Y = min(one.Y, two.Y);
		one.Z = min(one.Z, two.Z);

		two.X = t1.X;
		two.Y = t1.Y;
		two.Z = t1.Z;
	}

	BoundingBox BoundingBox::operator*(const float& scale) const
	{
		return BoundingBox(one * scale, two * scale);
	}

	BoundingBox BoundingBox::operator+(const Vector& translation) const
	{
		return BoundingBox(one + translation, two + translation);
	}

	const bool BoundingBox::operator==(const BoundingBox& other) const
	{
		return ((one == other.one) && (two == other.two));
	}

	const bool BoundingBox::operator!=(const BoundingBox& other) const
	{
		return ((one != other.one) || (two != other.two));
	}

	const bool BoundingBox::operator==(const Vector& other) const
	{
		return ((other.X >= one.X) && (other.X <= two.X)
			&&  (other.Y >= one.Y) && (other.Y <= two.Y)
			&&  (other.Z >= one.Z) && (other.Z <= two.Z));
	}

	const bool BoundingBox::collides(const BoundingBox& other) const
	{
		return ((one.X < other.two.X) && (two.X > other.one.X)
			&&  (one.Y < other.two.Y) && (two.Y > other.one.Y)
			&&  (one.Z < other.two.Z) && (two.Z > other.one.Z));
	}

	const bool BoundingBox::collides(const Vector& other) const
	{
		return ((other.X >= one.X) && (other.X <= two.X)
			&&  (other.Y >= one.Y) && (other.Y <= two.Y)
			&&  (other.Z >= one.Z) && (other.Z <= two.Z));
	}

	const bool BoundingBox::collides(const BoundingBox& other, const float& tScale, const float& oScale) const
	{
		const Vector tOne(one.X * tScale, one.Y * tScale, one.Z * tScale);
		const Vector tTwo(two.X * tScale, two.Y * tScale, two.Z * tScale);
		const Vector oOne(other.one.X * oScale, other.one.Y * oScale, other.one.Z * oScale);
		const Vector oTwo(other.two.X * oScale, other.two.Y * oScale, other.two.Z * oScale);

		return ((tOne.X < oTwo.X) && (tTwo.X > oOne.X)
			&&  (tOne.Y < oTwo.Y) && (tTwo.Y > oOne.Y)
			&&  (tOne.Z < oTwo.Z) && (tTwo.Z > oOne.Z));
	}

	const bool BoundingBox::collides(const Vector& other, const float& scale) const
	{
		const Vector tOne(one.X * scale, one.Y * scale, one.Z * scale);
		const Vector tTwo(two.X * scale, two.Y * scale, two.Z * scale);

		return ((other.X >= tOne.X) && (other.X <= tTwo.X)
			&&  (other.Y >= tOne.Y) && (other.Y <= tTwo.Y)
			&&  (other.Z >= tOne.Z) && (other.Z <= tTwo.Z));
	}

	const Vector& BoundingBox::getLesser(void) const
	{
		return one;
	}

	const Vector& BoundingBox::getGreater(void) const
	{
		return two;
	}

	BoundingBox& BoundingBox::setBoundaries(const Vector& one, const Vector& two)
	{
		this->one = one;
		this->two = two;
		adjust();

		return *this;
	}

	const Vector BoundingBox::getCenter(void) const
	{
		Vector t;
		t.X = (one.X + two.X) / 2.0f;
		t.Y = (one.Y + two.Y) / 2.0f;
		t.Z = (one.Z + two.Z) / 2.0f;

		return t;
	}

	void BoundingBox::draw(IDirect3DDevice9* device) const
	{
		float verts[24];
		INT32 index[84];

		//0
		verts[ 0] = one.X;
		verts[ 1] = one.Y;
		verts[ 2] = one.Z;

		//1
		verts[ 3] = two.X;
		verts[ 4] = one.Y;
		verts[ 5] = one.Z;

		//2
		verts[ 6] = one.X;
		verts[ 7] = two.Y;
		verts[ 8] = one.Z;

		//3
		verts[ 9] = two.X;
		verts[10] = two.Y;
		verts[11] = one.Z;

		//4
		verts[12] = one.X;
		verts[13] = one.Y;
		verts[14] = two.Z;

		//5
		verts[15] = two.X;
		verts[16] = one.Y;
		verts[17] = two.Z;

		//6
		verts[18] = one.X;
		verts[19] = two.Y;
		verts[20] = two.Z;

		//7
		verts[21] = two.X;
		verts[22] = two.Y;
		verts[23] = two.Z;


		index[ 0] = 0;
		index[ 1] = 2;
		index[ 2] = 1;

		index[ 3] = 2;
		index[ 4] = 3;
		index[ 5] = 1;

		index[ 6] = 1;
		index[ 7] = 5;
		index[ 8] = 4;

		index[ 9] = 4;
		index[10] = 0;
		index[11] = 1;

		index[12] = 3;
		index[13] = 2;
		index[14] = 6;

		index[15] = 6;
		index[16] = 7;
		index[17] = 3;

		index[18] = 4;
		index[19] = 5;
		index[20] = 6;

		index[21] = 5;
		index[22] = 7;
		index[23] = 6;

		index[24] = 1;
		index[25] = 3;
		index[26] = 5;

		index[27] = 5;
		index[28] = 3;
		index[29] = 7;

		index[30] = 0;
		index[31] = 4;
		index[32] = 2;

		index[33] = 4;
		index[34] = 6;
		index[35] = 2;

		device->SetFVF(D3DFVF_XYZ);
		device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
		device->SetRenderState(D3DRS_LIGHTING, false);
		device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
		device->SetTexture(0, 0);

		device->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 8, 12, index, D3DFMT_INDEX32, verts, sizeof(float) * 3);

		device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
		device->SetRenderState(D3DRS_LIGHTING, true);
		device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
	}
}