        ///////////////////////////////////////////////////////////////////////////////
/// @file deApi.cpp
///
/// @brief DestinyEdit API
///
/// @author jwvanderbeck
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Mar 2003
/// @author jwvanderbeck
/// @remarks Creation
///
///////////////////////////////////////////////////////////////////////////////

#define DEAPI_PRIVATE
#define DEAPI_EXPORT
#include "deApi.hpp"

//#include "deApi_Private.hpp"

//
// Access to the overall API manager
deApi& deApi_GetManager()
{
	static deApi g_TheApi;
	return g_TheApi;
}




//
// deApiType
//
// This class provides dynamic runtime type information services for the api
deApiType::deApiType()
{
	m_sName = "";
	m_pParent = NULL;
}
deApiType::deApiType(const deString& sName, deApiType* pParent)
{
	m_sName = sName;
	m_pParent = pParent;
}
deApiType::~deApiType()
{
	m_sName = "";
	m_pParent = NULL;
}
deString& deApiType::GetName()
{
	return m_sName;
}
deString& deApiType::GetParentName()
{
	if (m_pParent)
	{
		return m_pParent->GetName();
	}
	else
		return m_sName;
}
deString& deApiType::GetBaseName()
{
	deApiType* pType = this;

	while(pType->GetParent())
	{
		pType = pType->GetParent();
	}
	return pType->GetName();
}
deApiType* deApiType::GetParent()
{
	return m_pParent;
}
deApiType* deApiType::GetBase()
{
	deApiType* pType = this;

	while(pType->GetParent())
	{
		pType = pType->GetParent();
	}
	return pType;
}
bool deApiType::IsA(const deApiType* pType)
{
	deApiType* pTemp = this;

	while(pTemp)
	{
		if (pTemp == pType)
			return true;

		pTemp = pTemp->GetParent();
	}

	return false;
}
bool deApiType::IsA(const deString& sType)
{
	deApiType* pTemp = this;

	while(pTemp)
	{
		if (pTemp->GetName() == sType)
			return true;

		pTemp = pTemp->GetParent();
	}

	return false;
}

void* deApiType::SafeCast(const deApiType* pCastTo)
{
	// this will safely upcast from a derived type to a base type
	// if the cast is safe, or return null if not.
	if (this->IsA(pCastTo))
	{
		// We are a derived type of the given cast type
		// This means we can simply cast to the given type
		return (void*)this;
	}
	// In this case, we ARE the specified type, so a cast should be safe
	else if (this == pCastTo)
		return (void*)this;
	else
		return NULL;
}
void* deApiType::SafeCast(const deString& sType)
{
	if (this->IsA(sType))
	{
		// We are a derived type of the given cast type
		// This means we can simply cast to the given type
		return (void*)this;
	}
	// In this case, we ARE the specified type, so a cast should be safe
	else if (m_sName == sType)
		return (void*)this;
	else
		return NULL;
}


deApiObject::deApiObject()
{
	bNull = true;
	iReferenceCount = 0;
	//printf("\nIn deApiObject()");
}

deApiObject::~deApiObject()
{
	//printf("\nIn ~deApiObject()");
}

bool deApiObject::IsNull()
{
	return bNull;
}

void deApiObject::DumpObject()
{
}

int deApiObject::GetReferenceCount()
{
	return iReferenceCount;
}

unsigned long deApiObject::GetRuntimeID()
{
	return 0;
}
unsigned long deApiObject::GetGlobalIDPrefix()
{
	return 0;
}
unsigned char deApiObject::GetGlobalID()
{
	return 0;
}
void deApiObject::RemoveReference()
{
	if (iReferenceCount > 0)
		iReferenceCount--;
	//printf("\n::DEBUG:: New Reference Count is %i", iReferenceCount);
}
void deApiObject::AddReference()
{
	iReferenceCount++;
	//printf("\n::DEBUG:: New Reference Count is %i", iReferenceCount);
}

//
// deApiFn_Attribute
//
// Function Set for workign with attributes
//
deApiFn_Attribute::deApiFn_Attribute() 
{ 
	// init pointers
	m_pAttribute = NULL;
}

deApiFn_Attribute::~deApiFn_Attribute() 
{ 
}

