#include "MW4Headers.hpp"
#include <stdio.h>
#include "adept\application.hpp"
#include "rail_move.hpp"
//#include "quadedge.h"
#include <MW4\MWMission.hpp>
#include <Adept\Map.hpp>
#include <Adept\CollisionGrid.hpp>
#include <ElementRenderer\StateChange.hpp>
#include <adept\collisionvolume.hpp>
#include "path.hpp"
#include "bridge.hpp"
#include "cultural.hpp"
#include "mwplayer.hpp"
#include "move_rect.hpp"

#pragma warning (push)
#include <vector>
#include <map>
#pragma warning (pop)

using namespace MW4AI;
using namespace MechWarrior4;
using namespace ElementRenderer;

#define BADSLOPE 0.707f
#define CELLSIZE 10

void ConvertMoveRectToZeroCenter (const char *filename,Stuff::Scalar xoffset,Stuff::Scalar zoffset)
{
	if (!filename)
		return;

	DWORD *file;
	DWORD filesize;
	DWORD *data;
	int numrects,i;
	struct TRect
	{
		Scalar left,right,top,bottom;
		int building;
		bool vertical;
	};
	TRect *rects;

	gos_GetFile (filename,(unsigned char **) &file,&filesize);
	data = file;
	numrects = *((int*) data);
	data++;
	rects = (TRect *) data;

	Stuff::FileStream stream(filename,Stuff::FileStream::WriteOnly);
	stream << numrects;

	for (i=0;i<numrects;i++)
	{
		rects->bottom += zoffset;
		rects->top += zoffset;
		rects->left += xoffset;
		rects->right += xoffset;
		stream.WriteBytes (rects,sizeof (TRect));
		rects++;
	}

	gos_Free (file);
}

CMoveRectList::CMoveRectList (void)
{
	m_Rects.clear ();
}

CMoveRectList::CMoveRectList (Stuff::MemoryStream *stream)
{
	int numrects,i;

	AutoHeap local_heap (g_RailHeap);
	m_Rects.clear ();
	*stream >> numrects;

	for (i=0;i<numrects;i++)
	{
		OBRect rect;
		stream->ReadBytes (&rect,sizeof (OBRect));
		rect.vertical = true;
		m_Rects.push_back (rect);
	}
}

CMoveRectList::~CMoveRectList (void)
{
}

void CMoveRectList::AddBuildingData (void)
{
// MSL 5.05 Added turretarray to list
	int tablescan[] =
	{
		NameTable::BuildingArray,
		NameTable::TurretArray,
		NameTable::VehicleArray
	};
	int size,i,j;
	NameTable *table = NameTable::GetInstance();
	Check_Object (table);
	AutoHeap local_heap (g_RailHeap);
	for (i=0;i<sizeof (tablescan)/sizeof (int);i++)
	{
		size = table->nameTableArray[tablescan[i]].GetLength ();
		for (j=0;j<size;j++)
		{
			NameTableEntry *data;
			Entity *who;
	
			data = &table->nameTableArray [tablescan[i]][j];
	
			if (!strnicmp (data->objectName,"water",5))
			{
				continue;
			}
	
			who = data->dataPointer->GetCurrent ();
	
			if (!who)
				continue;
			if ((!who->GetHierarchicalVolume ()) && (!who->GetSolidVolume ()))
				continue;
			if (!who->IsDerivedFrom (Bridge::DefaultData))
				continue;
			if (!who->IsDerivedFrom (Cultural::DefaultData))
			{
				MWObject *obj;
				obj = Cast_Object (MWObject *,who);
				if ((obj->GetAI ()) && (tablescan[i] != NameTable::BuildingArray))
					continue;
			}
			else
				continue;
	
			OBB *obb;
			CollisionVolume *col;
			col = who->GetHierarchicalVolume ();
			if (!col)
				col = who->GetSolidVolume ();
			OBB world_bounds;
			world_bounds.Multiply(col->m_localSpaceBounds, who->GetLocalToWorld());
			obb = &(world_bounds);
			ExtentBox box (*obb);
			Point3D loc = (Point3D) obb->localToParent;
	
			OBRect rect (box.minX,box.minZ,box.maxX,box.maxZ,data->GetObjectID (),((box.maxX - box.minX) < (box.maxZ-box.minZ)));
			m_Rects.push_back (rect);
		}
	}
}

