#include "StdAfx.h"
#include "finder.h"


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

//////////////////////////////////////////////////////////////////////////
// карта long-aplExtent
void CaplMapExt::FreeExts(int nFrom)
{
	aplExtent *pExt;
	for (int i=nFrom; i<Size; i++)
	{
		pExt = (aplExtent *)Data[i].out;
		if(pExt) delete pExt;
		Data[i].out = 0;
	}
}

int CaplMapExt::Add(long in, aplExtent *ext /* = NULL */, bool bCopy /* = false */)
{
	int i = CaplMap::Add(in, 0);
	if(ext)
	{
		aplExtent *pExt = ext;
		if(bCopy)
		{
			pExt = new aplExtent;
			pExt->Unique = false;
			pExt->SetSize(ext->GetSize());
			pExt->Append(*ext);
			pExt->Unique = ext->Unique;
			pExt->Sorted_id = ext->Sorted_id;
			pExt->Sorted_inst = ext->Sorted_inst;
		}
		Data[i].out = (long)pExt;
	}
	return i;
}



void CaplMapExt::AddToExt(int i, CaplInstance *inst)
{
	if((i<0) || (i>=Size)) return;
	if(!inst) return;
	aplExtent *ext;
	if(Data[i].out == 0)
	{
		ext = new aplExtent;
		ext->Unique = m_bUnique;
		Data[i].out = (long)ext;
	}
	else
		ext = (aplExtent *)Data[i].out;
	ext->Add(inst);
}

void CaplMapExt::AddToExtByIn(long in, CaplInstance *inst)
{
	int i = FindByIn(in);
	AddToExt(i, inst);
}

void CaplMapExt::QAddToExtByIn(long in, CaplInstance *inst)
{
	int i = QFindByIn(in);
	AddToExt(i, inst);
}

void CaplMapExt::Clear()
{
	FreeExts();
	CaplMap::Clear();
}

bool CaplMapExt::Remove(int index)
{
	if((index<0)||(index>=Size))return false;
	if(Data[index].out != 0)
	{
		aplExtent *pExt = (aplExtent *)Data[index].out;
		delete pExt;
		Data[index].out = 0;
	}
	return CaplMap::Remove(index);
}

void CaplMapExt::SetKeys(aplExtent &extKeys, bool bSort /* = false */)
{
	Clear();
	int i, co = extKeys.GetSize();
	if(co == 0) return;
	SetSize(co);
	for (i = 0; i<co; i++)
	{
		Data[i].in = (long)extKeys[i];
		Data[i].out = 0;
	}
	Size = co;
	if(co>1) m_sorted = false;
	if(bSort) SortIn();
}

void CaplMapExt::Classify(aplExtent &extKeys, aplExtent &extVals, CaplAttr *attr)
{
	if((extKeys.GetSize() == 0) || (!attr)) return;
	SetKeys(extKeys, true);
	Classify(extVals, attr, true);
}

void CaplMapExt::SetExtUnique(bool bUnc)
{
	m_bUnique = bUnc;
}

void CaplMapExt::Classify(aplExtent &extVals, CaplAttr *attr, bool bSortedIn)
{
	if(!attr) return;
	if(Size == 0) return;
	int i, co = extVals.GetSize();
	if(co == 0) return;
	CaplStepData *data = extVals[0]->GetMyData();
	CaplInstance *inst;
	if(bSortedIn)
	{
		for (i = 0; i<co; i++)
		{
			data->GetAttr(extVals[i], attr, inst);
			QAddToExtByIn((long)inst, extVals[i]);
		}
	}
	else
	{
		for (i = 0; i<co; i++)
		{
			data->GetAttr(extVals[i], attr, inst);
			AddToExtByIn((long)inst, extVals[i]);
		}
	}
}

void CaplMapExt::Classify(CaplMapExt &mapVals, CaplAttr *attr, bool bSortedIn /* = true */)
{
	if(!attr) return;
	if(Size == 0) return;
	int i, co = mapVals.Size;
	int j, co2;
	if(co == 0) return;
	CaplStepData *data = ((CaplInstance *)Data[0].in)->GetMyData();
	CaplInstance *inst;
	aplExtent *pExt;
	if(bSortedIn)
	{
		for (i = 0; i<co; i++)
		{
			pExt = (aplExtent *)mapVals.Data[i].out;
			if(!pExt) continue;
			co2 = pExt->GetSize();
			for (j = 0; j<co2; j++)
			{
				data->GetAttr(pExt->GetAt(j), attr, inst);
				QAddToExtByIn((long)inst, pExt->GetAt(j));
			}
		}
	}
	else
	{
		for (i = 0; i<co; i++)
		{
			pExt = (aplExtent *)mapVals.Data[i].out;
			if(!pExt) continue;
			co2 = pExt->GetSize();
			for (j = 0; j<co2; j++)
			{
				data->GetAttr(pExt->GetAt(j), attr, inst);
				AddToExtByIn((long)inst, pExt->GetAt(j));
			}
		}
	}
}

void CaplMapExt::DetachAll()
{
	for (int i = 0; i<Size; i++)	Data[i].out = 0;
}

