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

#include "stdafx.h"
#include "PatchIT.h"
#include "Span.h"

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

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

void Span::DeleteChildren()
{
	if(Next) Next->DeleteChildren();
	delete Next;
	Next=NULL;
}

void Span::InsertNodeAfter(Span *span)
{
	
	if(Next)
	{
		Next->Prev=span;
	}
	span->Next=Next;
	span->Prev=this;
	Next=span;
}

int Span::FindLargestSpan(Span *comspan,DWORD *pos1,DWORD *pos2,DWORD minsize)
{
	DWORD maxspan=minsize;
	
	BYTE *comsbuf=comspan->Buffer;
	
	
	DWORD pos,cspos,dpos;
	
	for(pos=0;pos<Size && (pos+maxspan)<=Size;pos++)
	{
		
		for(cspos=0;cspos<comspan->Size && (cspos+maxspan)<=comspan->Size;cspos++)
		{
			
			if(Buffer[pos]==comsbuf[cspos] && 
				Buffer[pos+(maxspan-1)]==comsbuf[cspos+(maxspan-1)]
				)
			{
				//Check First and Last for Early out
				
				for(dpos=1;(cspos+dpos)<comspan->Size && 
							(pos+dpos)<Size &&
							Buffer[pos+dpos]==comsbuf[cspos+dpos];dpos++);
				
				if(dpos>maxspan)
				{
					maxspan=dpos;
					*pos1=pos;
					*pos2=cspos;
				}
			}	
		} 
	}
	
	
	return maxspan;
} //End of Find Span	


int Span::MapLargestSpan(Span *comspan,DWORD minsize)
{
	DWORD spansize;
	DWORD pos,cspos;
	
	
	spansize=FindLargestSpan(comspan,&pos,&cspos,minsize);
	
	
	if(spansize>minsize)
	{	// Missed creeping up Take Last One
		Span *new_span1,*new_span2;
		new_span1=AddSpanAt(Buffer+pos,spansize);
		new_span2=comspan->AddSpanAt(comspan->Buffer+cspos,spansize);
		new_span1->MappedTo=new_span2;
		new_span2->MappedTo=new_span1;
		
		if(new_span1->Prev!=NULL && new_span1->Prev->MappedTo==NULL && 
			new_span2->Prev!=NULL && new_span2->Prev->MappedTo==NULL)	//Map the left
			new_span1->Prev->MapLargestSpan(new_span2->Prev,minsize);
		
		if(new_span1->Next!=NULL && new_span1->Next->MappedTo==NULL && 
			new_span2->Next!=NULL && new_span2->Next->MappedTo==NULL)	//Map the right
			new_span1->Next->MapLargestSpan(new_span2->Next,minsize);
		
		return spansize;
		
	}
	return spansize;
} //End of Find Span	


Span *Span::AddSpanAt(BYTE * loc,DWORD size)
{
/* // This will put it in the right place
if(loc<Buffer)
{					// Location is in a forward Box
ASSERT(Next);
Next->AddSpanAt(loc,size,map);
return;
}
	*/	
	ASSERT(loc>=Buffer && (loc+size)<=(Buffer+Size)); //Must Be a Sub Span
	ASSERT(MappedTo==NULL);					 //Cannot Split a Mapped Span
	
	
	
	DWORD endsize;
	Span *new_span;
	
	if((loc-Buffer)==0)							//Don't Need a new one Adjust them
	{
		endsize=Size-size;
		Size=size;
		new_span=this;
	}
	else
	{
		new_span= new Span(loc,size);	// Make our Span
		InsertNodeAfter(new_span);
		endsize=Size-((loc-Buffer)+size);
		Size=(loc-Buffer);
	}
	
	
	ASSERT(endsize>=0);
	if(endsize>0)
	{
		new_span->InsertNodeAfter(new Span(loc+size,endsize));	// At end span if needed;
	}
	
	return new_span;
}

void Span::SpanInfo(CString &fstr,BYTE *base1,BYTE *base2)
{
	CString str;
	str.Format("Location = %i Size = %i ",Buffer-base1,Size);
	if(MappedTo)
	{
		CString str2;
		str2.Format(" -> Location = %i",MappedTo->Buffer-base2);
		str+=str2;
	}
	str+="\n";	 
	fstr+=str;
	if(Next) Next->SpanInfo(fstr,base1,base2);
}

void Span::BuildOps(Span *sspan,CPatchOperation *OpList,const BYTE *base1,const BYTE *base2)
{
	Span *cur_node1,*cur_node2;
	
	DWORD lastloc=0;
	cur_node1=this;
	cur_node2=sspan;
	
	while(cur_node1 && cur_node2)
	{
		if(cur_node2->MappedTo==NULL)
		{
			OpList->Next=new CInsert(cur_node1->Buffer-base1,cur_node2->Size,cur_node2->Buffer-base2);
			OpList=OpList->Next;
			cur_node2=cur_node2->Next;
		}
		
		if(cur_node1->MappedTo==NULL)
		{
			OpList->Next=new CDelete(cur_node1->Buffer-base1,cur_node1->Size);
			OpList=OpList->Next;
			lastloc=cur_node1->Buffer-base1+cur_node1->Size;
			cur_node1=cur_node1->Next;
		}
		
		
		ASSERT((!cur_node1 || cur_node1->MappedTo!=NULL));
		ASSERT((!cur_node2 || cur_node2->MappedTo!=NULL));
		
		if(cur_node1 || cur_node2)
		{
			ASSERT(cur_node2 && cur_node1);
			lastloc=cur_node1->Buffer-base1+cur_node1->Size;
			cur_node1=cur_node1->Next;
			cur_node2=cur_node2->Next;
		}
		
	}
	
	if(cur_node1)
	{
		ASSERT(cur_node1->MappedTo==NULL);
		OpList->Next=new CDelete(cur_node1->Buffer-base1,cur_node1->Size);
		OpList=OpList->Next;
		lastloc=cur_node1->Buffer-base1+cur_node1->Size;
		cur_node1=cur_node1->Next;
	}
	
	if(cur_node2)
	{
		ASSERT(cur_node2->MappedTo==NULL);
		OpList->Next=new CInsert(lastloc,cur_node2->Size,cur_node2->Buffer-base2);
		OpList=OpList->Next;
		cur_node2=cur_node2->Next;
	}
	
	ASSERT(!cur_node1 && !cur_node2);
	
}

Span::~Span()
{
	DeleteChildren();
	
}
