//
// The developer of the original code and/or files is Tripwire, Inc.
// Portions created by Tripwire, Inc. are copyright (C) 2000 Tripwire,
// Inc. Tripwire is a registered trademark of Tripwire, Inc.  All rights
// reserved.
// 
// This program is free software.  The contents of this file are subject
// to the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version.  You may redistribute it and/or modify it
// only in compliance with the GNU General Public License.
// 
// This program is distributed in the hope that it will be useful.
// However, this program is distributed AS-IS WITHOUT ANY
// WARRANTY; INCLUDING THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS
// FOR A PARTICULAR PURPOSE.  Please see the GNU General Public License
// for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
// 
// Nothing in the GNU General Public License or any other license to use
// the code or files shall permit you to use Tripwire's trademarks,
// service marks, or other intellectual property without Tripwire's
// prior written consent.
// 
// If you have any questions, please contact Tripwire, Inc. at either
// info@tripwire.org or www.tripwire.org.
//
///////////////////////////////////////////////////////////////////////////////
// hierdbnode.h
//
// these classes are used by cHierDatabase as the nodes in the hierarchy
//
#ifndef __HIERDBNODE_H
#define __HIERDBNODE_H

#ifndef __TYPES_H
#include "types.h"
#endif
#ifndef __ARCHIVE_H
#include "archive.h"
#endif

///////////////////////////
// BIG TODO -- I need to change all of these strings to be wchar_t instead of TSTRINGS
//				Also, they should serialize themselves in a platform-neutral byte order
///////////////////////////

//-----------------------------------------------------------------------------
// cHierNode -- the base class for all other nodes; this class contains type 
//		information
//-----------------------------------------------------------------------------
class cHierNode
{
public:
	enum Type
	{
		TYPE_INVALID	= -1,
		TYPE_MIN		= 0,
		TYPE_ROOT		= 1,
		TYPE_ENTRY,
		TYPE_ARRAY,
		TYPE_ARRAY_INFO,
		TYPE_MAX
	};

	
	cHierNode( Type type = TYPE_INVALID ) : mType( type ) {}
	virtual ~cHierNode() {}

	int32	mType;

	/////////////////////////////////////////
	// methods to override
	/////////////////////////////////////////
	virtual int32 CalcArchiveSize() const							{ return ( sizeof(mType) ); }
		// this method should return the amount of space that this class will take up in an archive
		// derived classes should override this if they have any data members that will be stored
		// with Read() or Write()
	virtual void Write	( cArchive& arch ) const	//throw(eArchive) 
		{ arch.WriteInt32( mType ); }
	virtual void Read	( cArchive& arch )			//throw(eArchive) 
	{ 
		arch.ReadInt32( mType );  
		//
		// do a rudimentary integrity check...
		//
		if( (mType <= TYPE_MIN) || (mType >= TYPE_MAX) )
		{
			ASSERT( false );
			throw eArchiveFormat( _T("Invalid type encountered in cHierNode::Read") );
		}
	
	}
		// these methods read and write the class to an archive. We had better be sure that 
		// we don't write more than we said we would in CalcArchiveSize() !
};

//-----------------------------------------------------------------------------
// cHierAddr -- the "address" of different items in the hierarchy
//-----------------------------------------------------------------------------
class cHierAddr
{
public:
	int32	mBlockNum;
	int32	mIndex;

	cHierAddr( int32 block = -1, int32 index = -1 ) : mBlockNum( block ), mIndex( index ) {}

	bool IsNull() const { return (mBlockNum == -1); }
		// returns true if the address points to "null" (ie -- no valid address)
	bool operator==( const cHierAddr& rhs ) const { return( (mBlockNum == rhs.mBlockNum) && (mIndex == rhs.mIndex) ); }


	/////////////////////////////////////////////////
	// serialization methods
	/////////////////////////////////////////////////
	int32	CalcArchiveSize	() const									
	{ 
		return ( sizeof(mBlockNum) + sizeof(mIndex) ); 
	}
	void Write( cArchive& arch ) const	//throw(eArchive) 
	{ 
		arch.WriteInt32( mBlockNum ); 
		arch.WriteInt32( mIndex ); 
	}
	void Read( cArchive& arch )	//throw(eArchive) 
	{ 
		arch.ReadInt32 ( mBlockNum ); 
		arch.ReadInt32 ( mIndex ); 
	}

};


//-----------------------------------------------------------------------------
// cHierRoot -- the root of the hierarchy; you can always count on this being
//		at (0, 0)
//-----------------------------------------------------------------------------
class cHierRoot : public cHierNode
{
public:
	cHierRoot() : cHierNode( TYPE_ROOT ) {}

