// PdfItem.cpp: implementation of the CPdfItem class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "PdfItem.h"

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

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

CPdfItem::CPdfItem(CaplAPI* api,CaplInstance* inst,COleDateTime codtDTFilter,
				   CString& csSNFilter,CaplInstance* ciContext)
{
	aplExtent		aeRelsNfd,aeRelsFd,aePdfsNfd,aePdfsFd;

	CaplInstance*	cit1	=NULL;
	CaplInstance*	cit2	=NULL;

	int				i		=0;

	m_pChars				=NULL;

	m_pChildItems			=NULL;
	m_iChildsCount			=-1;

	m_csPrdID				="";
	m_csPrdName				="";
	m_csPdfID				="";
	m_pcsCharTypes			=NULL;

	m_pdInitialValues		=NULL;
	m_pdCalculatedValues	=NULL;

	m_dQuantity				=1;



	m_api=api;
	m_inst=inst;

	m_codtDTFilter=codtDTFilter;
	m_csSNFilter=csSNFilter;
	m_ciContext=ciContext;

	//	получаем информацию об этом изделии
	LoadInfo();
	//	получаем субпродукты для этого изделия
	//dmibor 30/05/06
//	m_api->m_prd_mgr.LoadAllSubProduct(NULL,m_ciContext,m_inst,aeRelsNfd,aePdfsNfd);
	m_api->m_prd_mgr.LoadAllSubProduct(NULL,m_ciContext,m_inst,aeRelsNfd,aePdfsNfd,false);
	//	фильтруем их
	FilterChilds(aeRelsNfd,aePdfsNfd,aeRelsFd,aePdfsFd);
	//	сохраняем количество
	m_iChildsCount=aeRelsFd.GetSize();
	//	если субпродуктов нет - выходим
	if(0==m_iChildsCount)
		return;
	//	если субпродукты есть - создаем на их основе объекты
	//	сохраняем указатели на объекты в массиве
	m_pChildItems=new CPdfItem*[m_iChildsCount];
	for(i=0;i<m_iChildsCount;i++)
	{
		cit1=aeRelsFd.GetAt(i);
		m_api->m_data.GetAttr(cit1,m_api->m_prd_mgr.a_pdr_r_ted,cit2);
		m_pChildItems[i]=new CPdfItem(m_api,cit2,m_codtDTFilter,m_csSNFilter,m_ciContext);
		m_api->m_data.GetAttr(cit1,m_api->m_prd_mgr.a_apl_qacu_value,m_pChildItems[i]->m_dQuantity);
	}
}

CPdfItem::~CPdfItem()
{
	int i=0,j=0,j_end=0;
	double* dp=NULL;

	//	если есть характеристики - удаляем их
	if(NULL!=m_pChars)
	{
		for(i=0;i<m_eLastChar+1;i++)
		{
			j_end=m_pChars[i]->Size;
			for(j=0;j<j_end;j++)
			{
				dp=(double*)m_pChars[i]->Data[j].out;
				delete dp;
				dp=NULL;
			}
			m_pChars[i]->Clear();
			delete m_pChars[i];
			m_pChars[i]=NULL;
		}
		delete m_pChars;
		m_pChars=NULL;
	}
	//	если есть типы хар-к - удаляем их
	if(NULL!=m_pcsCharTypes)
	{
		for(i=0;i<m_eLastChar+1;i++)
		{
			delete m_pcsCharTypes[i];
			m_pcsCharTypes[i]=NULL;
		}
		delete m_pcsCharTypes;
		m_pcsCharTypes=NULL;
	}
	//	если есть исходные значения хар-к - удаляем их
	if(NULL!=m_pdInitialValues)
	{
		for(i=0;i<m_eLastChar+1;i++)
		{
			delete m_pdInitialValues[i];
			m_pdInitialValues[i]=NULL;
		}
		delete[] m_pdInitialValues;
		m_pdInitialValues=NULL;
	}
	//	если есть расчетные значения - удаляем их
	if(NULL!=m_pdCalculatedValues)
	{
		for(i=0;i<m_eLastChar+1;i++)
		{
			delete m_pdCalculatedValues[i];
			m_pdCalculatedValues[i]=NULL;
		}
		delete[] m_pdCalculatedValues;
		m_pdCalculatedValues=NULL;
	}
	//	удаляем дочерние объекты. при этом для них вызывается такая же функция удаления
	for(i=0;i<m_iChildsCount;i++)
		delete m_pChildItems[i];
	//	удаляем массив, в котором хранились указатели на дочерние объекты
	delete[] m_pChildItems;
}


