// HNode.cpp: implementation of the HNode class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Peeper.h"
#include "HNode.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

//CArray<HNode,HNode &> HNode::Guff;
//DWORD HNode::ObjCount;

HNode *HNode::Create()
{
	return new HNode;
}

void HNode::Delete(HNode *node)
{
	delete node;
}


HNode::HNode()
{
	Children.SetSize(0,5);
	Clones.SetSize(0,5);
	Original=NULL;
	Parent=NULL;
	Item=NULL;
	Flag=0;
}


bool HNode::AddLocalFile(const CString &fname,const CString &path)
{
	return NewChild()->ParseLocalFile(fname,path);
}

bool HNode::ParseLocalFile(const CString &fname,const CString &path)
{
	FName=fname;
	Path=path;
	Flag=0;
	
	FName.Replace('/','\\');
	int loc=FName.ReverseFind('\\');
	if(loc>=0) // If path was included add it
	{
		Path+=FName.Left(loc+1);
		FName=FName.Mid(loc+1);
	}
	
	
	CString fbuf;
	if(SysGetFile(FName,Path,fbuf))
	{
		return Parse(fbuf.GetBuffer(0));
		fbuf.ReleaseBuffer();
	}
	else
	{
		return ParseGlobalFile(fname);
	}
}

bool HNode::ParseGlobalFile(const CString &fname)
{
	FName=fname;
	Flag=0;
	
	CString path,fbuf;
	if(PathMan->GetFile(FName,Path,fbuf))
	{
		FName.Replace('/','\\');
		int loc=FName.ReverseFind('\\');
		if(loc>=0) // If path was included add it
		{
			Path+=FName.Left(loc+1);
			FName=FName.Mid(loc+1);
		}
		
		return Parse(fbuf.GetBuffer(0));
	}
	else
	{
		Flag|=HN_NOTFOUND;
	}
	
	return true;
}

bool HNode::IsAbove(HNode *node)
{
	if(IsSameName(node)) return true;
	if(Parent==NULL) return false;
	return Parent->IsAbove(node);
}

bool HNode::Parse(char *fbuf)
{
	
	if(Parent && Parent->IsAbove(this))		// If the file is in the Tree we have a loop
	{
		Flag|=HN_LOOP;
		return false;
	}
	
	// If the file has been parsed before copy it
	if(CopyFromTree(this))
		return true;
	
	
	int start=0;
	int bufsize=strlen(fbuf);
	bool foundinclude=false;
	int sd,ed;
	
	for(;;)
	{
		
		
		for(foundinclude=false;!foundinclude;)
		{
			while(
				!(fbuf[start]=='/' && (fbuf[start+1]=='/') || fbuf[start+1]=='*') &&
				fbuf[start]!='#' && 
				start<bufsize) 
				start++;
			
			if((fbuf[start]=='/') && (fbuf[start+1]=='/'))
			{
				while(fbuf[start]!='\x0D' &&  start<bufsize) start++;	// swallow white spaces
				if(start>=bufsize) return true;
			}
			else if((fbuf[start]=='/') && (fbuf[start+1]=='*'))
			{
				start+=2;
				if(start>=bufsize) {Flag|=HN_PARSEERROR; return true;}
				while(!(fbuf[start]!='*' && fbuf[start+1]!='/') &&  start<bufsize) start++;	// swallow white spaces
				if(start>=bufsize) {Flag|=HN_PARSEERROR; return true;}
			}
			else 
				
			{
				if(start>=bufsize) return true;
				start++;
				while((fbuf[start]==' ' || fbuf[start]=='\t') && fbuf[start]!='\x0D') start++;	// swallow white spaces
				if(!strncmp(fbuf+start,"include",7))
				{
					start+=7;
					foundinclude=true;
				}
			}
		}
		
		for(sd=start;fbuf[sd]!='\"' && fbuf[sd]!='\x0D';sd++);
		if(fbuf[sd]=='\"')
		{
			sd++;
			for(ed=sd;fbuf[ed]!='\"' && fbuf[ed]!='\x0D';ed++);
			if(fbuf[ed]!='\"')	{ Flag|=HN_PARSEERROR; return true; }
			fbuf[ed]=0;
			NewChild()->ParseLocalFile(fbuf+sd,Path);
		}
		else
		{
			for(sd=start;fbuf[sd]!='<' && fbuf[sd]!='\x0D';sd++);
			if(fbuf[sd]=='\x0D') { Flag|=HN_PARSEERROR; return true; }
			sd++;
			for(ed=sd;fbuf[ed]!='>' && fbuf[ed]!='\x0D';ed++);
			if(fbuf[ed]!='>')	{ Flag|=HN_PARSEERROR; return true; }
			fbuf[ed]=0;
			NewChild()->ParseGlobalFile(fbuf+sd);
		}
		start=ed+2;	
	}	
}

