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

#include "FileLogCache.h"

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

/* Create a new FileLogCache.  After a FileLogCache has been constructed,
 * not much else needs to be done to it. */
FileLogCache::FileLogCache(StrBuf filepath, ClientApi* cli, Error* e)
{
	client = cli;
	errors = e;
	client->Init( errors );

	changes = new ChangeSorter();
	main = new FileHead(filepath, this); //Create the "main" FileHead.
	size = 1;
	numarrows = 0;
	main->loc = cl_main;
	head = main;
	tail = main;
	from = NULL;
	into = NULL;
	client->WaitTag(); //flesh out "main" before scan!
	main->scanMain(); //check all revs in "main"
	client->Final( errors );
}

FileHead* FileLogCache::AddFrom(StrBuf filepath)
{
	size++;
	if (from == NULL) //If we don't have any "from" FileHeads yet:
	{
		from = new FileHead(filepath, this);
		from->loc = cl_from;
		head = from;

		from->next_into = main;
		main->next_from = from;	
	} 
	else
	{	//otherwise, insert this as the new "from"
		FileHead* working = new FileHead(filepath, this);
		working->loc = cl_from;
		working->next = from;

		main->next_from = working;
		working->next_into = main;
		from->next_into = working;
		working->next_from = from;

		from = working;
	}
	return from;
}

/*AddInto works much like AddFrom - I don't think it needs explanation. */
FileHead* FileLogCache::AddInto(StrBuf filepath)
{
	size++;
	if (into == NULL)
	{
		into = new FileHead(filepath, this);
		into->loc = cl_into;
	
		into->next_from = main;
		main->next_into = into;

	}
	else
	{
		FileHead* working = new FileHead(filepath, this);
		working->loc = cl_into;
		working->next = into;

		main->next_into = working;
		working->next_from = main;
		into->next_from = working;
		working->next_into = into;

		into = working;
	}
	return into;
}

FileHead* FileLogCache::AddAfter(StrBuf filepath, FileHead* caller)
{
	size++;
	if (caller == main) return AddFrom(filepath);
	FileHead* working = new FileHead(filepath, this);
	working->loc = caller->loc;
	working->next = caller->next;
	caller->next = working;
	switch (caller->loc)
	{
	case cl_from:
		if (caller == head) head = working;
		working->next_from = caller->next_from;
		working->next_into = caller;
		if (caller->next_from) caller->next_from->next_into = working;
		caller->next_from = working;
		break;
	case cl_into:
		if (caller == tail) tail = working;
		working->next_into = caller->next_into;
		working->next_from = caller;
		if (caller->next_into) caller->next_into->next_from = working;
		caller->next_into = working;
		break;
	}
	return working;
}


FileHead* FileLogCache::Get(StrBuf& filepath, bool exfrom, FileHead* caller)
{
	/* If this is a Windows server, do case insensitive compares. */
	if (client->GetProtocol("nocase")) return GetI(filepath, exfrom, caller);

	if (main->name == filepath){ //Was it main?
		return main;
	}
	FileHead* working = from; //Is it in from?
	while (working != NULL)
	{
		if (working->name == filepath) return working;
		working = working->next;
	}
	working = into; //Is it in into?
	while (working != NULL)
	{
		if (working->name == filepath) return working;
		working = working->next;
	}
	/* Make a new one, then. */
	if (caller == main) //If the caller was "main"...
	{
		if (exfrom) return AddFrom(filepath);
		else return AddInto(filepath);
	}
	else
	{
		return AddAfter(filepath, caller);
	}
}

FileHead* FileLogCache::GetI(StrBuf& filepath, bool exfrom, FileHead* caller)
{
	if (main->name.CCompare(filepath) == 0) //Was it main?
	{
		return main;
	}
	FileHead* working = from; //Is it in from?
	while (working != NULL)
	{
		if (working->name.CCompare(filepath) == 0) return working;
		working = working->next;
	}
	working = into; //Is it in into?
	while (working != NULL)
	{
		if (working->name.CCompare(filepath) == 0) return working;
		working = working->next;
	}
	/* Make a new one, then. */
	if (caller == main) //If the caller was "main"...
	{
		if (exfrom) return AddFrom(filepath);
		else return AddInto(filepath);
	}
	else
	{
		return AddAfter(filepath, caller);
	}
}

	

FileLogCache::~FileLogCache() //Clean up everything when deleting this object.
{
	if (main != NULL) delete main;
	if (from != NULL) delete from;
	if (into != NULL) delete into;
	delete changes;
}