int CPdfItem::GetCount(void)
{
	//	в начале количество ставим в 1 = этот объект
	int i=0,c=1;

	// для всех дочерних объектов вызываем эту же функцию и ее значение прибавляем к кол-ву
	for(i=0;i<m_iChildsCount;i++)
		c+=m_pChildItems[i]->GetCount();

	return c;

}

void CPdfItem::LoadChars(CaplTAggr<CaplAttr*,CaplAttr*,APLAGGR_LIST>& caCharVals,
						 CaplTAggr<CaplInstance*,CaplInstance*,APLAGGR_LIST>& caChars,
						 int* ipChars,int iCharCount)
{
	aplExtent		aeGrpChars;
	aplExtent		aeOutCharVals;
	CaplInstance*	ciChar=NULL;
	CaplInstance*	ciCharType=NULL;
	int i=0,i_end=0;
	int j=0,j_end=0;
	double* pdCharVal=NULL;

	//	создаем массив map-ов для хранения значений хар-к.
	//	вход - указатель на instance - тип хар-ки
	//	выход - собственно значение хар-ки
	m_pChars=new CaplMap*[m_eLastChar+1];
	//	создаём массив исходных значений хар-к
	m_pdInitialValues=new double*[m_eLastChar+1];
	//	создаём массив расчётных значений хар-к
	m_pdCalculatedValues=new double*[m_eLastChar+1];
	for(i=0;i<m_eLastChar+1;i++)
	{
		m_pChars[i]=new CaplMap;
		m_pChars[i]->bAutoSort=false;

		m_pdInitialValues[i]=new double;
		m_pdCalculatedValues[i]=new double;
	}

	//	получаем значения хар-к для изделия
	//dmibor 30/05/06
//	m_api->m_charact_mgr.FindAssociatedCharacteristic(m_inst,aeOutCharVals,aeGrpChars);
	m_api->m_charact_mgr.FindAssociatedCharacteristic(m_inst,aeOutCharVals,aeGrpChars,false,false,false);

	i_end=aeOutCharVals.GetSize();
	j_end=iCharCount;
	for(i=0;i<i_end;i++)
	{
		// получаем хар-ку из значения хар-ки
		m_api->m_data.GetAttr(aeOutCharVals.GetAt(i),
							  m_api->m_charact_mgr.a_apl_charact_val_charact,ciChar);
		for(j=0;j<j_end;j++)
		{
			// проверяем на соотв. с заданными хар-ками.
			if(ciChar==caChars.GetAt(j))
			{
				//	получаем тип
				m_api->m_data.GetAttr(aeOutCharVals.GetAt(i),
									  m_api->m_charact_mgr.a_apl_charact_val_type,ciCharType);
				
				pdCharVal=new double;
				m_api->m_data.GetAttr(aeOutCharVals.GetAt(i),caCharVals.GetAt(j),
									  *pdCharVal);
				//	добавляем в map. ключ - тип, выход - указатель на double - собственно цифру
				m_pChars[ipChars[j]]->Add((long)ciCharType,(long)pdCharVal);
			}
		}
	}

	//	сортируем map для ускорения последующего доступа
	for(j=0;j<j_end;j++)
	{
		m_pChars[j]->bAutoSort=true;
		m_pChars[j]->SortIn();
	}

	//	если нет дочерних объектов - выходим
	if(0==m_iChildsCount)
		return;
	//	вызываем эту функцию у дочерних объектов
	for(i=0;i<m_iChildsCount;i++)
		m_pChildItems[i]->LoadChars(caCharVals,caChars,ipChars,iCharCount);
	
}