void CMoveRectList::Create (WorkCallBack callback)
{
	AddBuildingData ();
//	DumpFile ();
}

void CMoveRectList::SaveFile (const char *filename)
{

	Stuff::FileStream stream(filename,Stuff::FileStream::WriteOnly);

	stream << m_Rects.size ();

	stlport::vector<OBRect>::iterator iter;
	iter = m_Rects.begin ();
	while (iter != m_Rects.end ())
	{
		stream.WriteBytes (&(*iter),sizeof (OBRect));
		iter++;
	}
}

void CMoveRectList::ConstructStream (Stuff::MemoryStream *stream,const char *filename)
{
	DWORD *file;
	DWORD filesize;
	DWORD *data;
	int numrects;

	if (filename)
	{
		gos_GetFile (filename,(unsigned char **) &file,&filesize);
		data = file;
		numrects = *((int*) data);
		data++;
		*stream << (numrects);				// width			negative for new style
		filesize -= sizeof (int);
		if (filesize)
			stream->WriteBytes (data,filesize);
		gos_Free (file);
	}
	else
	{
		*stream << (DWORD) 0;			// for number of rects
	}
}

void CMoveRectList::DumpFile (void)
{
	FILE *file;

	file = fopen ("f:\\fred.out","w");

	stlport::vector<OBRect>::iterator iter;
	iter = m_Rects.begin ();
	while (iter != m_Rects.end ())
	{
		fprintf (file,"%d,%d %d,%d\n",iter->left,iter->top,iter->right,iter->bottom);
		iter++;
	}
	fclose (file);
}


const OBRect *CMoveRectList::Collide (const Point3D& start,const Point3D& end) const
{
	stlport::vector<OBRect>::const_iterator iter;
	for (iter = m_Rects.begin ();iter != m_Rects.end ();iter++)
	{
		Scalar t,x,z;

		if (iter->vertical)
		{
			if (end.z == start.z)			
				continue;
			t = (iter->top - start.z) / (end.z - start.z);
			if ((t>=0.0f) && (t<=1.0f))
			{
				x = start.x + ((end.x - start.x)*t);
				if ((x >= iter->left) && (x <= iter->right))
					return &(*iter);
			}

			t = (iter->bottom - start.z) / (end.z - start.z);
			if ((t>=0.0f) && (t<=1.0f))
			{
				x = start.x + ((end.x - start.x)*t);
				if ((x >= iter->left) && (x <= iter->right))
					return &(*iter);
			}
		}
		else
		{
			if (end.x == start.x)
				continue;
			t = (iter->left - start.x) / (end.x - start.x);
			if ((t>=0.0f) && (t<=1.0f))
			{
				z = start.z + ((end.z - start.z)*t);
				if ((z >= iter->top) && (z <= iter->bottom))
					return &(*iter);
			}
			
			t = (iter->right - start.x) / (end.x - start.x);
			if ((t>=0.0f) && (t<=1.0f))
			{
				z = start.z + ((end.z - start.z)*t);
				if ((z >= iter->top) && (z <= iter->bottom))
					return &(*iter);
			}
		}
	}

	return NULL;
}

bool CMoveRectList::RectWithin (Stuff::Point3D& pt,Stuff::Scalar dist)
{
	stlport::vector<OBRect>::const_iterator iter;
	iter = m_Rects.begin ();
	Stuff::Scalar value;
	dist *= dist;
	Stuff::Scalar cx,cz;
	while (iter != m_Rects.end ())
	{
		cx = ((iter->right - iter->left)/2.0f) + iter->left;
		cz = ((iter->bottom - iter->top)/2.0f) + iter->top;
		value = (pt.x - cx) * (pt.x - cx);
		value += ((pt.z - cz) * (pt.z - cz));
		if (value < dist)
			return true;
		iter++;
	}
	return false;
}

const OBRect *CMoveRectList::Inside (const Point3D& pt) const
{
	stlport::vector<OBRect>::const_iterator iter;
	iter = m_Rects.begin ();
	while (iter != m_Rects.end ())
	{
		if ((pt.x >= iter->left) && (pt.x <= iter->right))
			if ((pt.z >= iter->top) && (pt.z <= iter->bottom))
				return &(*iter);
		iter++;
	}
	return NULL;
}

void CMoveRectList::BridgeKilled (int id)
{
}