deApiHandle deApiFn_Attribute::Create(DataType AttributeType, const deString& sName, const deString& sDescription)
{	
	deApiHandle hHandle;
	switch(AttributeType)
	{
		case DataType::Float:
			{
				// create object
				m_pAttribute = new deApiAttribute_Float;
				hHandle = TheApi.CreateObject(m_pAttribute);
				m_type = DataType::Float;
				return hHandle;
				break;
			}
		default:
			return hHandle;
	}
}

bool deApiFn_Attribute::AddToCollection(deApiObject* pCollection)
{
	if (!pCollection)
		return false;
	if (pCollection->IsNull())
		return false;

//	((deApiAttributeCollection*)pCollection)->AddAttribute(m_pObjectFloat);
	return true;
}

//
// deApiAttribute
//
// Base object for attribute objects.  This should never be created directly.  Use the more
// specific derived attributes
//
deApiAttribute::deApiAttribute()
{
	//printf("\nIn deApiAttribute()");
}

deApiAttribute::~deApiAttribute()
{
	//printf("\nIn ~deApiAttribute()");
}

deApiAttribute::Type deApiAttribute::GetAttributeType()
{
	return Type::Invalid;
}

unsigned long deApiAttribute::GetRuntimeID()
{
	return runtimeID;
}



bool deApi::InitApi(HWND hWindow)
{
	runtimeID = 0;
	m_pNodeTree = new deApiNodeTree;
	m_hWindow = hWindow;
	if (hWindow)
	{
		if (!IsWindow(hWindow))
			return false;
	}
	m_iOutputWindow = 0;
#ifdef _DEBUG
	// in debug build, we create a standard debug output window for messages
	deApiFn_OutputWindow fnWindow;
	deApiHandle hOutputWindow;
	hOutputWindow = fnWindow.Create(0,0,600,200,"API Debug", false, false);
	m_iOutputWindow = hOutputWindow.GetRuntimeID();
#endif
	m_pRender = new deApiRender;
	return true;
}
//
// Output some text to the API's default output window
// This is only active in debug mode
void deApi::DebugOut(const deString& sText)
{
	if (m_iOutputWindow == 0)
		return;

	deApiFn_OutputWindow fnWindow;
	deApiHandle hWindow;
	deApiFn_NodeTree fnTree;
	hWindow = fnTree.GetNode(m_iOutputWindow);
	fnWindow.BindHandle(hWindow);
	fnWindow.AddLogText(sText);
}

unsigned long deApi::GetNextRuntimeID()
{
	runtimeID++;
	return runtimeID;
}
deApiHandle deApi::CreateObject(deApiObject* pObject)
{
	unsigned long newID;
	deApiHandle hHandle;

	newID = m_pNodeTree->AddNode(pObject);
	hHandle = m_pNodeTree->GetNode(newID);
	return hHandle;
}
bool deApi::DestroyObject(unsigned long runtimeID)
{
	return false;
}
//
// Exchange a handle for an object pointer
deApiObject* deApi::GetObjectFromHandle(deApiHandle handle)
{
	unsigned long id = handle.GetRuntimeID();
	deApiObject* pObject = m_pNodeTree->GetApiObject(id);
	return pObject;
}


//
// deApiAttribute_Float
//
// ApiObject for float type attributes
// perhaps make this a real instead and handle both float and double.  Not sure yet.
//
deApiAttribute_Float::deApiAttribute_Float()
{
	//printf("\nIn deApiAttribute_Float()");
	// retrive a runtime ID
	runtimeID = TheApi.GetNextRuntimeID();
}
deApiAttribute_Float::~deApiAttribute_Float()
{
	//printf("\nIn ~deApiAttribute_Float()");
}
deApiAttribute_Float::Type deApiAttribute_Float::GetAttributeType() 
{ 
	return Type::Float; 
}
void deApiAttribute_Float::DumpObject()
{
	//printf("\n::DEBUG::\nDumping data for deApiAttribute_Float\nruntimeID: %i", runtimeID);
}


//
// deApiAttributeCollection
//
// Collection of attributes which is then applied as either the "inputs" or "outputs" for a node.
// A node can only have a single collection for each.
//
deApiAttributeCollection::deApiAttributeCollection()
{
	//printf("\nIn deApiAttributeCollection()");
//	m_NumAttributes = 0;
	bNull = false;
}
deApiAttributeCollection::~deApiAttributeCollection()
{
	//printf("\nIn ~deApiAttributeCollection()");
}