void CPdfItem::CalcChars(double* dpRetVals,int* ipChars,int iCharCount,
						 aplExtent& aeTypesOrder)
{
	int i=0,i_end=0;
	int j=0,j_end=0;
	double* dpt=0;
	double* _ldpRetVals=new double[iCharCount];
	double* _ldpRetChildVals=new double[iCharCount];
	BOOL bFound=FALSE;

	i_end=iCharCount;
	j_end=aeTypesOrder.GetSize();
	//	цикл по кол-ву хар-к для посчёта
	for(i=0;i<i_end;i++)
	{
		//	инициализируем значения нулями
		dpRetVals[i]=0;
		_ldpRetVals[i]=0;
		//	цикл по кол-ву типов хар-к - приоритетов
		for(j=0;j<j_end;j++)
		{
			//	получаем значение хар-ки из map по ключу - указателю на instance - тип хар-ки
			dpt=(double*)m_pChars[ipChars[i]]->QGetByIn((long)aeTypesOrder.GetAt(j));
			//	если такой хар-ки нет - в map будет -1
			if(-1!=(int)dpt)
			{
				// если нашли хар-ку - устанавливаем флаг и выходим из цикла
				bFound=TRUE;
				break;
			}
		}
		if(TRUE==bFound)
		{
			//	если нашли - сбрасываем флаг
			bFound=FALSE;
			//	сохраняем значение во временной переменной
			_ldpRetVals[i]=*dpt;
			//	получаем тип хар-ки для найденного значения из входного массива
			CaplInstance* cit=aeTypesOrder.GetAt(j);
			//	если указатель = NULL - это хар-ка с не заданным типом
			//	получаем и сохраняем тип найденного значения хар-ки
			if(NULL==cit)
				*m_pcsCharTypes[ipChars[i]]="тип не задан";
			else
				m_api->m_data.GetAttr(cit,m_api->m_charact_mgr.a_apl_charact_type_name,
									  *m_pcsCharTypes[ipChars[i]]);
		}
		else
		{
			//	если хар-ка не найдена - устанавливаем ее значение в 0
			_ldpRetVals[i]=0;
			//	вместо типа хар-ки пишем , что она не найдена
			*m_pcsCharTypes[ipChars[i]]="характеристика не задана";
		}
	}

	//	устанавливаем исходные значения хар-к
	for(i=0;i<i_end;i++)
		*m_pdInitialValues[ipChars[i]]=_ldpRetVals[i];

	if(0==m_iChildsCount)
	{
		//	если нет дочерних объектов - значит данное изделие не является сборкой, след.
		//	расчетные значения хар-к = исходным значениям хар-к
		//	устанавливаем расчетные значения хар-к
		for(i=0;i<i_end;i++)
			*m_pdCalculatedValues[ipChars[i]]=_ldpRetVals[i];
		//	заполняем значениями выходной массив
		for(i=0;i<i_end;i++)
			dpRetVals[i]=_ldpRetVals[i];
		//	удаляем временные переменные
		delete[] _ldpRetVals;_ldpRetVals=NULL;
		delete[] _ldpRetChildVals;_ldpRetChildVals=NULL;
		//	выходим
		return;
	}
	for(i=0;i<m_iChildsCount;i++)
	{
		//	в цикле вызываем эту функцию для дочерних объектов и сохраняем результат ее 
		//	работы во временной переменной
		m_pChildItems[i]->CalcChars(_ldpRetChildVals,ipChars,iCharCount,aeTypesOrder);
		for(j=0;j<iCharCount;j++)
		{
			//	прибавляем к значениям хар-к для данного изделия значения хар-к для дочерних
			//	изделий
			_ldpRetVals[j]+=_ldpRetChildVals[j]*m_pChildItems[i]->m_dQuantity;
			_ldpRetChildVals[j]=0;
		}
	}

	for(i=0;i<i_end;i++)
	{
		//	устанавливаем расчетные значения хар-к
		*m_pdCalculatedValues[ipChars[i]]=_ldpRetVals[i];
	}
	//	заполняем значениями выходной массив
	for(i=0;i<iCharCount;i++)
		dpRetVals[i]=_ldpRetVals[i];
	//	удаляем временные переменные
	delete[] _ldpRetVals;_ldpRetVals=NULL;
	delete[] _ldpRetChildVals;_ldpRetChildVals=NULL;

	//	выходим
	return;
}