void CaplMapExt::GetOutExtent(aplExtent &outExt, bool bAllUnique)
{
	if(outExt.GetSize()>0)outExt.Clear();
	int i, co, s = 0;
	aplExtent *pExt;
	for (i = 0; i<Size; i++)
	{
		if(Data[i].out == 0) continue;
		pExt = (aplExtent *)Data[i].out;
		s += pExt->GetSize();
	}
	if(s == 0) return;
	outExt.SetSize(s+1);
	int sz = sizeof(void *);
	if(bAllUnique)
	{
		int s1 = 0;
		for (i = 0; i<Size; i++)
		{
			if(Data[i].out == 0) continue;
			pExt = (aplExtent *)Data[i].out;
			co = pExt->Size;
			if(co > 0)
			{
				memcpy(outExt.Data + s1, pExt->Data, co*sz);
				s1+=co;
			}
		}
		outExt.Size = s;
		outExt.Sorted_id = outExt.Sorted_inst = false;
	}
	else
	{
		for (i = 0; i<Size; i++)
		{
			if(Data[i].out == 0) continue;
			pExt = (aplExtent *)Data[i].out;
			outExt.Append(*pExt);
		}
	}
}
/*
void CaplMapExt::MProjection(CaplAttrValue *av, int co, CaplMapExt &mp)
{
	mp.Clear();
	if(!av)return;
	mp.SetSize(Size);
	int i, j, k, co1;
	aplExtent *pExt;
	mp.SetExtUnique(false);
	for (i = 0; i<Size; i++)
	{
		mp.Data[i].in = Data[i].in;
		mp.Data[i].out = 0;
		if(Data[i].out)
		{
			pExt = (aplExtent *)Data[i].out;
			co1 = pExt->GetSize();
			for (j = 0; j<co; j++)
			{
				
			}
		}
	}
	mp.Size = Size;
	mp.m_sorted = m_sorted;
}
//*/

//*
void CaplMapExt::SProjection(CaplAttrValue *av, int co, CaplMap &mp)
{
	mp.Clear();
	if(!av)return;
	mp.SetSize(Size);
	int i, j, co1;
	aplExtent *pExt;
	CaplInstance *inst;
	CaplValue val;
	long in1, out1;
	for (i = 0; i<Size; i++)
	{
		in1 = Data[i].in;
		out1 = 0;
		if(Data[i].out)
		{
			pExt = (aplExtent *)Data[i].out;
			co1 = pExt->GetSize();
			for (j = 0; j<co1; j++)
			{
				inst = pExt->GetAt(j);
				if(MatchAttrs(inst, av, co)) // найдено полное соответствие
				{
					out1 = (long)inst;
					break;
				}
			}
		}
		mp.Add(in1, out1);
	}
}
//*/

bool CaplMapExt::MatchAttrs(CaplInstance *inst, CaplAttrValue *av, int co)
{
	if(!inst) return false;
	int k;
	CaplValue v;
	CaplStepData *da = inst->GetMyData();
	for (k = 0; k<co; k++)
	{
		da->GetAttr(inst, av[k].attr, v);
		if(v != av[k].value) break;
	}
	return (k >= co);
}

void CaplMapExt::QCreateSubSet(aplExtent &extKeys, CaplMapExt &mp, bool bCopy, bool bNN)
{
	mp.Clear();
	int i, s = 0, co = extKeys.GetSize();
	if(co == 0) return;
	int *inds = new int[co];
	aplExtent *ext;
	for (i = 0; i<co; i++)
	{
		inds[i] = QFindByIn((long)extKeys[i]);
		if(inds[i] < 0) continue;
		if(bNN && (Data[inds[i]].out == 0)) 
		{
			inds[i] = -1;
			continue;
		}
		s++;
	}
	mp.SetSize(s);
	for (i = 0; i<co; i++)
	{
		if(inds[i]<0)continue;
		ext = (aplExtent *)Data[inds[i]].out;
		mp.Add(Data[inds[i]].in, ext, bCopy);
	}
	delete[] inds;
	mp.m_sorted = false;
}

void CaplMapExt::DeleteInstances(bool bDelKeys, bool bDelVals, aplExtent *extRec)
{
	if(!bDelKeys && !bDelVals) return;
	int i, j;
	aplExtent *pe;
	CaplInstance *inst;
	for (i = 0; i<Size; i++)
	{
		if(bDelKeys)
		{
			inst = (CaplInstance *)Data[i].in;
			if(inst)
			{
				if(inst->GetAccessmode() == aplOWN) inst->GetMyData()->DeleteInstance(inst, false, false);
				else if(extRec) extRec->Add(inst);
			}
		}
		if(bDelVals)
		{
			pe = (aplExtent *)Data[i].out;
			if(pe)
			{
				for (j = 0; j<pe->GetSize(); j++)
				{
					inst = pe->GetAt(j);
					if(inst)
					{
						if(inst->GetAccessmode() == aplOWN) inst->GetMyData()->DeleteInstance(inst, false, false);
						else if(extRec) extRec->Add(inst);
					}
				}
			}
		}
	}
}