unsigned short deApiAttributeCollection::GetAttributeCount()
{
	return 0;
}
deApiObject* deApiAttributeCollection::GetAttribute(unsigned long runtimeID)
{
	return NULL;
}
void deApiAttributeCollection::DumpObject()
{
	//printf("\n::DEBUG::\nDumping data for deApiAttributeCollection");
//	//printf("\nm_NumAttributes: %i", m_NumAttributes);
	int i;
	//printf("\nDumping runtime IDs of all contained attributes:");
	for (i = 0; i < m_tarrayAttributes.Length(); i++)
	{
		//printf("\n\t%i", m_tarrayAttributes[i]);
	}
}


bool deApiAttributeCollection::IsNull()
{
	return bNull;
}

bool deApiAttributeCollection::AddAttribute(deApiObject* pAttribute)
{
/*	if (m_NumAttributes >= 65535)
		return false;
	if (m_NumAttributes < 0)
		return false;
	
	unsigned long runtimeID = pAttribute->GetRuntimeID();

	if (runtimeID == 0)
		return false;
	
	if (!m_tarrayAttributes.PushBack(runtimeID))
		return false;
	m_NumAttributes++;*/

	return true;
}



//
// deApiHandle
//
// Encapsulates an api object handle, shielding the actual object behind the 
// handle for safety and security
//
// Used to query the handle to see if it is useable with a specified function set
bool deApiHandle::IsA(const deApiType* pType)
{
	deApiObject* pObject = Dereference();
	if (!pObject)
		return false;

	return pObject->Type.IsA(pType);
}
bool deApiHandle::IsA(const deString& sType)
{
	deApiObject* pObject = Dereference();
	if (!pObject)
		return false;

	return pObject->Type.IsA(sType);
}
//
// Does the handle reference a null or invalid api object?
bool deApiHandle::IsNull()
{
	return bNull;
}
//
// Return the underlying object's runtime ID
unsigned long deApiHandle::GetRuntimeID()
{
	deApiObject* pObject = Dereference();
	if (!pObject)
		return 0;

	return runtimeID;
}
//
// Destroy the underlying api object referenced by this handle.
// The object will not be physically destroyed until this and
// all other outstanding handles are released.  This only flags
// it for destruction.
bool deApiHandle::Destroy()
{
	//printf("\nIn ~deApiHandle::Destroy()");
	deApiObject* pObject = Dereference();
	if (!pObject)
		return false;

	pObject->RemoveReference();

	return true;
}
//
// Overloaded assignment operator
deApiHandle& deApiHandle::operator=(deApiHandle& rhs)
{
	//printf("\nIn deApiHandle::operator=()");
	// ok, assignment..
	// We need to increase the underlying object's reference count
	// and duplicate our handle to the new one

	// self assignment
	if (this == &rhs)
	{
		return *this;
	}

	deApiObject* pObject = rhs.Dereference();
	if (pObject)
	{
		bNull = false;
		runtimeID = rhs.runtimeID;
		pObject->AddReference();
	}
	else
	{
		bNull = true;
		runtimeID = rhs.runtimeID;
	}
	return *this;
}
//
// Overloaded copy constructor
deApiHandle::deApiHandle(const deApiHandle& rhs)
{
	//printf("\nIn deApiHandle Copy Constructor");
	// We need to increase the underlying object's reference count
	// and duplicate our handle to the new one

	deApiObject* pObject;// = rhs.Dereference();

	if (rhs.bNull)
		pObject = NULL;
	else
		pObject = TheApi.m_pNodeTree->GetApiObject(rhs.runtimeID);

	if (pObject)
	{
		bNull = false;
		runtimeID = rhs.runtimeID;
		pObject->AddReference();
	}
	else
	{
		bNull = true;
		runtimeID = rhs.runtimeID;
	}
}
//
// Default constructor
deApiHandle::deApiHandle()
{
	//printf("\nIn deApiHandle()");
	bNull = true;
	runtimeID = 0;
}
//
// Default destructor
deApiHandle::~deApiHandle()
{
	//printf("\nIn ~deApiHandle()");
	//
	// The default destructor should automaticly handle checking the underlying
	// objects reference count and destroying it if neccesary.
	if (!bNull)
	{
		if (runtimeID > 0)
		{
			deApiObject* pObject = Dereference();
			if (pObject)
			{
				pObject->RemoveReference();
				// check to see if object reference count <= 0
				// If so, destroy it
				if (pObject->GetReferenceCount() <= 0)
				{
					//printf("\n::DEBUG:: Handle is destroying underlying object. Reference count is 0");
					TheApi.m_pNodeTree->DestroyNode(runtimeID);
					bNull = true;
					runtimeID = 0;
				}
			}
		}
	}
}
//
// Helper function to de-reference underlying object for internal use
deApiObject* deApiHandle::Dereference()
{
	if (bNull)
		return NULL;

	deApiObject* pObject = TheApi.m_pNodeTree->GetApiObject(runtimeID);

//	if (!pObject)
//		bNull = true;

	return pObject;
}
// 
// Used by deApiObjectNodeTree to link the handle to its underlying api object
void deApiHandle::SetRuntimeID(unsigned long runtimeID)
{
	// verify we dont' already have a valid ID.  If we do,just fail out.  We do NOT
	// want to lose our existing link on accident. This should really never happen.
	if (this->runtimeID > 0)
		return;

	if (runtimeID == 0)
	{
		this->runtimeID = 0;
		bNull = true;
	}
	else
	{
		this->runtimeID = runtimeID;
		bNull = false;
		// dereferece this new object and add a reference count
		deApiObject* pObject = Dereference();
		if (pObject)
			pObject->AddReference();
	}
}