bool HNode::CopyFromTreeDown(HNode *dest)
{
	if(IsCopy()) return false;
	if(IsSameName(dest))
	{
		dest->Copy(this);		
		return true;
	}
	else
	{
		int size=Children.GetSize();
		for(int i=0;i<size;i++)
		{
			HNode *node=Children[i];
			if(node->CopyFromTreeDown(dest))
				return true;
		}
	}
	
	return false;
}

bool HNode::CopyFromTree(HNode *dest)
{
	if(!Parent) return false;
	
	for(int i=0;i<Parent->Children.GetSize();i++)
		if(Parent->Children[i]!=this && !(Parent->Children[i]->Flag&HN_LOOP))
		{
			if(Parent->Children[i]->CopyFromTreeDown(dest))
				return true;
		}
		return Parent->CopyFromTree(dest);
}

void HNode::FillTree(CTreeCtrl *tree,HNode *stopat,HTREEITEM parent)
{
	if(stopat==NULL) return;
	
	
}


void HNode::FillTree(CTreeCtrl *tree,HTREEITEM parent,int level,int levelmax)
{
	if(level>levelmax) return;
	Item=parent;
	if(!IsRoot() && level>0) 
	{
		Item=AddItem(tree,parent);
	}
	
	for(int i=0;i<Children.GetSize();i++)
	{
		Children[i]->FillTree(tree,Item,level+1);
	}
	
}

HTREEITEM HNode::AddItem(CTreeCtrl *tree,HTREEITEM parent)
{
	HTREEITEM itm;
	if(Flag&HN_NOTFOUND || Flag&HN_LOOP)
	{
		CString con;
		if(Flag&HN_NOTFOUND) con+="(Not Found)";
		if(Flag&HN_LOOP) con+="(Circular)";
		itm=tree->InsertItem(Path+FName+con,parent);
	}
	else
	{
		itm=tree->InsertItem(Path+FName,parent);
	}
	tree->SetItemData(itm,(DWORD)this);
	
	return itm;
}


void HNode::FillReverseTree(CTreeCtrl *tree,HTREEITEM parent)
{
	if(IsRoot()) return;
	HTREEITEM itm=AddItem(tree,parent);
	
	if(!Parent) return;
	
	Parent->FillReverseTree(tree,itm);
	
	int i;
	for(i=0;i<Clones.GetSize();i++)
		if(Clones[i]!=this && Clones[i]->Parent)
			Clones[i]->Parent->FillReverseTree(tree,itm);
		
		if(IsCopy())
		{
			if(Original->Parent)
				Original->Parent->FillReverseTree(tree,itm);
			
			for(int i=0;i<Original->Clones.GetSize();i++)
				if(Original->Clones[i]!=this && Original->Clones[i]->Parent)
					Original->Clones[i]->Parent->FillReverseTree(tree,itm);
				
		}
		
}

void HNode::Copy(HNode *node)
{
	ASSERT(node!=this);
	Destroy();
	FName=node->FName;
	Path=node->Path;
	Flag=node->Flag;
	PathMan=node->PathMan;
	
	Original=node;
	node->Clones.Add(this);
	
	
	for(int i=0;i<node->Children.GetSize();i++)
	{
		Children.Add(node->Children[i]);
	}
	//	VerifyNode();
}

