#pragma once

class HierNode;
class Hierarchy;

const HierOpen = 1;
const HierReal = 2;
const HierPresent = 4;
const HierVisible = 8;

class HierNode
{
friend class Hierarchy;
	HierNode *		m_pSibling;
	HierNode *		m_pChild;
	char *			m_pFullName;
	char *			m_pBaseName;
	unsigned long	m_Flags;

public:
	void *			m_pData;
					HierNode( char *pName );
	virtual			~HierNode();
	char *			FullName() { return m_pFullName; }
	char *			BaseName() { return m_pBaseName; }
	unsigned long	NumSubNames();
	char *			SubName( int subNameNo );
	char *			ParentName();
	bool			IsOpen() { return m_Flags & HierOpen; }
};


// Note: once a HierNode is inserted into a Hierarchy, the Hierarchy "owns" it (for deletion purposes)


class Hierarchy
{
	unsigned long	m_nNodes;
	unsigned long	m_nVisibleNodes;
	HierNode *		m_pFirstNode;
	HierNode **		m_pVisibleNode;
	unsigned long	m_nVisibleNodeTableSize;
	bool			m_fVisibleValid;

	void			DeleteTree( HierNode *pRoot );
	HierNode *		FindOrInsertUnder( HierNode **ppNext, char *pName );
	void			AppendVisibleNode( HierNode *pNode );
	void			AccumulateVisible( HierNode *pNode );
	void			RebuildVisibleNodeTable();
	void			MarkNonPresentTree( HierNode *pRoot );
	void			DeleteNonPresentTree( HierNode **ppNext );


public:
					Hierarchy();
					~Hierarchy();							// Deletes all nodes
	HierNode *		Find( char *pName );
	HierNode *		FindOrCreate( char *pName );
	HierNode *		InsertImaginary( char *pName );
	void			InsertReal( HierNode *pNode );			// Insert a real node, construct imaginary as necessary
	unsigned long	NumNodes() { return m_nNodes; }			// Number of real & imaginary nodes
	unsigned long	NumVisibleNodes();						// Number of visible real & imaginary nodes
	HierNode *		VisibleNode( unsigned long LineNo );	// Returns a real or imaginary visible node
	void			DeleteNonPresent();						// deletes all non-present nodes
	void			RebuildListStart();						// Marks all as non-present
	void			OpenClose( unsigned long LineNo );		// Toggle open/closed state of a visible node by line no
};