//
// Retrieves a handle to the object with the specified runtime ID
deApiHandle deApiNodeTree::GetNode(unsigned long runtimeID)
{
	// bounds check the id to make sure it is within the index range
	// of our array
	int iSize = m_tarrayNodes.Length();
	if ((runtimeID >= iSize) || (runtimeID <= 0))
	{
		// the requested runtime ID is beyond the bounds of our
		// current node list, which means the object it supposedly
		// references is invalid.  Build an invalid handle for return
		deApiHandle hObject;
		hObject.SetRuntimeID(0);
		return hObject;
	}
	else
	{
		// If we get this far, then the runtime ID is in bounds, but that
		// doesn't mean its a valid ID.  The object may have been destroyed
		// and we're just referencing the hole in the list.  We need to verify 
		// the object referenced is valid now
		if (m_tarrayNodes[runtimeID])
		{
			// valid (we hope) object
			deApiHandle hObject;
			hObject.SetRuntimeID(runtimeID);
			return hObject;
		}
		else
		{
			// invalid object
			deApiHandle hObject;
			hObject.SetRuntimeID(0);
			return hObject;
		}
	}
}
void deApiNodeTree::GetNodes(deTArray<unsigned long>& aReturn, deString& TypeFilter, int iMaxCount)
{
   int iIndex;
   int iCount = 0;
   bool bFiltered = false;

   if (TypeFilter.Length() > 0)
      bFiltered = true;

   if (iMaxCount == -1)
      iMaxCount = m_tarrayNodes.Length();

   for (iIndex = 0; iIndex < m_tarrayNodes.Length(); iIndex++)
   {
      if (iCount > iMaxCount)
         return;

      if (m_tarrayNodes[iIndex])
      {
         if (bFiltered)
         {
            if (m_tarrayNodes[iIndex]->Type.IsA(TypeFilter))
            {
               aReturn.PushBack(iIndex);
               iCount++;
            }
         }
         else
         {
            aReturn.PushBack(iIndex);
            iCount++;
         }
      }
   }
}
//
// Inserts the specified object pointer into the tree's array.
// The new runtime ID for the node will be returned, with 0 indicating a failure
// If the array is not large enough, it will automaticly
// be resized.
unsigned long deApiNodeTree::AddNode(deApiObject* pNewObject)
{
	// adding a new object is a multi-step process here.
	// First, we check to see if we have any recycled IDs to use
	// If yes, we insert it into that slot, and return that ID.
	// If not, we then add a new entry to the end of the list.

	int iSize = m_runtimeIDs.Length();

	if (iSize == 0)
	{
		// no recycled IDs to be used, so just add a new entry to end of list
		m_tarrayNodes.PushBack(pNewObject);
		pNewObject->AddReference();
		return m_tarrayNodes.Length() - 1;
	}
	else
	{
		// we have recycled IDs to be used, so grab the ID at the end of the list
		// and use that
		int iNewID = m_runtimeIDs[m_runtimeIDs.Length()-1];
		m_runtimeIDs.RemoveElementAt(m_runtimeIDs.Length()-1);
		m_tarrayNodes[iNewID] = pNewObject;
		pNewObject->AddReference();
		return iNewID;
	}
}
//
// Removes the specified node and destroys the underlying object
bool deApiNodeTree::DestroyNode(unsigned long runtimeID)
{
	// bounds check the id to make sure it is within the index range
	// of our array
	int iSize = m_tarrayNodes.Length();
	if ((runtimeID >= iSize) || (runtimeID <= 0))
	{
		// the requested runtime ID is beyond the bounds of our
		// current node list, which means the object it supposedly
		// references is invalid.
		return false;
	}
	else
	{
		// If we get this far, then the runtime ID is in bounds, but that
		// doesn't mean its a valid ID.  The object may have been destroyed
		// and we're just referencing the hole in the list.  We need to verify 
		// the object referenced is valid now
		if (m_tarrayNodes[runtimeID])
		{
			// valid (we hope) object.  So destroy it, and null the space out
			// then add this ID to our list of recycled IDs.
			delete m_tarrayNodes[runtimeID];
			m_tarrayNodes[runtimeID] = NULL;
			m_runtimeIDs.PushBack(runtimeID);
			return true;
		}
		else
		{
			// invalid object
			return false;
		}
	}
}
//
// Returns the actual underlying api object for a given runtime ID
// This is ONLY used by deApiHandle, and no one else should ever be doing
// this de-reference.
deApiObject* deApiNodeTree::GetApiObject(unsigned long runtimeID)
{
	// bounds check the id to make sure it is within the index range
	// of our array
	int iSize = m_tarrayNodes.Length();
	if ((runtimeID >= iSize) || (runtimeID <= 0))
	{
		// the requested runtime ID is beyond the bounds of our
		// current node list, which means the object it supposedly
		// references is invalid.
		return NULL;
	}
	else
	{
		// If we get this far, then the runtime ID is in bounds, but that
		// doesn't mean its a valid ID.  The object may have been destroyed
		// and we're just referencing the hole in the list.  We need to verify 
		// the object referenced is valid now
		if (m_tarrayNodes[runtimeID])
		{
			// valid (we hope) object
			deApiObject* pObject = m_tarrayNodes[runtimeID];
			return m_tarrayNodes[runtimeID];
		}
		else
		{
			// invalid object
			return NULL;
		}
	}
}
deApiNodeTree::deApiNodeTree()
{
	m_tarrayNodes.PushBack(NULL);
}
deApiNodeTree::~deApiNodeTree()
{
}