void CPdfItem::GetChilds(CPtrArray& paChilds)
{
	int i=0;
	//	очищаем выходной массив
	paChilds.RemoveAll();
	//	если нет дочерних объектов - выходим
	if(0==m_iChildsCount)
		return;
	//	добавляем в выходной массив указатели на дочерние объекты
	for(i=0;i<m_iChildsCount;i++)
		paChilds.Add(m_pChildItems[i]);
}

void CPdfItem::GetInfo(CStringList& csInfo)
{
	int i=0;
	CString cst="";
	csInfo.AddTail(m_csPrdID);										// 0
	csInfo.AddTail(m_csPrdName);									// 1
	csInfo.AddTail(m_csPdfID);										// 2
	CString buf;
	buf.Format("%g",m_dQuantity);
	csInfo.AddTail(buf);										// 3
	for(i=0;i<m_eLastChar+1;i++)
		csInfo.AddTail(*m_pcsCharTypes[i]);							// 4,5
	for(i=0;i<m_eLastChar+1;i++)
	{
		cst="";
		cst.Format("%g",*m_pdInitialValues[i]);						// 5,7
		csInfo.AddTail(cst);
		cst="";
		cst.Format("%g",(*m_pdCalculatedValues[i]*m_dQuantity));	// 6,8
		csInfo.AddTail(cst);
	}
}


void CPdfItem::FilterChilds(aplExtent& aeRelsNfd,aplExtent& aePdfsNfd,aplExtent& aeRelsFd,
							aplExtent& aePdfsFd)
{
	CaplInstance* cit=NULL;
	aplExtent aet1,aet2;
	aplExtent* aepS=NULL;
	aplExtent* aepD=NULL;
	int i=0;
	
	//	если не задан ни один фильтр - просто копируем входные массивы в выходные и выходим
	if(m_codtDTFilter.GetStatus()!=COleDateTime::valid && m_csSNFilter=="")
	{
		aeRelsFd.Append(aeRelsNfd);
		aePdfsFd.Append(aePdfsNfd);
		return;
	}
	//	фильтруем связи
	aepS=&aeRelsNfd;aepD=&aet1;
	//	по серийному номеру
	if(m_csSNFilter!="")
	{
		m_api->m_prd_mgr.FilterlBySN(*aepS,m_csSNFilter,*aepD);
		aepS=aepD;aepD=&aet2;
	}
	//	по дате
	if(m_codtDTFilter.GetStatus()==COleDateTime::valid)
	{
		m_api->m_prd_mgr.FilterlByDate(*aepS,m_codtDTFilter,*aepD);
		aepS=aepD;aepD=NULL;
	}

	aeRelsFd.Append(*aepS);
	//	восстанавливаем изделия по отфильтрованным связям
	for(i=0;i<aeRelsFd.GetSize();i++)
	{
		cit=NULL;
		m_api->m_data.GetAttr(aeRelsFd.GetAt(i),m_api->m_prd_mgr.a_pdr_r_ted,cit);
		aePdfsFd.Add(cit);
	}
}

void CPdfItem::LoadInfo(void)
{
	CaplInstance* ciPrd=NULL;
	int i=0;

	//	получаем информацию об изделии

	m_api->m_data.GetAttr(m_inst,m_api->m_prd_mgr.a_pdf_prd,ciPrd);

	m_api->m_data.GetAttr(ciPrd,m_api->m_prd_mgr.a_prd_id,m_csPrdID);
	m_api->m_data.GetAttr(ciPrd,m_api->m_prd_mgr.a_prd_name,m_csPrdName);
	m_api->m_data.GetAttr(m_inst,m_api->m_prd_mgr.a_pdf_id,m_csPdfID);

	// типы хар-к и сами хар-ки не заполненны, т.к. ещё не проводилось расчета
	m_pcsCharTypes=new CString*[m_eLastChar+1];
	for(i=0;i<m_eLastChar+1;i++)
	{
		m_pcsCharTypes[i]=new CString;
		*m_pcsCharTypes[i]="";
	}
}
