// aplStepDataWithFile.cpp: implementation of the CaplStepDataWithFile class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "aplStepDataWithFile.h"
#include "..\CaplData_Client\MiddleWare.h"


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

//#define _PUT_BLOB_2_FILE

char apl_step_format_id_2[] = "apl_step_data V 0.2";
char apl_step_format_id_u2[] ="apl_step_data Vu0.2";
char apl_step_format_id_3[] = "apl_step_data V 0.3";
char apl_step_format_id_u3[]="apl_step_data Vu0.3";
char apl_text_format_id[] = "apl_text_data V 0.1";
char apl_text_format_id_u[]="apl_text_data Vu0.1";
char apl_blob_format_id[] = "apl_blob_data V 0.1";

void PumpTimerPaint(){
	MSG msg; 
	while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT,
		PM_REMOVE|  PM_NOYIELD)) 
		DispatchMessage(&msg);
	while (::PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER,
		PM_REMOVE|  PM_NOYIELD)) 
		DispatchMessage(&msg);
}

//**********************************************************************
bool aplReadValueFromFile(CFile &file, pCaplInstance *instmap, CaplValue *value, bool bAnsiString /*= true*/)
{
	if(value==0) return false;
	if(instmap==0)return false;
	value->Clear();
	aplValueType type=aplNOTYPE;
	int i,size=0,ival=0;
	long instindex=0;
	double rval=0;
	bool bval=false;
	char lval=-1;
	CaplInstance *instval;
	char microtype;
	CaplIntegrBINValEx blobval;
	file.Read(&microtype,sizeof(microtype));
	type=(aplValueType)microtype;
	switch (type)
	{
	case aplINTEGER: file.Read(&ival,sizeof(ival));value->Set(ival); break;
	case aplREAL: file.Read(&rval,sizeof(rval));value->Set(rval); break;
	case aplBOOL: file.Read(&bval,sizeof(bval));value->Set(bval); break;
	case aplLOGICAL: file.Read(&lval,sizeof(lval));value->Set(lval); break;
	case aplINSTANCE: 
		file.Read(&instindex,sizeof(instindex));
		instval=instmap[instindex];
		if(instval!=0) 	value->Set(instval); else value->Clear();
		break;
	case aplSTRING: 
		file.Read(&size,sizeof(size));
		value->sval=new TCHAR[size];
#ifdef _UNICODE
		if (bAnsiString)
		{
			char *c_buf = new char[size];
			file.Read(c_buf, size);
			CaplStringAdapter sAdapter(c_buf);
			value->Set((LPCWSTR)sAdapter);
			value->type=aplSTRING;
			delete[] c_buf;
		}
		else
		{
			file.Read(value->sval,size*sizeof(TCHAR));
			value->type=aplSTRING;
		}
#else
		file.Read(value->sval,size);
		value->type=aplSTRING;
#endif
		break;
	case aplINTEGRATEDBIN: 
		file.Read(&ival,sizeof(ival));
		blobval.blobId=ival;
		value->Set(blobval); break;
	case aplBINARY:
		file.Read(&size,4);
		//********sval=new char[size];
		//*******dbuf.Read(sval,size);
		//********databuf.Add(sval,size);
		//********value->Set(databuf);
		//****delete sval;
		break;
	case aplAGGR: 
		CaplAggr aggrval;
		CaplValue val;
		file.Read(&size,4);
		for(i=0;i<size;i++)
		{
			val.Clear();
			aplReadValueFromFile(file,instmap,&val,bAnsiString);
			aggrval.Add(val);
		}
		value->Set(aggrval);
		aggrval.Clear();
		break;
	}
	return true;
}


CaplIntegrBINValEx::CaplIntegrBINValEx()
{
	blobId=0;size=0;filePosition=0;tempFile=0;
}

CaplIntegrBINValEx::~CaplIntegrBINValEx()
{
	Clear();
}

void CaplIntegrBINValEx::Clear()
{
	blobId=0;size=0;filePosition=0;
	ClearTempFile();

}

void CaplIntegrBINValEx::ClearTempFile()
{
	if(tempFile!=0){
		CString name=tempFile->GetFilePath();
		tempFile->Close();
		delete tempFile;
		CFile::Remove(name);
	}
	tempFile=0;
}

bool CaplIntegrBINValEx::CreateTempFile()
{
	CFileException pError;
	TCHAR* buf_path=new TCHAR[MAX_PATH];
	TCHAR* buf_name=new TCHAR[MAX_PATH];
	GetTempPath(MAX_PATH,buf_path);
	GetTempFileName(buf_path,_T("apl"),0,buf_name);
	tempFile=new CFile();
	if(!tempFile->Open(buf_name,CFile::modeReadWrite | CFile::shareDenyWrite,&pError)){
		delete tempFile;tempFile=0;
	}
	delete[] buf_path;
	delete[] buf_name;
	return tempFile!=0;
}


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

CaplStepDataWithFile::CaplStepDataWithFile()
{
	CaplStepData();
	m_integr_blob_max_id=10;
	m_MaxInstNum = BEGIN_MAX_INST_NUM;
}

//**********************************************************************
CaplStepDataWithFile::~CaplStepDataWithFile()
{
/*
	if(m_file.GetFileName()!=_T("")){
		m_file.Close();
	}
*/
	CloseWithoutClear();
}

//**********************************************************************
bool CaplStepDataWithFile::CloseWithoutClear()
{
	m_list_blob.Clear();
	if(m_file.m_hFile!=CFile::hFileNull)
		m_file.Close();
	
	return true;
}