//
// deApiOutputWindow
//
// Instance of a standard output/log window
//
// Create the output window
deApiTypes::StatusCode deApiOutputWindow::CreateOutputWindow(int x, int y, int width, int height, const char* title, bool bSizeable, bool bCaption)
{
	HWND hParent = TheApi.GetWindowHandle();

//	if (!hParent)
//		return deApiTypes::sError;

	if (!IsWindow(hParent))
		hParent = NULL;

	DWORD iStyle = WS_POPUP | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | ES_READONLY;
	if (bCaption)
		iStyle |= WS_CAPTION;
	if (bSizeable)
		iStyle |= WS_THICKFRAME;

	m_hWindow = CreateWindow/*Ex(WS_EX_TOOLWINDOW, */("EDIT", title, iStyle, x, y, width, height, hParent, NULL, (HINSTANCE) GetWindowLong(hParent, GWL_HINSTANCE), NULL);

	SetWindowText(m_hWindow, title);

	return deApiTypes::sOk;
}
deApiOutputWindow::deApiOutputWindow()
{ 
	m_hWindow = NULL; 
	m_sText += ">>Output window created\r\n"; 
}
void deApiOutputWindow::AddLogText(const deString& text)
{
	m_sText += text;
	m_sText += "\r\n";
	bool bOk;
	if (m_hWindow)
		bOk = SetWindowText(m_hWindow, m_sText.const_str());
	if (!bOk)
		DWORD err = GetLastError();
}
void deApiOutputWindow::Hide(bool bShow)
{
	if (m_hWindow)
	{
		if (!bShow)
			ShowWindow(m_hWindow, SW_RESTORE);
		else
			ShowWindow(m_hWindow, SW_HIDE);
	}
}
//
// Get the contents of the window
deString deApiOutputWindow::GetLogText()
{
	return m_sText;
}
deApiOutputWindow::~deApiOutputWindow() 
{ 
	DestroyOutputWindow(); 
}

