//===========================================================================//
// File:	vdata.cc                                                            //
// Project: MUNGA           Brick: Connection Library                        //
// Contents: Implementation details for registered classes and virtual data  //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  -----------------------------------------------------------//
// 11/03/94  ECH  Initial coding.                                            //
// 11/03/94  ECH  Made compatible with BC4.0                                 //
// 11/08/94  ECH  Made compatible with BC4.0	                                //
// 11/29/94  JMA  Changed ClassIdentity to ClassID                           //
// 11/30/94  JMA  Adapted to style changes                                   //
// 12/01/94  JMA  Made compatible with SGI CC                                //
// 12/12/94  ECH  Changed class id access                                    //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc.                //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#include "StuffHeaders.hpp"

//#############################################################################
//#######################    RegisteredClass    ###############################
//#############################################################################

RegisteredClass::ClassData*
	RegisteredClass::DefaultData = NULL;

RegisteredClass::ClassID
	RegisteredClass::FirstTemporaryClassID = FirstTemporaryClassID;

RegisteredClass::ClassData**
	RegisteredClass::ClassDataArray = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	RegisteredClass::InitializeClass(unsigned class_id_count)
{
	Verify(!DefaultData);
	Verify(!ClassDataArray);
	ClassDataArray = new ClassData*[class_id_count];
	Check_Pointer(ClassDataArray);
	memset(ClassDataArray, 0, sizeof(*ClassDataArray)*class_id_count);
	DefaultData = new ClassData(RegisteredClassClassID, "Stuff::RegisteredClass");
	Check_Object(DefaultData);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	RegisteredClass::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
	delete[] ClassDataArray;
	ClassDataArray = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
RegisteredClass::RegisteredClass(ClassData *class_data):
	classData(class_data)
{
	Check_Object(class_data);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const char*
	RegisteredClass::GetClassString() const
{
	Check_Object(this);
	RegisteredClass__ClassData *data = GetClassData();
	Check_Object(data);
	return data->GetClassName();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	RegisteredClass::TestInstance() const
{
	Check_Object(classData);
}

//#############################################################################
//####################    RegisteredClass::ClassData    #######################
//#############################################################################

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
RegisteredClass__ClassData::RegisteredClass__ClassData(
	RegisteredClass::ClassID class_id,
	const char *name,
	RegisteredClass__ClassData *parent
)
{
	//
	//--------------------------------
	// Set up the class data variables
	//--------------------------------
	//
	Verify(static_cast<unsigned>(class_id) < ClassIDCount);
	classID = class_id;
	className = name;
	firstChildClass = NULL;
	nextSiblingClass = NULL;
	parentClass = parent;
	Verify(!RegisteredClass::ClassDataArray[class_id]);
	RegisteredClass::ClassDataArray[class_id] = this;

	//
	//--------------------------------------------------------------------
	// If this class has a parent, hook up to it, otherwise we must be the
	// root class
	//--------------------------------------------------------------------
	//
	if (parentClass)
	{
		Check_Object(parent);
		parent->DeriveClass(this);
	}
	else
	{
		Verify(classID == RegisteredClassClassID);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
RegisteredClass__ClassData::~RegisteredClass__ClassData()
{
	Check_Object(this);

	//
	//----------------------------------------------------------------------
	// Make sure there are no children left, then if this is the root class,
	// make sure it's parent link is NULL
	//----------------------------------------------------------------------
	//
	Verify(!firstChildClass);
	if (classID == RegisteredClassClassID)
	{
		Verify(!parentClass);
	}

	//
	//-----------------------------------------------------------------------
	// Otherwise, this is the a child class, so make sure it is it's parent's
	// current first child.  This ensures that the deallocation order is
	// symmetrical to the allocation order.  Then remove it from the linked
	// list
	//-----------------------------------------------------------------------
	//
	else
	{
		Check_Object(parentClass);
		Verify(parentClass->firstChildClass == this);
		parentClass->firstChildClass = nextSiblingClass;
	}

	//
	//-------------------------------------
	// Remove this from the ClassData array
	//-------------------------------------
	//
	Verify(static_cast<unsigned>(classID) < ClassIDCount);
	Verify(RegisteredClass::ClassDataArray[classID] == this);
	RegisteredClass::ClassDataArray[classID] = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	RegisteredClass__ClassData::IsDerivedFrom(
		RegisteredClass__ClassData* parent
	)
{
	Check_Object(this);

	//
	//---------------------------
	// Handle null parent pointer
	//---------------------------
	//
	if (!parent)
	{
		return false;
	}

	//
	//------------------------------
	// We are descended from ourself
	//------------------------------
	//
	Check_Object(parent);
	if (parent == this)
	{
		return true;
	}

	//
	//-----------------------------------------------
	// Spin up the chain looking for the parent class
	//-----------------------------------------------
	//
	RegisteredClass__ClassData *class_data = parentClass;
	while (class_data)
	{
		Check_Object(class_data);
		if (class_data == parent)
		{
			return true;
		}
		class_data = class_data->parentClass;
	}
	return false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
RegisteredClass__ClassData*
	RegisteredClass__ClassData::FindClassData(const char* name)
{
	Check_Object(this);
	if (!_stricmp(className, name))
	{
		return this;
	}

	RegisteredClass__ClassData *class_data = firstChildClass;
	RegisteredClass__ClassData *result = NULL;
	while (class_data)
	{
		Check_Object(class_data);
		result = class_data->FindClassData(name);
		if (result)
		{
			Check_Object(result);
			return result;
		}
		class_data = class_data->nextSiblingClass;
	}
	return result;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	RegisteredClass__ClassData::DeriveClass(RegisteredClass__ClassData* child)
{
	Check_Object(this);
	Check_Object(child);
	Verify(child->parentClass == this);
	Verify(!child->nextSiblingClass);

	child->nextSiblingClass = firstChildClass;
	firstChildClass = child;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	RegisteredClass__ClassData::TestInstance()
{
	RegisteredClass__ClassData *p = this;
	RegisteredClass__ClassData *class_data = parentClass;
	while (class_data)
	{
		Check_Signature(class_data);
		p = class_data;
		class_data = class_data->parentClass;
	}
	Verify(p->classID == RegisteredClassClassID);
}