//**********************************************************************
void CaplStepDataWithFile::ClearDict()
{
	CaplStepData::ClearDict();
	// Проверка entities.Size!=0 нужна, так как CaplStepData::ClearDict() теперь виртуальная и может быть вызвана при чтении данных из файла
	if(entities.Size!=0 && m_file.m_hFile!=CFile::hFileNull)
		m_file.Close();
}
/*
void CaplStepDataWithFile::SetLastErrorEx(int ErrorCode, bool warning,CString file,int line)
{
	//	if(m_SetErrorMode)
	{
		m_LastErrorCode=ErrorCode;
		m_ErrorDescription=GetErrorDescription(ErrorCode)+m_ErrorAnnotation;
		if(file!=_T("") && line !=0){
			m_ErrorAnnotation.Format(_T("%s(%i) : {%i} %s"),file,line,ErrorCode,warning?_T("Warning "):_T("Error "));
			OutputDebugString(m_ErrorAnnotation+m_ErrorDescription);
			m_ErrorDescription+=m_ErrorAnnotation;
		}
		m_ErrorAnnotation=_T("");
		
		if(ErrorCode!=APLAPIERR_NOERROR) 
			PrintError(warning);
	}
}
*/
//**********************************************************************
const TCHAR* CaplStepDataWithFile::GetErrorDescription(int ErrorCode )
{
	switch (ErrorCode)
	{
		
	case APLAPIERR_INTEGRATED_BIN_NOT_FOUND:return APL_T("Интегрированный файл не найден");break;
	case APLAPIERR_INTEGRATED_BIN_BODY_NOT_FOUND:return APL_T("Тело интегрированного файла не найдено");break;
	case APLAPIERR_INTEGRATED_BIN_BODY_NOT_CORRECT:return APL_T("Ошибка в заголовке интегрированного файла");break;
	default: return  CaplStepData::GetErrorDescription(ErrorCode );break;			
	}
}