//
// deApiFn_OutputWindow
//
// Provides functions for manipulating a text output/log window for the editor/api.
//
// default constructor
deApiFn_OutputWindow::deApiFn_OutputWindow()
{
	pOutputWindow = NULL;
}
//
// default destructor
deApiFn_OutputWindow::~deApiFn_OutputWindow()
{
}
//
// Create a new output window
deApiHandle deApiFn_OutputWindow::Create(int x, int y, int width, int height, const deString& title, bool bSizeable, bool bCaption)
{
	deApiHandle hHandle;
	pOutputWindow = new deApiOutputWindow;
	if DEAPI_SUCCEEDED(pOutputWindow->CreateOutputWindow(x, y, width, height, title.const_str(), bSizeable, bCaption))
	{
//		pOutputWindow->AddReference();
		hHandle = TheApi.CreateObject(pOutputWindow);
	}

	return hHandle;
}
//
// Bind function set to an existing handle
deApiTypes::StatusCode deApiFn_OutputWindow::BindHandle(deApiHandle handle)
{

	deApiObject* pObject = TheApi.GetObjectFromHandle(handle);
	if (pObject)
	{
		pOutputWindow = (deApiOutputWindow*)pObject;
	}
	else
		return deApiTypes::sNullObject;

	return deApiTypes::sOk;
}
//
// Add text to the output window
void deApiFn_OutputWindow::AddLogText(const deString& sText)
{
	if (pOutputWindow)
	{
		pOutputWindow->AddLogText(sText);
	}
}
void deApiFn_OutputWindow::Hide(bool bShow)
{
	if (pOutputWindow)
	{
		pOutputWindow->Hide(bShow);
	}
}
//
// Save the contents of the window to a text file
/*void deApiFn_OutputWindow::WriteToFile(const deString& sFileName)
{
	if(pOutputWindow)
	{
		deString sText = pOutputWindow->GetLogText();
		IdeFSReal* pFileSystem = IdeFileSystem_CreateFSReal();
		
		if (!pFileSystem->Open(sFileName.const_str(), deFS_Open_CreateAlways | deFS_Open_Write))
			return;
		char* szText = sText.Alloc(sText.Length());
		pFileSystem->Write(szText, sizeof(char)*sText.Length());
		sText.Trim();
		pFileSystem->Close();
	}
}*/