void HNode::Destroy()
{
	
	if(!IsCopy())
	{
		for(int i=0;i<Children.GetSize();i++) 
		{
			HNode *node=Children[i];
			ASSERT(node!=NULL);
			ASSERT(node->Parent==this);
			Delete(node);
			Children[i]=NULL;
		}
	}
	
	Children.RemoveAll();
	Clones.RemoveAll();
	FName="";
	Path="";
	Flag=0;
	Original=NULL;
	PathMan=NULL;
}


DWORD HNode::NodeCount()
{
	int sum=1;
	for(int i=0;i<Children.GetSize();i++)
	{
		sum+=Children[i]->NodeCount();
	}
	
	return sum;
}

DWORD HNode::TreeSize()
{
	int sum=sizeof(HNode)+Children.GetSize()*sizeof(HNode *)+FName.GetLength()+Path.GetLength();
	if(!IsCopy())
	{
		for(int i=0;i<Children.GetSize();i++)
		{
			sum+=Children[i]->TreeSize();
		}
	}
	return sum;
}

HNode *HNode::AddChild(HNode *child) 
{
	ASSERT(child!=NULL);
	ASSERT(child->Parent==NULL);
	Children.Add(child); 
	child->Parent=this; 
	child->PathMan=PathMan;
	return child;
}

void HNode::VerifyNode()
{
	ASSERT(this);
	for(int i=0;i<Children.GetSize();i++) 
	{
		ASSERT(Children[i]);
		ASSERT(Children[i]->Parent);
		ASSERT(Children[i]->Parent==this);
		Children[i]->VerifyNode();
	}
	
}

void HNode::ParseDsp(const CString &fname,const CString &path)
{
	FName=fname;
	Path=path;
	
	CString dspbuf;
	//	CString path=Path.Left(Path.ReverseFind('\\')+1);
	bool res=SysGetFile(FName,Path,dspbuf);
	ASSERT(res);
	int start=0;
	
	start=dspbuf.Find("SOURCE=");
	CString sfname;
	while(start>=0)
	{
		start+=strlen("SOURCE=");
		int endl=dspbuf.Find('\x0D',start);
		if(endl>=0)
		{
			sfname=dspbuf.Mid(start,endl-start);
			if(sfname.Left(2)==".\\") sfname=sfname.Mid(2);
			if(!sfname.Right(4).CompareNoCase(".cpp") || !sfname.Right(2).CompareNoCase(".c"))
				AddLocalFile(sfname,Path);
		}
		
		start=dspbuf.Find("SOURCE=",start+1);
	}
	
	
}	

HNode *HNode::Find(const CString fname,HNode *after,bool returnnext)
{
	if(after==NULL) returnnext=true;
	if(!FName.CompareNoCase(fname))
	{
		if(returnnext) return this;
		if(after==this) returnnext=true;
	}
	
	HNode *ret=NULL;
	
	
	
	for(int i=0;i<Children.GetSize();i++) 
	{
		ret=Children[i]->Find(fname,after,returnnext);
		if(ret) return ret;
	}
	
	
	return NULL;
}

void HNode::DrillDownTo(CTreeCtrl *tree)
{
	if(IsRoot()) 
	{	
		return;
	}
	else
		Parent->DrillDownTo(tree);
	
	int i;
	
	if(Item==NULL)	// If I haven't been added
	{
		for(i=0;i>Parent->Children.GetSize();i++)	// Add me and my siblings
			Parent->Children[i]->Item=Parent->Children[i]->AddItem(tree,Parent->Item);
		
		ASSERT(Item);
	}
	
	for(i=0;i>Children.GetSize();i++)			// Add my children
		if(!Children[i]->Item)
			Children[i]->Item=Children[i]->AddItem(tree,Parent->Item);
		
		
		tree->Expand(Parent->Item,TVE_EXPAND);		// Expand my parent
}


HNode::~HNode()
{
	Destroy();
	Parent=NULL;
}