//**********************************************************************
bool CaplStepDataWithFile::LoadFromFile(const TCHAR *file_name, bool appload_mode)
{
	if(file_name==0 && m_CurDataFile==_T("")) {SetLastErrorWithFileInfo(APLAPIERR_BADFILENAME); return false;}
	SetLastErrorWithFileInfo(APLAPIERR_NOERROR);
	
	if(file_name!=NULL)
		m_CurDataFile = file_name;

	WIN32_FIND_DATA file_data;
	HANDLE res_find;
	int internal_error=0;

	CString tmp_file=m_CurDataFile;
	tmp_file+=_T(".tmp");
	CString bak_file=m_CurDataFile;
	bak_file+=_T(".bak");
	
	res_find=FindFirstFile(m_CurDataFile,&file_data);
	if(res_find!=INVALID_HANDLE_VALUE){
		FindClose(res_find);
		if(file_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ||
			file_data.dwFileAttributes & FILE_ATTRIBUTE_READONLY ||
			file_data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
		{
			internal_error=APLAPIERR_FILE_BD_READ_ONLY;
			//SetLastErrorWithFileInfo(APLAPIERR_FILE_BD_READ_ONLY);//return false;
		}
	}else{
		SetLastErrorWithFileInfo(APLAPIERR_FILE_BD_NOT_FOUND);return false;
	}

	CString tmp_name=m_CurDataFile;
	if(!appload_mode)ClearData();
	m_CurDataFile=tmp_name;

	res_find=FindFirstFile(bak_file,&file_data);
	if(res_find!=INVALID_HANDLE_VALUE){
		FindClose(res_find);
		if(file_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ||
			file_data.dwFileAttributes & FILE_ATTRIBUTE_READONLY ||
			file_data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
		{
			internal_error=APLAPIERR_FILE_BD_READ_ONLY;
			//SetLastErrorWithFileInfo(APLAPIERR_FILE_BD_READ_ONLY);//return false;
		}
	}
	res_find=FindFirstFile(tmp_file,&file_data);
	if(res_find!=INVALID_HANDLE_VALUE){
		FindClose(res_find);
		if(file_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ||
			file_data.dwFileAttributes & FILE_ATTRIBUTE_READONLY ||
			file_data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
		{
			internal_error=APLAPIERR_FILE_BD_READ_ONLY;
			//SetLastErrorWithFileInfo(APLAPIERR_FILE_BD_READ_ONLY);//return false;
		}
	}
	
	CFileException pError;
	if(m_file.GetFileName()!=_T("")){
		m_file.Close();
	}
	if(!m_file.Open(m_CurDataFile,CFile::modeRead | CFile::shareDenyWrite,&pError)) 
	{
		if(pError.m_cause==CFileException::fileNotFound){
			//The file could not be located."
			SetLastErrorWithFileInfo(APLAPIERR_BADFILENAME); return false;
		}else if(pError.m_cause==CFileException::badPath ){
			//All or part of the path is invalid.
		}else if(pError.m_cause==CFileException::tooManyOpenFiles){
			//The permitted number of open files was exceeded.
		}else if(pError.m_cause==CFileException::accessDenied){
			//The file could not be accessed.
		}
		SetLastErrorWithFileInfo(APLAPIERR_FILE_IO); return false;
	}

	int mode=0,i=strlen(apl_step_format_id_2)+1,k=(int)m_file.GetLength();
	if(k>i)
	{
		char *buf=new char[i];
		m_file.Read(buf,i);
		buf[i-1]='\0';

		if(strcmp(buf, apl_step_format_id_2)==0 || strcmp(buf, apl_step_format_id_3)==0 ||		// ANSI-форматы
			strcmp(buf, apl_step_format_id_u2)==0 || strcmp(buf, apl_step_format_id_u3)==0)		// UNICODE-форматы
			mode=1;
		else if(strcmp(buf, apl_text_format_id)==0 || strcmp(buf, apl_text_format_id_u)==0)
			mode=2;
		else 
		{
			buf[13]='\0';
			if(strcmp(buf, "ISO-10303-21;")==0)
				mode=3;
		}

		delete buf;
	}
	if(mode==1)
	{
		m_Default_TextFormat=false;
		if(!ApploadFromFile())return false;

	}
	else if(mode==2)
	{
		m_file.Close();
		if(!LoadFromTextFile(m_CurDataFile)){SetLastErrorWithFileInfo(APLAPIERR_INVALIDDATAFORMAT);return false;}
	}
	else if(mode==3)
	{
		m_file.Close();
		aplP21Header header;
		if(!LoadP21(file_name,header)){SetLastErrorWithFileInfo(APLAPIERR_INVALIDDATAFORMAT);return false;}
	}
	CSortClass::SortExtentById(*((aplExtent*)&instances));
	if(internal_error!=0)SetLastErrorWithFileInfo(internal_error);
	if(GetLastError()!=APLAPIERR_NOERROR)return false;


	return true;
}

//**********************************************************************
bool CaplStepDataWithFile::ApploadFromFile(aplExtent *ext_inst)
{
	m_file.Seek(0,CFile::begin);
	m_blob_begin_pos=CFile::end;


	if(ext_inst!=0) ext_inst->Clear();
	m_list_blob.Clear();
	SetLastError(0);
	TCHAR *sbuf;
	bool tmp_readonly;
	int i,j,k;
	apl_id id_b;
	USHORT type_id_b,attr_id_b;
	CString buf,buf1;
	CaplInstance *inst,*lastinst;
	CaplEntity *ent,*lastent;
	CaplAttr *attr;
	pCaplInstance *instmap=0;
	CaplValue value;
	char version[20];
	//!!!!!!
	int last_size_inst;
	try
	{
		k=0;
		m_file.Read(version, strlen(apl_step_format_id_2)+1);
#ifdef _UNICODE
		if(strcmp(version, apl_step_format_id_u2)==0 || strcmp(version, apl_step_format_id_u3)==0)
		{
			m_global_ansi_string = false;
		}
		else
		{
			if(strcmp(version, apl_step_format_id_2)==0 || strcmp(version, apl_step_format_id_3)==0)
			{
				m_global_ansi_string = true;
			}
			else
			{
				APL_THROW(APLAPIERR_INVALIDDATAFORMAT);

			}
		}
#else
		if(strcmp(version, apl_step_format_id_2)!=0 && strcmp(version, apl_step_format_id_3)!=0)
		{
			//MessageBox(0,APL_T("Не тот формат"),APL_T("Ошибка"),MB_ICONERROR);
			if(strcmp(version, apl_step_format_id_u2)==0 || strcmp(version, apl_step_format_id_u3)==0)
			{
				APL_THROW_EX(APLAPIERR_INCOMPATIBLDATAFORMAT,CString( APL_T("Файл содержит Unicode строки и не может быть прочитан. Используйте версию для unicode.")));
			}
			else
			{
				APL_THROW(APLAPIERR_INVALIDDATAFORMAT);
			}
		}
#endif
		m_file.Read(&k,4);
		sbuf=new TCHAR[k];
#ifdef _UNICODE
		if (m_global_ansi_string)
		{
			char *c_buf = new char[k];
			m_file.Read(c_buf,k);
			CaplStringAdapter sAdapter(c_buf);
			wcsncpy(sbuf, (LPCWSTR)sAdapter, k);
			delete[] c_buf;
		}
		else
			m_file.Read(sbuf,k*sizeof(TCHAR));
#else
		m_file.Read(sbuf,k);
#endif
		if(m_CurSchema!=sbuf)
		{
			if(instances.Size>0)APL_THROW(APLAPIERR_INCOMPATIBLEDICT);
			CString tmp_name=m_CurDataFile;
			CaplStepData::ClearDict();
			if(!LoadDictionary(sbuf)) 
			{
				//MessageBox(0,APL_T("Кривой словарик"),APL_T("Ошибка"),MB_ICONERROR);
				delete sbuf;
				APL_THROW(-1);
			}
			m_CurDataFile=tmp_name;
		}
		delete sbuf;
		m_file.Read(&m_MaxInstNum,sizeof(m_MaxInstNum));
		m_file.Read(&k,4);
		instances.SetSize(k+instances.Size);
		instmap=new pCaplInstance[k];
		for(i=0;i<k;i++)instmap[i]=0;
		//!!!!
		last_size_inst=instances.Size;
		// чтение Instance
		for(i=0;i<k;i++)
		{
			if(!m_file.Read(&id_b,4)) 
				APL_THROW(APLAPIERR_BADDATA);
			if(!m_file.Read(&type_id_b,sizeof(type_id_b))) 
				APL_THROW(APLAPIERR_BADDATA);
			char access_mode=0;
			if(!m_file.Read(&access_mode,sizeof(access_mode))) 
				APL_THROW(APLAPIERR_BADDATA);

			if(id_b>m_MaxInstNum){
				m_MaxInstNum=id_b+1;
			}

			// поиск соответствующего
			inst=0;
			if(m_is_readonly && access_mode<2){access_mode=2;}
			if(id_b!=0)
			{
				aplQFindInstIdInExtent(*((aplExtent*)(&instances)),id_b,last_size_inst,true,&inst);
				if(inst!=0) inst->SetAccessmode((aplAccessModeType)access_mode);
			}
			if(type_id_b==0)
			{
				// удаление Instance
				if(inst!=0) { if(inst->GetType()!=0) DeleteInstance(inst,true,true); }
			}
			else
			{
				ent=GetEntityById(type_id_b);
				if(ent==0)
				{
					m_ErrorAnnotation.Format(_T(" (%i)"),type_id_b);
					APL_THROW(APLAPIERR_BADDATA_INVALID_ENTINY_ID);
				}

				// создание нового
				if(inst==0)
				{
					// проверка в удаленных
					/* убрано 05.10.200
					/*if(killed_instances.Find(id_b)!=-1)
					{
						id_b=id_b;
					}
					if(killed_instances.Find(id_b)==-1)*/
					{
						tmp_readonly=m_is_readonly;
						m_is_readonly=false;
						inst=CreateInstance(ent);
						m_is_readonly=tmp_readonly;
						if(id_b!=0){
							inst->SetId(id_b);
						}
						inst->SetAccessmode((aplAccessModeType)access_mode);
					}
				}
				instmap[i]=inst;
				if(ext_inst!=0) ext_inst->Add(inst);
			}
			PumpTimerPaint();
		}
		CSortClass::SortInstById(instances);

		//Чтение attributes
		while (m_file.Read(&id_b,4))
		{
			if(id_b==0xFFFFFFFF)
				break;
			lastinst=instmap[id_b];
			//if((long)lastinst==0) 
			//	APL_THROW(APLAPIERR_BADDATA);
			if((long)lastinst==0)
			{
				m_file.Read(&k,4);
				for(i=0;i<k;i++)
				{
					if(!m_file.Read(&attr_id_b,sizeof(attr_id_b)))APL_THROW(APLAPIERR_BADDATA);
					aplReadValueFromFile(m_file,instmap,&value,m_global_ansi_string);
				}
				continue;
			}
			lastent=lastinst->GetType();
			m_file.Read(&k,4);
			for(i=0;i<k;i++)
			{
				if(!m_file.Read(&attr_id_b,sizeof(attr_id_b)))
					APL_THROW(APLAPIERR_BADDATA);
				if(attr_id_b==0) continue;
				aplReadValueFromFile(m_file,instmap,&value,m_global_ansi_string);
				
				if(lastent==0) continue; // Inst удален в текущей сессии
				
				attr=0;
				for(j=0;j<lastent->all_attrs.Size;j++)
				{
					if(lastent->all_attrs[j]->id==attr_id_b)
					{
						attr=lastent->all_attrs[j];
						break;
					}
				}
				if(attr==0) 
				{
					// проверка в перегружающих
					for(j=0;j<lastent->attrs.Size;j++)
					{
						if(lastent->attrs[j]->id==attr_id_b)
						{
							if(lastent->attrs[j]->vid!=_T('e')){SetLastErrorWithFileInfo(APLAPIERR_BADATTR); return 0;}
							if(lastent->attrs[j]->redeclaring==0){SetLastErrorWithFileInfo(APLAPIERR_BADATTR); return 0;}
							attr=lastent->attrs[j]->redeclaring;
							break;
						}
					}
				}
				if(attr==0)
				{
					m_ErrorAnnotation.Format(_T(" (%i)\n\nInstance ID = %i\n\nEntity ID = %i (%s)"),
						attr_id_b,lastinst->GetId(),lastent->id,LPCTSTR(lastent->name));
					APL_THROW(APLAPIERR_BADDATA_INVALID_ATTR_ID);
				}

				CaplInstance::CaplValueDefinition *val=GetAttrValue(lastinst,attr,true);
				if(val==0)
				{
					APL_THROW(APLAPIERR_BADDATA);
					continue;
				}
				if(val->changed==false)
				{
					if(ChekAttrType(lastinst,attr,value))
					{
						val->value.Set(value);
						if(value.type==aplAGGR)
						{
							if(val->ArhiveAggr==0) val->ArhiveAggr=new CaplAggr;
							else val->ArhiveAggr->Clear();
							val->ArhiveAggr->Append(*(value.aggrval));
						}
					}
				}
			}
			PumpTimerPaint();
		}
		// интегрированные в файл БЛОБы
		DWORD pos=(DWORD)m_file.GetPosition();
		DWORD file_size=(DWORD)m_file.GetLength();
		if(pos<file_size){
			CaplIntegrBINValEx *blobval;
			int blob_id;
			DWORD blob_size;
			m_file.Read(version,strlen(apl_blob_format_id)+1);
			if(CString(apl_blob_format_id)!=version)
			{
				MessageBox(0,APL_T("Не тот формат для БЛОБов"),APL_T("Ошибка"),MB_ICONERROR);
				APL_THROW(APLAPIERR_INVALIDDATAFORMAT);
			}
			// 
			while(true){
				pos=(DWORD)m_file.GetPosition();
				if(pos==file_size)break;
				if(m_file.Read(&blob_id,4)!=4)break;
				if(m_integr_blob_max_id<blob_id)m_integr_blob_max_id=blob_id;
				if(m_file.Read(&blob_size,4)!=4)break;
				if(pos+8+blob_size>file_size){
					MessageBox(0,APL_T("Не тот размер БЛОБа"),APL_T("Ошибка"),MB_ICONERROR);
					APL_THROW(APLAPIERR_INVALIDDATAFORMAT);
				}
				blobval=new CaplIntegrBINValEx();
				blobval->blobId=blob_id;
				blobval->size=blob_size;
				blobval->filePosition=pos;
				m_list_blob.Add(blobval);
#if defined(_DEBUG) && defined (_PUT_BLOB_2_FILE)
				CFile testfile;
				DWORD size,cur_size;
				size=blob_size;
				testfile.Open(_T("D:\\temp\\__\\2.2"),CFile::modeCreate|CFile::modeWrite);
				char *buf=new char[SIZE_PORTION_FILE_OPERATE];
				while(true){
					cur_size=SIZE_PORTION_FILE_OPERATE>blob_size?blob_size:SIZE_PORTION_FILE_OPERATE;
					if(cur_size!=m_file.Read(buf,cur_size)){
						delete[] buf;
						SetLastErrorWithFileInfo(APLAPIERR_FILE_IO); return false;
					}
					testfile.Write(buf,cur_size);
					pos+=cur_size;
					size-=cur_size;
					if(size==0)
						break;
				}
				testfile.Close();
#else
				m_file.Seek(blob_size,CFile::current);
#endif
			}
		}
		
	}
	catch(SaplErrorDescription error)
	{
		if(error.m_err_code!=-1)SetLastErrorEx(error);
		int err=m_LastErrorCode;
		CString err_descr=m_ErrorDescription;
		ClearData();
		m_LastErrorCode=err;
		m_ErrorDescription=err_descr;
		if (instmap!=0) delete instmap;
		return false;
	}
	if (instmap!=0) delete instmap;

	return true;
}

bool CaplStepDataWithFile::GlobalCreateId()
{
	bool need_sort=false;
	for(int i=0;i<instances.Size;i++){
		if(instances[i]->GetId()==0){
			instances[i]->SetId(++m_MaxInstNum);
			need_sort=true;
		}
	}
	if(need_sort){
		CSortClass::SortInstById(instances);
	}
	return true;
}

//**********************************************************************
bool CaplStepDataWithFile::SaveToFile(const TCHAR *file_name, bool bCreateBakup)
{
	if(file_name==0 && m_CurDataFile==_T("")) {SetLastErrorWithFileInfo(APLAPIERR_BADFILENAME); return false;}
	SetLastError(0);
	int i,id,size,old_id,old_size;
	UINT cur_size;
	UINT new_pos;
	int new_size;
	TCHAR *buf;
	CaplIntegrBINValEx* blobval;
	CFile* fileread=0;


	WIN32_FIND_DATA file_data;
	HANDLE res_find;
	if(file_name!=0){m_CurDataFile=file_name;}
	CString tmp_file=m_CurDataFile;
	tmp_file+=_T(".tmp");
	CString bak_file=m_CurDataFile;
	bak_file+=_T(".bak");

	CSortClass::SortInstById(instances);
	
	res_find=FindFirstFile(m_CurDataFile,&file_data);
	if(res_find!=INVALID_HANDLE_VALUE){
		FindClose(res_find);
		if(file_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ||
			file_data.dwFileAttributes & FILE_ATTRIBUTE_READONLY ||
			file_data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
		{
			SetLastErrorWithFileInfo(APLAPIERR_FILE_BD_READ_ONLY);return false;
		}
	}

	res_find=FindFirstFile(bak_file,&file_data);
	if(res_find!=INVALID_HANDLE_VALUE){
		FindClose(res_find);
		if(file_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ||
			file_data.dwFileAttributes & FILE_ATTRIBUTE_READONLY ||
			file_data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
		{
			SetLastErrorWithFileInfo(APLAPIERR_FILE_BD_READ_ONLY);return false;
		}
	}
	res_find=FindFirstFile(tmp_file,&file_data);
	if(res_find!=INVALID_HANDLE_VALUE){
		FindClose(res_find);
		if(file_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ||
			file_data.dwFileAttributes & FILE_ATTRIBUTE_READONLY ||
			file_data.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)
		{
			SetLastErrorWithFileInfo(APLAPIERR_FILE_BD_READ_ONLY);return false;
		}
	}
	
	CaplDataBuf data;
	if(m_Default_TextFormat) return SaveToTextFile(m_CurDataFile);
	if(!SaveToDataBuf(data,0x0003)) return false;

	CFile* file=0;
	
	TCHAR szError[1024];
      
	CFileException pError;
	file=new CFile();
	if(!file->Open(tmp_file,CFile::modeCreate|CFile::modeWrite,&pError)){
		pError.GetErrorMessage(szError, 1024);
		m_ErrorAnnotation=APL_T("Не могу открыть файл '")+pError.m_strFileName+CString(APL_T("' Ошибка: "))+szError;
		SetLastErrorWithFileInfo(APLAPIERR_FILE_IO);
		delete file;
		return false;
	}
	
	TRY
	{
		CFileException a;
		// цапельные данные
		file->Write(data.m_data,data.m_Size);
		file->Flush();
		// Записываем интегрированные файлы
		// разделитель
		id=0xFFFFFFFF;
		file->Write(&id,4);
		// заголовок
		file->Write(apl_blob_format_id,strlen(apl_blob_format_id)+1);
		buf=new TCHAR[SIZE_PORTION_FILE_OPERATE];
		for(i=0;i<m_list_blob.GetSize();i++){
			blobval=m_list_blob.GetAt(i);
			if(blobval==0)continue;
			if(blobval->blobId==0)continue;
			id=blobval->blobId;
			new_pos=(UINT)file->GetPosition();
			file->Write(&id,4);
			// откуда он?
			if(blobval->tempFile==0){
				// из старого файла
				m_file.Seek(blobval->filePosition,CFile::begin);
				size=blobval->size;
				m_file.Read(&old_id,4);
				if(old_id!=id){
					m_ErrorAnnotation=APL_T("При чтении интегрированного БЛОБа возникла ошибка: не совпадают id блоб-ов");
					file->Close();
					delete file;
					return false;
					SetLastErrorWithFileInfo(APLAPIERR_FILE_IO); 
				}
				m_file.Read(&old_size,4);
				if(old_size!=size){
					m_ErrorAnnotation=APL_T("При чтении интегрированного БЛОБа возникла ошибка: не совпадают размеры блоб-ов");
					SetLastErrorWithFileInfo(APLAPIERR_FILE_IO); 
					file->Close();
					delete file;
					return false;
				}
				fileread=&m_file;
			}else{
				// из временного файла
				size=(int)blobval->tempFile->GetLength();
				blobval->tempFile->SeekToBegin();
				fileread=blobval->tempFile;
			}
			file->Write(&size,4);
			new_size=size;
#if defined(_DEBUG) && defined (_PUT_BLOB_2_FILE)
			CFile testfile;
			testfile.Open(_T("D:\\temp\\__\\2.2"),CFile::modeCreate|CFile::modeWrite);
#endif
			// копируем тело
			while(true){
				cur_size=SIZE_PORTION_FILE_OPERATE>size?size:SIZE_PORTION_FILE_OPERATE;
				if(cur_size!=fileread->Read(buf,cur_size)){
					delete[] buf;
					delete blobval;
					pError.GetErrorMessage(szError, 1024);
					m_ErrorAnnotation=APL_T("При чтении файла '")+pError.m_strFileName+CString(APL_T("' возникла ошибка: "))+szError;
					SetLastErrorWithFileInfo(APLAPIERR_FILE_IO); 
					file->Close();
					delete file;
					return false;
				}
				file->Write(buf,cur_size);
#if defined(_DEBUG) && defined (_PUT_BLOB_2_FILE)
				testfile.Write(buf,cur_size);
#endif
				size-=cur_size;
				if(size==0)
					break;
			}
#if defined(_DEBUG) && defined (_PUT_BLOB_2_FILE)
			testfile.Close();
#endif
			blobval->ClearTempFile();
			blobval->size=new_size;
			blobval->filePosition=new_pos;
		}

		delete[] buf;
		file->Flush();
		file->Close();
		delete file;
		if(m_file.GetFileName()!=_T("")){
			m_file.Close();
		}
		CFileFind finder;

		// Удаление старого bak 
		if(finder.FindFile(bak_file))
			CFile::Remove(bak_file);

		// Сделать bak если установлен соответствующий флаг
		if(finder.FindFile(m_CurDataFile))
		{
			if(bCreateBakup)
				CFile::Rename(m_CurDataFile,bak_file);
			else//Добавлено, чтобы не создавать резервную копию
				CFile::Remove(m_CurDataFile);//Добавлено, чтобы не создавать резервную копию
		}
		
		CFile::Rename(tmp_file,m_CurDataFile);
		if(!m_file.Open(m_CurDataFile,CFile::modeRead | CFile::shareDenyWrite,&pError)) 
		{
			if(pError.m_cause==CFileException::fileNotFound){
				//The file could not be located."
				pError.GetErrorMessage(szError, 1024);
				m_ErrorAnnotation=APL_T("При открытии файла '")+pError.m_strFileName+CString(APL_T("' возникла ошибка: "))+szError;
				SetLastErrorWithFileInfo(APLAPIERR_BADFILENAME); return false;
			}else if(pError.m_cause==CFileException::badPath ){
				//All or part of the path is invalid.
			}else if(pError.m_cause==CFileException::tooManyOpenFiles){
				//The permitted number of open files was exceeded.
			}else if(pError.m_cause==CFileException::accessDenied){
				//The file could not be accessed.
			}
			pError.GetErrorMessage(szError, 1024);
			m_ErrorAnnotation=APL_T("При открытии файла '")+pError.m_strFileName+CString(APL_T("' возникла ошибка: "))+szError;
			SetLastErrorWithFileInfo(APLAPIERR_FILE_IO); return false;
		}
	}
	CATCH( CFileException, e )
	{
		e->GetErrorMessage(szError, 1024);
		m_ErrorAnnotation=APL_T("При операциях с файлом '")+e->m_strFileName+CString(APL_T("' возникла ошибка: "))+szError;
		SetLastErrorWithFileInfo(APLAPIERR_FILE_IO);
		return false;
	}
	END_CATCH

	return true;
}

bool CaplStepDataWithFile::PutIntegratedBlob(CaplInstance* inst,CaplAttr* attr,const TCHAR* namefilesource)
{
	CaplIntegrBINValEx *blobval;
	DWORD pos=0,size=0,cur_size=0;
	CaplValue val;
	if(m_file.m_hFile==CFile::hFileNull){
		return false;
	}

	if(inst==0) {SetLastErrorWithFileInfo(APLAPIERR_BADINSTANCE); return false;}
	if(inst->GetType()==0) {SetLastErrorWithFileInfo(APLAPIERR_BADINSTANCE); return false;}
	if(attr==0) {SetLastErrorWithFileInfo(APLAPIERR_BADATTR); return false;}
	if(inst->GetAccessmode()>aplRW) {SetLastErrorWithFileInfo(APLAPIERR_NOACCESSRIGHT); return false;}
	if(!ChekAttrType(inst, attr,aplINTEGRATEDBIN)){SetLastErrorWithFileInfo(APLAPIERR_BADTYPE); return false;}
	if(namefilesource==0){SetLastErrorWithFileInfo(APLAPIERR_BADDATA); return false;}

	// удалим старое значение, если оно есть
	DelIntegratedBlob(inst,attr);
	// пытаемся открыть переданный нам файл
	CFile file;
	CFileException pError;
	
	if(!file.Open(namefilesource,CFile::modeRead | CFile::shareDenyWrite,&pError)) 
	{
		if(pError.m_cause==CFileException::fileNotFound){
			//The file could not be located."
			SetLastErrorWithFileInfo(APLAPIERR_BADFILENAME); 
			return false;
		}
		SetLastErrorWithFileInfo(APLAPIERR_FILE_IO); 
		return false;
	}
	file.SeekToBegin();
	char *buf=new char[SIZE_PORTION_FILE_OPERATE];

	// создаем временный файл
	blobval=new CaplIntegrBINValEx();
	if(blobval==0)return false;
	blobval->blobId=++m_integr_blob_max_id;
	if(!blobval->CreateTempFile()){
		delete blobval;
		file.Close();
		return false;
	}

	// читаем из временного файла
#if defined(_DEBUG) && defined (_PUT_BLOB_2_FILE)
	CFile testfile;
	testfile.Open(_T("D:\\temp\\__\\2.2"),CFile::modeCreate|CFile::modeWrite);
#endif
	file.SeekToBegin();
	size=(DWORD)file.GetLength();
	blobval->tempFile->SeekToBegin();
	while(true){
		cur_size=SIZE_PORTION_FILE_OPERATE>size?size:SIZE_PORTION_FILE_OPERATE;
		if(cur_size!=file.Read(buf,cur_size)){
			delete[] buf;
			delete blobval;
			file.Close();
			SetLastErrorWithFileInfo(APLAPIERR_FILE_IO); 
			return false;
		}
		blobval->tempFile->Write(buf,cur_size);
#if defined(_DEBUG) && defined (_PUT_BLOB_2_FILE)
		testfile.Write(buf,cur_size);
#endif
		pos+=cur_size;
		size-=cur_size;
		if(size==0)
			break;
	}
#if defined(_DEBUG) && defined (_PUT_BLOB_2_FILE)
	testfile.Close();
#endif
	blobval->tempFile->Flush();
	file.Close();
	delete[] buf;

	// заносим описание  файла в массив
	m_list_blob.Add(blobval);
	val.Set(*blobval);
	PutAttr(inst,attr,val);

	return true;
}

bool CaplStepDataWithFile::DelIntegratedBlob(CaplInstance* inst,CaplAttr* attr)
{
	if(m_file.m_hFile==CFile::hFileNull){
		return false;
	}
	CaplIntegrBINValEx *blobval;
	CaplIntegrBINVal blobsrc;
	int i;
	CaplValue val;

	if(inst==0) {SetLastErrorWithFileInfo(APLAPIERR_BADINSTANCE); return false;}
	if(inst->GetType()==0) {SetLastErrorWithFileInfo(APLAPIERR_BADINSTANCE); return false;}
	if(attr==0) {SetLastErrorWithFileInfo(APLAPIERR_BADATTR); return false;}
	if(inst->GetAccessmode()>aplRW) {SetLastErrorWithFileInfo(APLAPIERR_NOACCESSRIGHT); return false;}
	
	if(!GetAttr(inst,attr,val))return false;
	val.Get(blobsrc);
	if(blobsrc.blobId==0){
		SetLastErrorWithFileInfo(APLAPIERR_INTEGRATED_BIN_NOT_FOUND);
		return false;
	}
	
	for(i=0;i<m_list_blob.GetSize();i++){
		blobval=m_list_blob.GetAt(i);
		if(blobsrc==*blobval){
			m_list_blob.Remove(i);
			break;
		}
	}

	blobsrc.blobId=0;
	val.Set(blobsrc);
	if(!PutAttr(inst,attr,val))return false;

	return true;
}



bool CaplStepDataWithFile::GetIntegratedBlob(CaplInstance* inst,CaplAttr* attr,const TCHAR* namefiledestination)
{
	if(m_file.m_hFile==CFile::hFileNull){
		return false;
	}

	CaplIntegrBINValEx *blobval;
	CaplIntegrBINVal blobsrc;
	int i;
	CFile* tempfile=0;
	DWORD pos=0,size=0,cur_size=0;
	CaplValue val;
	
	if(inst==0) {SetLastErrorWithFileInfo(APLAPIERR_BADINSTANCE); return false;}
	if(inst->GetType()==0) {SetLastErrorWithFileInfo(APLAPIERR_BADINSTANCE); return false;}
	if(attr==0) {SetLastErrorWithFileInfo(APLAPIERR_BADATTR); return false;}
	if(inst->GetAccessmode()>aplRW) {SetLastErrorWithFileInfo(APLAPIERR_NOACCESSRIGHT); return false;}
	if(!ChekAttrType(inst, attr,aplINTEGRATEDBIN)){SetLastErrorWithFileInfo(APLAPIERR_BADTYPE); return false;}
	if(namefiledestination==0){SetLastErrorWithFileInfo(APLAPIERR_BADDATA); return false;}

	if(!GetAttr(inst,attr,val))return false;
	val.Get(blobsrc);
	if(blobsrc.blobId==0){
		SetLastErrorWithFileInfo(APLAPIERR_INTEGRATED_BIN_NOT_FOUND);
		return false;
	}

	for(i=0;i<m_list_blob.GetSize();i++){
		blobval=m_list_blob.GetAt(i);
		if(blobsrc==*blobval){
			tempfile=blobval->tempFile;
			pos=blobval->filePosition;
			size=blobval->size;
			break;
		}
	}
	if(tempfile==0 && (pos==0 || size==0)){
		SetLastErrorWithFileInfo(APLAPIERR_INTEGRATED_BIN_NOT_FOUND);
		return false;
	}
	// копируем из файла в файл
	CFile file;
	CFile* file_src=0;
	CFileException pError;

	if(!file.Open(namefiledestination,CFile::modeWrite | CFile::modeCreate | CFile::shareDenyWrite,&pError)) 
	{
		if(pError.m_cause==CFileException::fileNotFound){
			//The file could not be located."
			SetLastErrorWithFileInfo(APLAPIERR_BADFILENAME); return false;
		}
		SetLastErrorWithFileInfo(APLAPIERR_FILE_IO); return false;
	}
	file.SeekToBegin();
	if(tempfile==0){
		// читаем из тела нашего файла
		if(pos+size+8>m_file.GetLength()){
			SetLastErrorWithFileInfo(APLAPIERR_INTEGRATED_BIN_BODY_NOT_FOUND); return false;
		}
		// проверяем заголовок 
		m_file.Seek(pos,CFile::begin);
		// id
		m_file.Read(&i,4);
		if(i!=blobsrc.blobId){
			SetLastErrorWithFileInfo(APLAPIERR_INTEGRATED_BIN_BODY_NOT_CORRECT); return false;
		}
		// size
		m_file.Read(&cur_size,4);
		if(cur_size!=size){
			SetLastErrorWithFileInfo(APLAPIERR_INTEGRATED_BIN_BODY_NOT_CORRECT); return false;
		}
		pos+=8;
		file_src=&m_file;
	}else{
		// читаем из временного файла
		tempfile->SeekToBegin();
		size=(DWORD)tempfile->GetLength();
		file_src=tempfile;
	}
	TCHAR *buf=new TCHAR[SIZE_PORTION_FILE_OPERATE];
#if defined(_DEBUG) && defined (_PUT_BLOB_2_FILE)
	CFile testfile;
	testfile.Open(_T("D:\\temp\\__\\2.2"),CFile::modeCreate|CFile::modeWrite);
#endif
	while(true){
		cur_size=SIZE_PORTION_FILE_OPERATE>size?size:SIZE_PORTION_FILE_OPERATE;
		if(cur_size!=file_src->Read(buf,cur_size)){
			delete[] buf;
			SetLastErrorWithFileInfo(APLAPIERR_FILE_IO); return false;
		}
		file.Write(buf,cur_size);
#if defined(_DEBUG) && defined (_PUT_BLOB_2_FILE)
		testfile.Write(buf,cur_size);
#endif
		pos+=cur_size;
		size-=cur_size;
		if(size==0)
			break;
	}
	file.Close();
#if defined(_DEBUG) && defined (_PUT_BLOB_2_FILE)
	testfile.Close();
#endif
	delete[] buf;

	return true;
}

void RemapAggrToNewDB_WF(aplExtent &instances,aplExtent &new_instances, CaplAggr &aggr)
{
	int i;
	int Range = aggr.GetSize();	
	int Reference;

	// Массив вложенный
	CaplValue *val;
	for ( i=0; i < Range; i++ )
	{
		val=aggr.GetByIndex(i);
		if(val==0) continue;
		if ( val->type == aplAGGR ) RemapAggrToNewDB_WF(instances,new_instances,*(val->aggrval));
		else if ( val->type == aplINSTANCE )
		{
			Reference = instances.Find(val->instval);
			if (Reference == -1) val->instval = 0;	// Instance не входит в набор
			else val->instval = new_instances[Reference];	// перекрестная ссылка
		}	
	}
};

void CaplStepDataWithFile::aplFarCopyInstances(aplExtent &instances, CaplStepDataWithFile &out_data, bool clear_data)
{
	long i, j, li_items_col, li_attr_col;

	CaplEntity * pEntityRef;			// Рабочие указатели
	CaplAttr * pAttrRef;	

	for(i=0;i<instances.GetSize();i++)
	{// Проверка на пустышки
		if(instances[i]==0)
		{
			instances.Remove(i);
			i--;
		}
	}
	li_items_col = instances.GetSize();
	if (li_items_col == 0) return;

	aplExtent new_inst;
	instances.Unique = false;
	new_inst.Unique=false;

	if(clear_data)
		out_data.ClearData();

	// Сначала копируем Instancы
	for (i = 0; i < li_items_col;  i++)		// По всем данным Inst-ам
	{
		pEntityRef = out_data.GetEntityBN( instances[i]->GetType()->name );	// Ссылка на тип Instance во втором StepData		
		new_inst.Add(out_data.CreateInstance( pEntityRef ));	// Добавили экземпляр
	}
			
	for (i = 0; i < li_items_col; i++)
	{
		if(new_inst[i]==0) continue;
		if(instances[i]->attrs==0) continue;
		// Копируем атрибуты и перекрестные ссылки :
		li_attr_col = instances[i]->GetType()->all_attrs.GetSize();				
		for (j = 0; j < li_attr_col; j++)	
		{	
			pAttrRef = out_data.GetAttrDefinition(new_inst[i]->GetType(), instances[i]->GetType()->all_attrs[j]->name );

			// Атрибут INSTANCE
			if ( instances[i]->attrs[j].value.type == aplINSTANCE )
			{
				int Reference = instances.Find(instances[i]->attrs[j].value.instval);
				if ( Reference == -1) out_data.PutAttr(new_inst[i], pAttrRef, (CaplInstance*)0); // ссылка за пределы массива instances
				else out_data.PutAttr(new_inst[i], pAttrRef, new_inst[ Reference ] );		// перекрестная ссылка
			}
			else if(instances[i]->attrs[j].value.type == aplINTEGRATEDBIN)
			{
				TCHAR* buf_path=new TCHAR[MAX_PATH];
				TCHAR* buf_name=new TCHAR[MAX_PATH];
				GetTempPath(MAX_PATH,buf_path);
				GetTempFileName(buf_path,_T("apl"),0,buf_name);
				CString tmp_file = buf_name;
				delete buf_path;
				delete buf_name;

				GetIntegratedBlob(instances[i],instances[i]->GetType()->all_attrs[j], tmp_file);
				out_data.PutIntegratedBlob(new_inst[i], pAttrRef, tmp_file);
				try{DeleteFile(tmp_file);}
				catch (...) {TRACE(APL_T("Ошибка при удалении файла\n"));}
//				out_data.GetIntegratedBlob(new_inst[i], pAttrRef, tmp_file);
			}
			else	
			{
				// Простой атрибут
				out_data.PutAttr(new_inst[i], pAttrRef, instances[i]->attrs[j].value);	// Присвоили значение
					// Атрибут AGGR
				if ( instances[i]->attrs[j].value.type == aplAGGR )	// Если атрибут - AGGR
				{
					RemapAggrToNewDB_WF(instances,new_inst,*(new_inst[i]->attrs[j].value.aggrval));
				}
			}			
		}

	}
}

//************************************************************************
CaplInstance  *CaplStepDataWithFile::CreateInstance(CaplEntity *entity,bool is_temporary,bool create_attrs)
{
//	CaplInstance *inst=CaplStepData::CreateInstance(entity,is_temporary,create_attrs);

	if (entity==0) {SetLastErrorWithFileInfo(APLAPIERR_BADENT); return 0;}
	if(m_is_readonly && !is_temporary){SetLastErrorWithFileInfo(APLAPIERR_MODE_READ_ONLY); return 0;}
	SetLastError(0);
	CaplInstance *inst=new CaplInstance(this,entity,0,create_attrs);
	if(inst==0) return 0;
	inst->SetTemporary(is_temporary);
	
	bool u=entity->instances.Unique;
	entity->instances.Unique=false;
	entity->instances.Add(inst);
	entity->instances.Unique=u;
	
	instances.Unique=false;
	instances.Add(inst);
	instances.Unique=true;


	if(inst!=0){inst->SetId(++m_MaxInstNum);}
	return inst;
}

CaplInstance  *CaplStepDataWithFile::CreateInstanceBN(const TCHAR *type_name,bool is_temporary,bool create_attrs)
{
	if (type_name==0) {SetLastErrorWithFileInfo(APLAPIERR_BADENT); return 0;}
	SetLastError(0);
	CaplEntity *ent=GetEntityBN(type_name);
	if (ent==0) {SetLastErrorWithFileInfo(APLAPIERR_BADENT); return 0;}
	return CreateInstance(ent,is_temporary,create_attrs);
}