//
// deApiFn_NodeTree
//
// Provides functions for manipulating the underlying node tree itself.  The node tree is
// the lower level tree orginazation where every persistent object is stored.  This 
// tree is also a linkage of operations.  Nodes can be connected together to form a chain
// of operations, with the output of one feeding into the input of the next.
deApiHandle deApiFn_NodeTree::GetNode(unsigned long iRuntimeID)
{
	deApiHandle hHandle;

	if (iRuntimeID > 0)
	{
		hHandle = TheApi.m_pNodeTree->GetNode(iRuntimeID);
	}

	return hHandle;
}
void deApiFn_NodeTree::GetNodes(deTArray<unsigned long>& aReturn, deString& TypeFilter, int iMaxCount)
{
   TheApi.m_pNodeTree->GetNodes(aReturn, TypeFilter, iMaxCount);
}
//
// deApiRender
//
// Encapsulates the render and driver subsystems
// Most of this is used internally.  The API will automaticlly handle
// setup and rendering.  The controlling application just needs to call an
// update once per frame.
bool deApiRender::Init(deString& sDriverName)
{
	m_pRender = IdeRender_GetPtr();
	if (!m_pRender)
		return false;

	// set render settings
	m_pRender->SetRenderFlag(IdeRender::Render_Fill);
	m_pRender->SetRenderFlag(IdeRender::Render_CullCW);
	m_pRender->SetMultiPassOptions(IdeRender::MultiPass_Disable); // MultiPass_Disable or MultiPass_ZOnlyPass
	m_pRender->SetBGColor(0x00000000);

	// setup driver & display
	m_pDriver = m_pRender->AttachToWindow(TheApi.GetWindowHandle(), sDriverName.Reserve(sDriverName.Length()));
	sDriverName.Trim();
	if (!m_pDriver)
	{
		DBGOUT(">>ERROR<< Failed to load D3Ddisplay driver.  Check that the working directory is properly set.");
		return false;
	}

	IdeDriver::deDisplay display;
	RECT rect;
	GetClientRect(TheApi.GetWindowHandle(), &rect);
	memset(&display, 0, sizeof(IdeDriver::deDisplay));
	display.Adapter = 0;
	display.BackBpp = IdeDriver::BPP_A8R8G8B8;
	display.FrontBpp = IdeDriver::BPP_A8R8G8B8;
	display.ZDepth = 24;
	display.StencilDepth = 0;
	display.Windowed = DE_TRUE;
	display.Width = rect.right;
	display.Height = rect.bottom;
	display.IgnoreVSync = deTRUE;
	if (!m_pRender->QueryFormat(m_pDriver, &display, deTRUE))
	{
		DBGOUT("::WARNING:: Unable to initialize a display driver with the specified settings.  Attempting to auto-detect useable settings.");
	}
	if (!m_pRender->LoadDriver(TheApi.GetWindowHandle(), &display, sDriverName.Reserve(sDriverName.Length())))
	{
		sDriverName.Trim();
		DBGOUT(">>ERROR<< Display driver failed to load!");
		return false;
	}
	sDriverName.Trim();

	return true;
}
void deApiRender::BeginFrame()
{
   if (m_pRender)
      m_pRender->BeginFrame(TheApi.GetWindowHandle());
}
void deApiRender::EndFrame()
{
   if (m_pRender)
      m_pRender->EndFrame(TheApi.GetWindowHandle(), 0.0);
}
void deApiRender::Render()
{
   IdeCamera *pCam;
   deApiObject *pObject;
   deApiCamera *pApiCamera;

   // iterate through nodes looking for cameras, then render found cameras.

   if (m_pRender)
   {
      deTArray<unsigned long> aIDs;
      TheApi.m_pNodeTree->GetNodes(aIDs, deString("deApiCamera"));
      int iIndex;
      for (iIndex = 0; iIndex < aIDs.Length(); iIndex++)
      {
         deApiHandle hObject;
         hObject = TheApi.m_pNodeTree->GetNode(aIDs[iIndex]);
         if (!hObject.IsNull())
         {
            pObject = TheApi.GetObjectFromHandle(hObject);
            pApiCamera = (deApiCamera*)pObject;
            pCam = pApiCamera->GetDestinyCamera();
            m_pRender->Render(pCam, 0.0);
         }
      }
   }
}
void deApiRender::SetState()
{
}
//
// deApiFn_Render
//
// Encapsulates both the rendering and display subsystems of Destiny3D.
// Most of this is automated for simple use, though more advanced hooks
// will probably be provided later on.
void deApiFn_Render::Init(deString& sDriverName)
{
	TheApi.m_pRender->Init(sDriverName);
}
void deApiFn_Render::Update(float fTime)
{
   TheApi.m_pRender->BeginFrame();
   TheApi.m_pRender->Render();
   TheApi.m_pRender->EndFrame();
}
//
// deApiCamera
//
// Camera controls
deApiCamera::deApiCamera()
{
   m_pCamera = IdeCamera_CreateCamera();
   m_sName = "";
   m_dFOV = m_pCamera->GetFOV();
   m_dOrthoWidth = m_pCamera->GetOrthoWidth();
   m_bIsOrtho = m_pCamera->IsOrtho();
   m_dNearClip =m_pCamera->GetNearClip();
   m_dFarClip = m_pCamera->GetFarClip();
   m_Transform = m_pCamera->Position();
   m_pCamera->SetWindow(TheApi.GetWindowHandle());
   //
   // TEMPORARY HACK TEMPORARY HACK
   // This is temporary until the viewport stuff is set up.
   // Eventually this should be settable by the viewport, and/or camera function set
   RECT r;
   GetWindowRect(TheApi.GetWindowHandle(), &r);
   deRect dr;
   dr.Top = r.top;
   dr.Left = r.left;
   dr.Bottom = r.bottom;
   dr.Right = r.right;
   m_pCamera->SetRect(dr);
}

deApiCamera::~deApiCamera()
{
   if (m_pCamera)
      m_pCamera->Release();
}