	cHierAddr	mChild;				// points to a cHierArray or an invalid address
	bool		mbCaseSensitive;	// determines the case-sensitiveness of lookups, ordering, etc.
	TCHAR		mDelimitingChar;	// the delimiting character; this is used when displaying a path to the user

	/////////////////////////////////////////////////
	// serialization methods
	/////////////////////////////////////////////////
	virtual int32 CalcArchiveSize() const							
	{ 
		return ( cHierNode::CalcArchiveSize() + mChild.CalcArchiveSize() ); 
	}
	virtual void Write	( cArchive& arch ) const	//throw(eArchive) 
	{ 
		cHierNode::Write	( arch );
		mChild.Write		( arch );
		arch.WriteInt32		( mbCaseSensitive ? 1 : 0 );
		TSTRING dc			( &mDelimitingChar, 1 );
		arch.WriteString	( dc );
	}
	virtual void Read	( cArchive& arch )			//throw(eArchive) 
	{ 
		cHierNode::Read	( arch );
		//
		// make sure the type is correct
		//
		if( mType !=  TYPE_ROOT )
		{
			ASSERT( false );
			throw eArchiveFormat( _T("Invalid type encountered; expected ROOT node") );
		}
		mChild.Read		( arch );
		int32 cs;
		arch.ReadInt32	( cs );
		mbCaseSensitive = cs ? true : false;
		TSTRING dc;
		arch.ReadString	( dc );
		if( dc.length() != 1 )
		{
			ASSERT( false );
			throw eArchiveFormat( _T("Read of the root node failed; invalid delimiting character.") );
		}
		mDelimitingChar = dc[0];
	}
};

//-----------------------------------------------------------------------------
// cHierEntry -- an entry that contains a name and points to some data
//-----------------------------------------------------------------------------
class cHierEntry : public cHierNode
{
public:
	cHierEntry() : cHierNode( TYPE_ENTRY ) {}

	TSTRING		mName;		// TODO -- change this to a wchar_t string
	cHierAddr	mData;
	cHierAddr	mChild;		// points to a cHierArray or an invalid address
	cHierAddr	mNext;		// the next peer entry in the linked list, or Null() if done

	/////////////////////////////////////////////////
	// serialization methods
	/////////////////////////////////////////////////
	virtual int32 CalcArchiveSize() const							
	{ 
		return (	cHierNode::CalcArchiveSize() + mChild.CalcArchiveSize() + 
					mData.CalcArchiveSize()		 + cArchive::GetStorageSize( mName ) +
					mNext.CalcArchiveSize() ); 
	}
	virtual void Write	( cArchive& arch ) const	//throw(eArchive) 
	{ 
		cHierNode::Write( arch );
		arch.WriteString( mName ); 
		mChild.Write	( arch );
		mData.Write		( arch );
		mNext.Write		( arch );
	}
	virtual void Read	( cArchive& arch )			//throw(eArchive) 
	{ 
		cHierNode::Read	( arch );
		//
		// make sure the type is correct
		//
		if( mType !=  TYPE_ENTRY )
		{
			ASSERT( false );
			throw eArchiveFormat( _T("Invalid type encountered; expected ENTRY node") );
		}

		arch.ReadString	( mName ); 
		mChild.Read		( arch );
		mData.Read		( arch );
		mNext.Read		( arch );
	}

};

//-----------------------------------------------------------------------------
// cHierArrayInfo -- constant-size struct that contains information about an array
//-----------------------------------------------------------------------------
class cHierArrayInfo : public cHierNode
{
public:
	cHierArrayInfo() : cHierNode( TYPE_ARRAY_INFO ) {}

	cHierAddr	mParent;		// points to a cHierArrayInfo or cHierRoot
	cHierAddr	mArray;			// points to cHierEntryArray

	/////////////////////////////////////////////////
	// serialization methods
	/////////////////////////////////////////////////
	virtual int32 CalcArchiveSize() const							
	{ 
		return (cHierNode::CalcArchiveSize() + mParent.CalcArchiveSize() + mArray.CalcArchiveSize()); 
	}
	virtual void Write	( cArchive& arch ) const	//throw(eArchive) 
	{ 
		cHierNode::Write( arch );
		mParent.Write	( arch );
		mArray.Write	( arch );
	}
	virtual void Read	( cArchive& arch )			//throw(eArchive) 
	{ 
		cHierNode::Read	( arch );
		//
		// make sure the type is correct
		//
		if( mType !=  TYPE_ARRAY_INFO )
		{
			ASSERT( false );
			throw eArchiveFormat( _T("Invalid type encountered; expected TYPE_ARRAY_INFO node") );
		}

		mParent.Read	( arch );
		mArray.Read		( arch );
	}

};



#endif //__HIERDBNODE_H