void deApiCamera::SetFOV(deDouble dDegrees)
{
   if (!m_pCamera)
      return;

   if (dDegrees != m_dFOV)
   {
      m_pCamera->SetFOV(dDegrees);
      m_dFOV = dDegrees;
   }
}
void deApiCamera::SetOrthoWidth(deDouble dWidth)
{
   if (!m_pCamera)
      return;

   if (dWidth != m_dOrthoWidth)
   {
      m_pCamera->SetOrthoWidth(dWidth);
      m_dOrthoWidth = dWidth;
   }
}
void deApiCamera::EnableOrtho(bool bEnable)
{
   if (!m_pCamera)
      return;

   if (bEnable != m_bIsOrtho)
   {
      m_bIsOrtho = bEnable;
      m_pCamera->EnableOrtho(bEnable);
   }
}
deTransform deApiCamera::GetTransform()
{
   if (!m_pCamera)
      return deTransform();

   m_Transform = m_pCamera->Position();
   return m_Transform;
}
void deApiCamera::SetTransform(deTransform transform)
{
   if (!m_pCamera)
      return;

   m_Transform = transform;
   m_pCamera->Position() = m_Transform;
}
void deApiCamera::SetName(const deString& sName)
{
   m_sName = sName;
}
deString& deApiCamera::GetName()
{
   return m_sName;
}
deDouble deApiCamera::GetFOV()
{
   return m_dFOV;
}
deDouble deApiCamera::GetOrthoWidth()
{
   return m_dOrthoWidth;
}
bool deApiCamera::IsOrtho()
{
   return m_bIsOrtho;
}
deDouble deApiCamera::GetNearClip()
{
   return m_dNearClip;
}
deDouble deApiCamera::GetFarClip()
{
   return m_dFarClip;
}
void deApiCamera::SetClip(deDouble dNear, deDouble dFar)
{
   if (!m_pCamera)
      return;

   m_dNearClip = dNear;
   m_dFarClip = dFar;
   m_pCamera->SetClip(m_dNearClip, m_dFarClip);
}
IdeCamera* deApiCamera::GetDestinyCamera()
{
   return m_pCamera;
}
//
// deApiFn_Camera
//
// Creation and manipulation of cameras
deApiHandle deApiFn_Camera::Create()
{
	deApiHandle hHandle;
   m_pCamera = new deApiCamera;
	if (m_pCamera)
	{
		hHandle = TheApi.CreateObject(m_pCamera);
	}

	return hHandle;
}
void deApiFn_Camera::SetFOV(deDouble dDegrees)
{
   if (m_pCamera)
      m_pCamera->SetFOV(dDegrees);
}
void deApiFn_Camera::SetOrthoWidth(deDouble dWidth)
{
   if (m_pCamera)
      m_pCamera->SetOrthoWidth(dWidth);
}
void deApiFn_Camera::EnableOrtho(bool bEnable)
{
   if (m_pCamera)
      m_pCamera->EnableOrtho(bEnable);
}
deTransform deApiFn_Camera::GetTransform()
{
   if (m_pCamera)
      return m_pCamera->GetTransform();
   else
      return deTransform();
}
void deApiFn_Camera::SetTransform(deTransform transform)
{
   if (m_pCamera)
      m_pCamera->SetTransform(transform);
}
void deApiFn_Camera::SetName(const deString sName)
{
   if (m_pCamera)
      m_pCamera->SetName(sName);
}
deString deApiFn_Camera::GetName()
{
   if (m_pCamera)
      return m_pCamera->GetName();
   else
      return deString("");
}
deDouble deApiFn_Camera::GetFOV()
{
   if (m_pCamera)
      return m_pCamera->GetFOV();
   else
      return 0.0;
}
deDouble deApiFn_Camera::GetOrthoWidth()
{
   if (m_pCamera)
      return m_pCamera->GetOrthoWidth();
   else
      return 0.0;
}
bool deApiFn_Camera::IsOrtho()
{
   if (m_pCamera)
      return m_pCamera->IsOrtho();
   else
      return false;
}
deDouble deApiFn_Camera::GetNearClip()
{
   if (m_pCamera)
      return m_pCamera->GetNearClip();
   else
      return 0.0;
}
deDouble deApiFn_Camera::GetFarClip()
{
   if (m_pCamera)
      return m_pCamera->GetFarClip();
   else
      return 0.0;
}
void deApiFn_Camera::SetClip(deDouble dNear, deDouble dFar)
{
   if (m_pCamera)
      m_pCamera->SetClip(dNear, dFar);
}




//
// Stand-Alone API Init
//
// This is used only when developing a stand-alone application that uses the API, but is
// not a plug-in to the editor.  When developing a standard plugin, this must not be used
bool deApi_InitStandAlone(HWND hParentWindow)
{
	bool bOk = TheApi.InitApi(hParentWindow);

#ifdef _DEBUG
	if (bOk)
	{
		DBGOUT("DestinyEdit API Initialized.");
	}
	else
	{
		DBGOUT(">>Fatal Error<< Failed to initalize the DestinyEdit API");
	}
#endif
	return bOk;
}