#include "stdafx.h"
#include <mlang.h>
#include <map>
#include <aplXML.h>
#include "apl_api.h"
#include "RequirementPropertiesDlg.h"
#include "RequirementPropertiesDlgEx.h"
#include "aplUsefullDefines.h"

#define CODEPAGE_Win_Cyrillic 1251
#define CODEPAGE_UTF_8 65001

typedef std::map<CString, CaplInstance*> TStrInstMap;
typedef TStrInstMap::iterator TStrInstMap_it;


void AddAttrrToLastRequirement(CaplAPI *api, CString &sText, CaplInstance **ciLastRequirement)
{
	CString sName;

	// получаем наименование
	int nDotIndex = sText.Find(_T('.'));
	if(nDotIndex == -1 || nDotIndex > 40) nDotIndex = sText.Find(_T('('));

	if(nDotIndex != -1) sName = sText.Left(nDotIndex);
	else sName = sText;

	// получаем текст
	sText.Delete(0, sName.GetLength());
	sText.Replace(_T("-"), _T(""));

	if(!sText.IsEmpty())
		if(sText[0] == _T('.')) 
			sText.Delete(0);			

	int nLenght = 100;
	for(int i=0, b=0; i<sText.GetLength(); i++, b++)
	{
		if(sText[i] == _T(' ') && b%nLenght > 0 && b>= nLenght)
		{
			b = 0;
		 	sText.Delete(i); 
			sText.Insert(i, _T('~'));
		}		
	}

	sText.Replace(_T("("), _T("<br>("));
	sText.Replace(_T("~"), _T("<br>"));
	if(sText.Left(4) == _T("<br>")) 
		sText.Delete(0, 4);

	api->m_data.PutAttr(*ciLastRequirement, api->m_req_mgr.a_req_html, sText);
	api->m_data.PutAttr(*ciLastRequirement, api->m_req_mgr.a_req_name, sName);

	*ciLastRequirement = NULL;
}

bool AllLettersUppear(CString str)
{
	for(int i=0; i<str.GetLength(); i++)
	{
		if(str[i] == _T(' ')) continue;
		if( !(str[i] >= _T('А') && str[i] <= _T('Я')) ) return false;
	}

	return true;
}

/************************************************************************/
/*                                                                      */
/************************************************************************/


bool CaplRequirementMgr::Attach(CaplAPI *api)
{
	if(api==0) {Detach();return false;}
	CaplStepManager::Attach(api);

	CHECK_ZERO_ATTR(e_requirement,                          m_data->GetEntityBN(_T("apl_requirement")));
	CHECK_ZERO_ATTR(a_req_state,                            m_data->GetAttrDefinition(e_requirement, _T("state")));
	CHECK_ZERO_ATTR(a_req_parent,                           m_data->GetAttrDefinition(e_requirement, _T("parent")));
	CHECK_ZERO_ATTR(a_req_root_parent,                      m_data->GetAttrDefinition(e_requirement, _T("root_parent")));
	CHECK_ZERO_ATTR(a_req_source,                           m_data->GetAttrDefinition(e_requirement, _T("source")));
	CHECK_ZERO_ATTR(a_req_id,                               m_data->GetAttrDefinition(e_requirement, _T("id")));
	CHECK_ZERO_ATTR(a_req_name,                             m_data->GetAttrDefinition(e_requirement, _T("name")));
	CHECK_ZERO_ATTR(a_req_html,                             m_data->GetAttrDefinition(e_requirement, _T("html")));
	CHECK_ZERO_ATTR(a_req_files,                            m_data->GetAttrDefinition(e_requirement, _T("files")));
	CHECK_ZERO_ATTR(a_req_no_need,                          m_data->GetAttrDefinition(e_requirement, _T("no_need")));
	CHECK_ZERO_ATTR(a_req_last_updated,                     m_data->GetAttrDefinition(e_requirement, _T("last_updated")));
	CHECK_ZERO_ATTR(a_req_updated_person,                   m_data->GetAttrDefinition(e_requirement, _T("updated_person")));
	CHECK_ZERO_ATTR(a_req_mos,                              m_data->GetAttrDefinition(e_requirement, _T("mos")));
	CHECK_ZERO_ATTR(a_req_executor,                         m_data->GetAttrDefinition(e_requirement, _T("executor")));
	CHECK_ZERO_ATTR(a_req_equivalence_date,                 m_data->GetAttrDefinition(e_requirement, _T("equivalence_date")));
	CHECK_ZERO_ATTR(a_req_pictures,							m_data->GetAttrDefinition(e_requirement, _T("pictures")));
	CHECK_ZERO_ATTR(a_req_developer,						m_data->GetAttrDefinition(e_requirement, _T("developer")));
	CHECK_ZERO_ATTR(a_req_vs,								m_data->GetAttrDefinition(e_requirement, _T("vs")));
	CHECK_ZERO_ATTR(a_req_wf_state,							m_data->GetAttrDefinition(e_requirement, _T("wf_state")));
	CHECK_ZERO_ATTR(a_req_notes,							m_data->GetAttrDefinition(e_requirement, _T("notes")));
	CHECK_ZERO_ATTR(a_req_cfg_oject,						m_data->GetAttrDefinition(e_requirement, _T("cfg_object")));

	CHECK_ZERO_ATTR(e_requirement_association,              m_data->GetEntityBN(_T("apl_requirement_association")));
	CHECK_ZERO_ATTR(a_req_assoc_item,                       m_data->GetAttrDefinition(e_requirement_association, _T("item")));
	CHECK_ZERO_ATTR(a_req_assoc_req,                        m_data->GetAttrDefinition(e_requirement_association, _T("requirement")));

	CHECK_ZERO_ATTR(e_requirement_stage,                       m_data->GetEntityBN(_T("apl_requirement_stage")));
	CHECK_ZERO_ATTR(a_req_stage_requirement,                   m_data->GetAttrDefinition(e_requirement_stage, _T("requirement")));
	CHECK_ZERO_ATTR(a_req_stage_mos,                           m_data->GetAttrDefinition(e_requirement_stage, _T("mos")));
	CHECK_ZERO_ATTR(a_req_stage_project,                       m_data->GetAttrDefinition(e_requirement_stage, _T("project")));	
	
	return true;
}

void CaplRequirementMgr::Detach()
{
	e_requirement = 0;
	a_req_state = 0;           
	a_req_parent = 0;          
	a_req_root_parent = 0;
	a_req_source = 0;          
	a_req_id = 0;              
	a_req_name = 0;            
	a_req_html = 0;            
	a_req_files = 0;           
	a_req_no_need = 0;         
	a_req_last_updated = 0;    
	a_req_updated_person = 0;  
	a_req_mos = 0;             
	a_req_executor = 0;        
	a_req_equivalence_date = 0;	
	a_req_pictures = 0;
	a_req_developer = 0;
	a_req_vs = 0;
	a_req_wf_state = 0;
	a_req_notes = 0 ;
	a_req_cfg_oject = 0;

	e_requirement_association = 0;
	a_req_assoc_item = 0;
	a_req_assoc_req = 0;
}

CString CaplRequirementMgr::GetInitialRequirementState()
{
	return _T("working");
}

bool CaplRequirementMgr::LoadReqInfo(CaplInstance *ciRequirement, bool bLoadDocuments)
{
	bad_api_return_bool;
	bad_instance_return_bool(ciRequirement);
	not_requirement_return_bool(ciRequirement);

	aplExtent aeItems;
	aeItems.Add(ciRequirement);

	return LoadReqInfo(aeItems, bLoadDocuments);
}

bool CaplRequirementMgr::LoadReqInfo(aplExtent &aeItems, bool bLoadDocuments)
{
	bad_api_return_bool;
	if(!aeItems.Size) return false;

	int nCount = 0;
	aplExtent aeDocs, aeRels;
	CaplLoadData ld(&m_api->m_data, DEF_SOURCE);

	// загружаем все атрибуты требований и сопутствующих ей объектов
	for(int i=0; i<aeItems.Size; i++) 
	{
		if(!aeItems[i]->GetType()) continue;

		nCount++;
		ld.AddQuery(0, aeItems[i], true);

		if(nCount==m_MaxItemsLoad || i==(aeItems.Size-1))
		{
			ld.AddQuery(_T('d'), 0, m_api->m_req_mgr.e_requirement,   m_api->m_req_mgr.a_req_pictures, true, true);
			ld.AddQuery(_T('d'), 0, m_api->m_req_mgr.e_requirement,   m_api->m_req_mgr.a_req_root_parent, true, true);
			ld.AddQuery(_T('d'), 0, m_api->m_req_mgr.e_requirement,   m_api->m_req_mgr.a_req_parent, true, true);

			ld.LoadEx(true, NULL);
			nCount = 0;
		}
	}	

	// загружаем документы
	if(bLoadDocuments) m_api->m_doc_mgr.FindAssociatedDocuments(aeItems, aeDocs, aeRels);

	return true;
}

bool CaplRequirementMgr::LoadRequirementId(CaplInstance *ciRequirement)
{
	bad_api_return_bool;
	bad_instance_return_bool(ciRequirement);
	not_requirement_return_bool(ciRequirement);

	aplExtent aeItems;
	aeItems.Add(ciRequirement);

	return LoadRequirementId(aeItems);
}

bool CaplRequirementMgr::LoadRequirementId(aplExtent &aeItems)
{
	bad_api_return_bool;
	if(!aeItems.Size) return false;

	int nCount = 0;
	CaplLoadData ld(&m_api->m_data, DEF_SOURCE);

	// загружаем всю информацию о требованиях
	for(int i=0; i<aeItems.Size; i++) 
	{
		if(!aeItems[i]->GetType()) continue;

		nCount++;
		ld.AddQuery(0, aeItems[i], false);

		if(nCount==m_MaxItemsLoad || i==(aeItems.Size-1))
		{
			ld.AddQuery(_T('d'), 0, m_api->m_req_mgr.e_requirement,   m_api->m_req_mgr.a_req_id, true, true);
			ld.LoadEx(true, NULL);
			nCount = 0;
		}
	}	

	return true;
}

bool CaplRequirementMgr::ShowProperties(CaplInstance *ciRequirement)
{
	bad_api_return_bool;
	bad_person_return_bool;
	bad_instance_return_bool(ciRequirement);
	not_requirement_return_bool(ciRequirement);

	CaplInstance *ciParent = 0;	
	m_api->m_data.GetAttr(ciRequirement, a_req_parent, ciParent);

	if(!ShowPropertiesDialog(ciRequirement, ciParent, CString(""), CString(""))) 
		return false;	
	else 
		return true;
}

CaplInstance* CaplRequirementMgr::ShowPropertiesDialog(CaplInstance *ciRequirement, CaplInstance *ciParent, CString &sVS, CString &sDeveloper)
{
	CaplSetResourceHandle setres(module_inst);

	CRequirementPropertiesDlg *dlg = 0;
	CRequirementPropertiesDlg dlgCommon(m_api, ciRequirement, ciParent);
	CRequirementPropertiesDlgEx dlgEx(m_api, ciRequirement, ciParent);
	
	if(m_api->m_options_mgr.CheckInstallCode(_T("sukhoi")))
	{
		dlg = &dlgEx;
	}
	else
	{
		dlg = &dlgCommon;
	}
	
	dlg->m_sVS = sVS; 
	dlg->m_sDeveloper = sDeveloper;

	int nResult = dlg->DoModal();
	if(nResult != IDOK)
		return 0;
	else
		return dlg->m_ciReq;
}

CaplInstance* CaplRequirementMgr::CreateRequirement(CaplInstance *ciParent /* = 0 */)
{
	bad_api_return_inst;
	bad_person_return_inst;

	CString sVS, sDeveloper;
	if(ciParent)
	{
		m_api->m_data.GetAttr(ciParent, a_req_vs, sVS);
		m_api->m_data.GetAttr(ciParent, a_req_developer, sDeveloper);
	}

	CaplInstance *ciReq = ShowPropertiesDialog(0, ciParent, sVS, sDeveloper);		
	if(0 == ciReq) 
		return 0;

	// привязываем новое к старому (если старое было =))
	if(ciParent) AddChild(ciParent, ciReq);
	if(m_AutoSave) m_api->SaveChanges();

	return ciReq;
}

CaplInstance* CaplRequirementMgr::AddChild(CaplInstance *ciParent, CaplInstance *ciChild)
{
	bad_api_return_inst;
	bad_instance_return_inst(ciChild);

	CaplInstance *ciRoot = 0, *ciTmpParent = 0;
	CString sDeveloper, sVS;
	
	m_api->m_data.GetAttr(ciChild, a_req_parent, ciTmpParent);
	m_api->m_data.PutAttr(ciChild, a_req_parent, ciParent);

	m_api->m_data.GetAttr(ciParent, a_req_vs, sVS);
	m_api->m_data.GetAttr(ciParent, a_req_developer, sDeveloper);
	m_api->m_data.PutAttr(ciChild, a_req_vs, sVS);
	m_api->m_data.PutAttr(ciChild, a_req_developer, sDeveloper);

	// ищем самую верхушку
	if(ciParent)
	{
		while(true)
		{
			m_api->m_data.GetAttr(ciParent, a_req_parent, ciRoot);
			if(ciRoot == ciChild) 
			{
				m_api->m_data.PutAttr(ciChild, a_req_parent, ciTmpParent);
				return 0;
			}

			if(ciRoot)
			{
				ciParent = ciRoot;
				continue;
			}

			m_api->m_data.PutAttr(ciChild, a_req_root_parent, ciParent);
			break;
		}
	}
	else
	{
		ciParent = ciChild;
	}

	return ciParent;
}

bool CaplRequirementMgr::DeleteRequirement(CaplInstance *ciRequirement, bool bShowMsg, bool bSaveChanges)
{
	bad_api_return_bool;
	bad_person_return_bool;
	bad_instance_return_bool(ciRequirement);
	not_requirement_return_bool(ciRequirement);

	int i;
	long dID;
	CString msg;
	int nCount = 0;
	aplExtent aeAssoc, aeTmp;
	CaplLoadData ld(&m_api->m_data,DEF_SOURCE);
	aplExtent aeExtToDel, aeParent;

	// удаляем само требование
	aeExtToDel.Add(ciRequirement);

	if(m_api->m_ModeInteractive && bShowMsg)
	{
		// а может и все чалдовые
		if(RequirementHasChild(ciRequirement)) 
		{
			msg =  APL_T("Требование содержит вложенные элементы. Удалить все требования рекурсивно?");
			aeParent.Add(ciRequirement);			
		}
		else
		{
			msg =  APL_T("Удалить требование?");			
		}

		if(AfxMessageBox(msg, MB_ICONSTOP|MB_YESNO) == IDNO) return false;
		if(aeParent.Size) 
		{
			dID = aplStartWaitDlg( APL_T("Поиск входящих элементов..."));
			GetChildsRecursiveFromBase(aeParent, aeExtToDel, true);
			aplEndWaitDlg(dID);
		}
	}

	dID = aplStartWaitDlg( APL_T("Поиск связей..."));
	for(i=0; i<aeExtToDel.Size; i++) 
	{
		if(!aeExtToDel[i]->GetType()) continue;

		nCount++;
		ld.AddQuery(0, aeExtToDel[i], true);

		if(nCount==m_MaxItemsLoad || i==(aeExtToDel.Size-1))
		{
			ld.AddQuery(_T('r'), 0, e_requirement_association,   a_req_assoc_req, true, true);
			ld.LoadEx(true, &aeTmp);

			// выбираем только нужное
			for(int j=0; j<aeTmp.Size; j++)
			{
				if(m_api->m_data.IsKindOf(aeTmp[j], e_requirement_association))
					aeAssoc.Add(aeTmp[j]);
			}
			
			nCount = 0;
			aeTmp.Clear();
		}
	}	
	aplEndWaitDlg(dID);

	dID = aplStartWaitDlg( APL_T("Удаление элементов..."));
	for(i=0; i<aeExtToDel.Size; i++)
		m_api->m_data.DeleteInstance(aeExtToDel[i]);
	aplEndWaitDlg(dID);

	dID = aplStartWaitDlg( APL_T("Удаление связей..."));
	for(i=0; i<aeAssoc.Size; i++)
		m_api->m_data.DeleteInstance(aeAssoc[i]);
	aplEndWaitDlg(dID);

	if(bSaveChanges) m_api->SaveChanges();

	return true;
}

bool CaplRequirementMgr::MoveRequirement(CaplInstance *ciMoved, CaplInstance *ciTo)
{
	bad_api_return_bool;
	bad_person_return_bool;
	bad_instance_return_bool(ciMoved);
	not_requirement_return_bool(ciMoved);
	
	// для всех чайлдовых элементов ciMoved нужно переставить RootParent на новый
	CaplInstance *ciOldRoot = 0;
	m_api->m_data.GetAttr(ciMoved, a_req_root_parent, ciOldRoot);

	// хм...рутового элемента не задано...странно...ладно, берем парента
	if(!ciOldRoot)
		m_api->m_data.GetAttr(ciMoved, a_req_parent, ciOldRoot);

	// и парента тоже нет =)) ну тогда парентом и будет ciMoved
	if(!ciOldRoot) //-V581
		ciOldRoot = ciMoved;

	// переставляем связи и узнаем новый рутовый элемент
	CaplInstance *ciNewRoot = AddChild(ciTo, ciMoved);	
	if(!ciNewRoot)
	{
		if(m_api->m_ModeInteractive)
			AfxMessageBox( APL_T("Перенос невозможен.\nВозможно образуется повтор или зацикливание связей."), MB_ICONSTOP);

		return false;
	}

	// берем все чалдовые
	CString sSql;
	aplExtent aeItems;

	sSql.Format(_T("SELECT Ext_1 FROM Ext_1 { apl_requirement.root_parent = #%d } END_SELECT"), ciOldRoot->GetId());
	m_api->m_data.NET_QueryEditParse(sSql);
	m_api->m_data.NET_QueryExecute(aeItems);

	// переставляем связи
	for(int i=0; i<aeItems.Size; i++)
		m_api->m_data.PutAttr(aeItems[i], a_req_root_parent, ciNewRoot);

	return true;
}

bool CaplRequirementMgr::RequirementHasChild(CaplInstance *ciRequirement)
{	
	bad_api_return_bool;
	bad_instance_return_bool(ciRequirement);
	not_requirement_return_bool(ciRequirement);

	// берем все чалдовые
	CString sSql;
	aplExtent aeItems;

	sSql.Format(_T("SELECT Ext_1 FROM Ext_1 { apl_requirement.parent = #%d } END_SELECT"), ciRequirement->GetId());
	m_api->m_data.NET_QueryEditParse(sSql);
	m_api->m_data.NET_QueryExecute(aeItems);

	if(aeItems.Size) return true;
	else return false;
}

bool CaplRequirementMgr::SetAttrForChilds(CaplInstance *ciReq)
{
	bad_api_return_bool;
	bad_instance_return_bool(ciReq);

	long dID;
	aplExtent aeChild;
	CString sDeveloper, sVS;
	
	dID = aplStartWaitDlg( APL_T("Установка атрибутов для дочерних требований..."));
	LoadChildsFromBase(ciReq, aeChild, true);
		
	m_api->m_data.GetAttr(ciReq, a_req_developer, sDeveloper);
	m_api->m_data.GetAttr(ciReq, a_req_vs, sVS);

	for(int i=0; i<aeChild.Size; ++i)
	{
		if(aeChild[i]->GetType() == 0) continue;

		m_api->m_data.PutAttr(aeChild[i], a_req_developer, sDeveloper);
		m_api->m_data.PutAttr(aeChild[i], a_req_vs, sVS);
	}

	aplEndWaitDlg(dID);
	return true;
}

bool CaplRequirementMgr::IsRequirementUniqueId(CaplInstance *ciParent, CaplInstance *ciRequirement, CString sId)
{
	bad_api_return_bool;
	bad_instance_return_bool(ciParent);
	if(sId.IsEmpty()) return false;
	
	CString sSql, buf;
	aplExtent aeItems;
	CaplInstance *ciRoot;

	m_api->m_data.GetAttr(ciParent, a_req_root_parent, ciRoot);
	if(!ciRoot) ciRoot = ciParent;

	// берем все чалдовые + корневой
	LoadChildsFromBase(ciParent, aeItems, false);
	aeItems.Add(ciParent);

// 	для всех грузим обозначения
// 		LoadRequirementId(aeItems);

	// проходим, сравниваем
	for(int i=0; i<aeItems.Size; i++)
	{
		if(ciRequirement == aeItems[i] && ciRequirement) continue;

		m_api->m_data.GetAttr(aeItems[i], a_req_id, buf);
		if(buf == sId) return false;
	}

	return true;	
}

bool CaplRequirementMgr::SubstituteImgReferencesWithFilesNames(CString &html, CStringArray &saImgReferences)
{
	saImgReferences.RemoveAll();

	CString sSRC = _T("src=\"");
	CString srcName, fileName;
	int nIndex = 0, nCount = 1;

	while(true)
	{
		int nIndexFind = html.Find(sSRC, nIndex);
		if(nIndexFind == -1) break;

		// новое имя будущего файла
		fileName.Format(_T("Image%d"), nCount++);

		// находим начало ссылки на файл
		int nLastQuoteIndex = html.Find(_T("\""), nIndexFind + sSRC.GetLength());

		// получаем значение ссылки изображения
		srcName = html.Mid(nIndexFind + sSRC.GetLength(), nLastQuoteIndex - nIndexFind - sSRC.GetLength());		

		// запоминаем комбинацию старого и нового
		saImgReferences.Add(srcName);
		saImgReferences.Add(fileName);

		// удаляем ссылку
		html.Delete(nIndexFind + sSRC.GetLength(), nLastQuoteIndex - nIndexFind - sSRC.GetLength());

		// и подменяем ее на имя файла		
		html.Insert(nIndexFind + sSRC.GetLength(), fileName);

		// двигаемся дальше
		nIndex = nIndexFind + sSRC.GetLength() + fileName.GetLength();		
	}

	return true;
}

bool CaplRequirementMgr::CreateFilesByBlobs(CaplInstance *ciReq, CString sPath, CStringArray &saBlobsAndFileNames)
{
	bad_api_return_bool;
	bad_instance_return_bool(ciReq);

	aplExtent aePictures;
	CString sBlob, sFileName, sSource;
	CaplInstance *ciPicture = 0;

	// набор картинок требования
	m_api->m_data.GetAttr(ciReq, a_req_pictures, aePictures);
	m_api->LoadExtentInfo(aePictures);

	for(int i=0; i<saBlobsAndFileNames.GetSize(); i+=2)
	{
		ciPicture = 0;
		sBlob = saBlobsAndFileNames[i];
		sFileName = saBlobsAndFileNames[i+1];

		for(int j=0; j<aePictures.Size; j++)
		{
			m_api->m_data.GetAttr(aePictures[j], m_api->m_doc_mgr.a_apl_stored_document_source, sSource);
			if(sSource == sBlob)
			{
				ciPicture = aePictures[j];
				break;
			}
		}

		if(ciPicture)
			m_api->m_data.NET_LoadBlob(ciPicture, m_api->m_doc_mgr.a_apl_stored_document_source, sPath+sFileName);		
	}
	
	return true;
}

bool CaplRequirementMgr::ReplaceReferenceInHTML(CString &html, CString oldSource, CString newSource)
{
	if(html.IsEmpty()) return false;
	if(oldSource.IsEmpty()) return false;
	if(newSource.IsEmpty()) return false;
	
	int nIndex = 0;
	CString fileName;
	CString sSRC = _T("src=\"");

	while(true)
	{
		int nIndexFind = html.Find(sSRC, nIndex);
		if(nIndexFind == -1) break;

		// находим начало ссылки на файл
		int nLastQuoteIndex = html.Find(_T("\""), nIndexFind + sSRC.GetLength());

		// получаем адрес файла
		fileName = html.Mid(nIndexFind + sSRC.GetLength(), nLastQuoteIndex - nIndexFind - sSRC.GetLength());

		// смотрим, может такой файл уже был
		if(fileName == oldSource)
		{
			// удаляем старое имя файла
			html.Delete(nIndexFind + sSRC.GetLength(), nLastQuoteIndex - nIndexFind - sSRC.GetLength());

			// и подменяем его на номер блоба
			html.Insert(nIndexFind + sSRC.GetLength(), newSource);

			// двигаемся дальше
			nIndex = nIndexFind + sSRC.GetLength() + newSource.GetLength();
		}
		else
		{
			nIndex = nLastQuoteIndex+1;
		}
	}

	return true;
}

CaplInstance* CaplRequirementMgr::CreateRequirementInderect(CaplInstance *ciParent, CString id, CString name, CString html)
{
	bad_api_return_inst;
	if(id.IsEmpty()) return 0;

	CaplInstance *ciRoot = 0;
	CaplInstance *ciRequirement = m_api->m_data.CreateInstance(m_api->m_req_mgr.e_requirement);
	if(!ciRequirement) return 0;

	if(ciParent)
	{
		m_api->m_data.GetAttr(ciParent, a_req_root_parent, ciRoot);
		if(!ciRoot) ciRoot = ciParent;
	}

	//CString sText;
	//GetUnformattedTextFromHTML(sText, html);

	m_api->m_data.PutAttr(ciRequirement, a_req_html, html);
	m_api->m_data.PutAttr(ciRequirement, a_req_id, id);
	m_api->m_data.PutAttr(ciRequirement, a_req_name, name);
	m_api->m_data.PutAttr(ciRequirement, a_req_parent, ciParent);
	m_api->m_data.PutAttr(ciRequirement, a_req_root_parent, ciRoot);
	m_api->m_data.PutAttr(ciRequirement, a_req_mos, _T("0"));
	m_api->m_data.PutAttr(ciRequirement, a_req_no_need, false);
	m_api->m_data.PutAttr(ciRequirement, a_req_wf_state, GetInitialRequirementState());

	return ciRequirement;
}

CString CaplRequirementMgr::GetFilePath(BOOL open, CString sExtension, CString sFilter)
{
	CFileDialog dlg(open, sExtension, _T(""), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, sFilter);

	if (dlg.DoModal() != IDOK)
		return _T("");

	return dlg.GetPathName();
}

CaplInstance* CaplRequirementMgr::CreateRequirementCopy(CaplInstance *ciRequirement)
{
	bad_api_return_inst;
	bad_instance_return_inst(ciRequirement);
	not_requirement_return_inst(ciRequirement);

	// создаем 
	CaplInstance *ciNewReq = m_api->m_data.CreateInstance(e_requirement);
	if(!ciNewReq) return 0;

	bool bAttr;
	CString strAttr;
	aplExtent extAttr;
	CaplInstance *ciAttr;
	CaplInstance *ciNullInst = 0;

	// некоторые атрибуты копируем
	m_api->m_data.GetAttr(ciRequirement, a_req_state, strAttr);
	m_api->m_data.PutAttr(ciNewReq, a_req_state, strAttr);

	m_api->m_data.GetAttr(ciRequirement, a_req_id, strAttr);
	m_api->m_data.PutAttr(ciNewReq, a_req_id, strAttr);

	m_api->m_data.GetAttr(ciRequirement, a_req_name, strAttr);
	m_api->m_data.PutAttr(ciNewReq, a_req_name, strAttr);

	m_api->m_data.GetAttr(ciRequirement, a_req_html, strAttr);
	m_api->m_data.PutAttr(ciNewReq, a_req_html, strAttr);

	m_api->m_data.GetAttr(ciRequirement, a_req_no_need, bAttr);
	m_api->m_data.PutAttr(ciNewReq, a_req_no_need, bAttr);

	m_api->m_data.GetAttr(ciRequirement, a_req_mos, strAttr);
	m_api->m_data.PutAttr(ciNewReq, a_req_mos, strAttr);

	m_api->m_data.GetAttr(ciRequirement, a_req_executor, ciAttr);
	m_api->m_data.PutAttr(ciNewReq, a_req_executor, ciAttr);

	m_api->m_data.GetAttr(ciRequirement, a_req_notes, strAttr);
	m_api->m_data.PutAttr(ciNewReq, a_req_notes, strAttr);

	m_api->m_data.GetAttr(ciRequirement, a_req_equivalence_date, strAttr);
	m_api->m_data.PutAttr(ciNewReq, a_req_equivalence_date, strAttr);

	m_api->m_data.GetAttr(ciRequirement, a_req_pictures, extAttr);
	m_api->m_data.PutAttr(ciNewReq, a_req_pictures, extAttr);

	// некоторые атрибуты задаем новые
	aplDate2String(COleDateTime::GetCurrentTime(), strAttr);
	m_api->m_data.PutAttr(ciNewReq, a_req_last_updated, strAttr);

	ciAttr = m_api->m_appr_mgr.GetCurrentPerson();
	m_api->m_data.PutAttr(ciNewReq, a_req_updated_person, ciAttr);

	m_api->m_data.PutAttr(ciNewReq, a_req_source, ciRequirement);

	m_api->m_data.PutAttr(ciNewReq, a_req_wf_state, GetInitialRequirementState());

	return ciNewReq;
}

void CaplRequirementMgr::GetChildsRecursiveFromBase(aplExtent &aeParents, aplExtent &aeChild, bool bRecursive)
{
	int i;
	aplExtent aeTmp, aeResult;
	CaplLoadData ld(&m_api->m_data, DEF_SOURCE);

	// готовим запрос
	aeParents.Sort();
	for(i=0; i<aeParents.Size; i++)
		ld.AddQuery(0, aeParents[i]);
	
	// выполняем запрос
	ld.AddQuery(_T('r'), 0, e_requirement, a_req_parent, true, true);
	ld.LoadEx(true, &aeTmp);

	LoadReqInfo(aeTmp);
	GetChildsRecursiveFromCash(aeParents, aeResult, false);

	aeChild.Append(aeResult);
	if(!bRecursive) return;

	// если нужно - идем глуюже
	if(aeResult.Size) GetChildsRecursiveFromBase(aeResult, aeChild, bRecursive);	
}

void CaplRequirementMgr::LoadChildsFromBase(CaplInstance *ciRequirement, aplExtent &aeChild, bool bRecursive)
{
	bad_api_return_void;
	bad_instance_return_void(ciRequirement);
	not_requirement_return_void(ciRequirement);

	aplExtent aeParents;
	aeParents.Add(ciRequirement);

	GetChildsRecursiveFromBase(aeParents, aeChild, bRecursive);		
}

void CaplRequirementMgr::LoadChildsFromCash(CaplInstance *ciRequirement, aplExtent &aeChild, bool bRecursive)
{
	bad_api_return_void;
	bad_instance_return_void(ciRequirement);
	not_requirement_return_void(ciRequirement);
		
	aplExtent aeParents;
	aeParents.Add(ciRequirement);
	GetChildsRecursiveFromCash(aeParents, aeChild, bRecursive);		
}

void CaplRequirementMgr::GetChildsRecursiveFromCash(aplExtent &aeParents, aplExtent &aeChild, bool bRecursive)
{
	CaplInstance *ciParent;
	aplExtent aeReq, aeTmp;

	aeParents.Sort();
	m_api->m_data.GetEntityExtent(e_requirement, aeReq);

	for(int i=0; i<aeReq.Size; i++)
	{
		m_api->m_data.GetAttr(aeReq[i], a_req_parent, ciParent);

		if(!ciParent) continue;
		if(aplQFindInstIdInExtent(aeParents, ciParent->GetId()) > -1) aeTmp.Add(aeReq[i]);
	}

	aeChild.Append(aeTmp);

	if(!bRecursive) return;
	GetChildsRecursiveFromCash(aeTmp, aeChild, bRecursive);
}

void CaplRequirementMgr::CopyRequirementsRecursive(CaplInstance *ciParent, CaplInstance *ciParentCopy, CaplInstance *ciSource)
{
	aplExtent aeChild;
	LoadChildsFromBase(ciParent, aeChild, false);

	for(int i=0; i<aeChild.Size; i++)
	{
		if(aeChild[i]->GetId() == 0) continue;

		CaplInstance *ciRequirementCopy = CreateRequirementCopy(aeChild[i]);
		m_api->m_data.PutAttr(ciRequirementCopy, a_req_source, ciSource);

		AddChild(ciParentCopy, ciRequirementCopy);
		CopyRequirementsRecursive(aeChild[i], ciRequirementCopy, ciSource);
	}	
}


bool CaplRequirementMgr::DeleteAllRequirementFromBase()
{
	bad_api_return_bool;

	CString sSql;
	aplExtent aeItems;

	// получаем все связанные
	sSql.Format(_T("SELECT Ext_1 FROM Ext_1 { apl_requirement} END_SELECT"));
	m_api->m_data.NET_QueryEditParse(sSql);
	m_api->m_data.NET_QueryExecute(aeItems);

	for(int i=0; i<aeItems.Size; i++)
		DeleteRequirement(aeItems[i], false, false);

	if(m_AutoSave) m_api->SaveChanges();
	return true;
}

bool CaplRequirementMgr::ImportRequirementsFromXMLword2003(aplExtent &aeRootItems, CString sPath, CaplInstance *ciParent)
{
	bad_api_return_bool;
	get_file_path_open(sPath, _T("xml"),  APL_T("Файлы XML (*.xml)|*.xml||"));

	// загружаем файл и находим таблицу с требованимями
	long dID;
	CaplXMLFile file;

	dID = aplStartWaitDlg( APL_T("Чтение файла..."));
	bool bRes = file.LoadFromFile(sPath);
	aplEndWaitDlg(dID);
	if(!bRes) return false;

	CaplXMLNode *nodeTable = file.root.FindSingleNodeBN(_T("w:tbl"));
	if(!nodeTable) return false;

	// проходим по таблице и создаем сущности
	bool bRoot;
	CaplInstance *ciLastParent = 0;
	TStrInstMap mapParents;
	TStrInstMap_it Iter;
	CString sValue, html, id, notes, name, prevHTML;

	dID = aplStartWaitDlg( APL_T("Импорт требований из XML..."));
	for(int i=0; i<nodeTable->subnodes.GetSize(); i++)
	{
		id=_T("");
		name=_T("");
		html=_T("");

		// идем по строкам
		CaplXMLNode *nodeRow = nodeTable->subnodes[i];
		if(nodeRow->name != _T("w:tr")) continue;

		int col = 0;
		for(int j=0; j<nodeRow->subnodes.GetSize(); j++)
		{
			// идем по столбцам
			CaplXMLNode *nodeTC = nodeRow->subnodes[j];
			if(nodeTC->name != _T("w:tc")) continue;

			CaplXMLNode *nodeWP = nodeTC->FindSingleNodeBN(_T("w:p"));
			{
				for(int a=0; a<nodeWP->subnodes.GetSize(); a++)
				{
					CaplXMLNode *nodeWR = nodeWP->subnodes[a];
					if(nodeWR->name != _T("w:r")) continue;

					CaplXMLNode *nodeWT = nodeWR->FindSingleNodeBN(_T("w:t"));
					if(!nodeWT) continue;

					// переводим в нужную кодирвку
					sValue += ConvertFromUTF8toWIN1251(nodeWT->text);
				}
			}

			// запоминаем
			if(col == 0) id = sValue;
			if(col == 1) html = sValue;
			if(col == 2) { notes = sValue; notes.MakeLower(); }

			col++;	
			sValue=_T("");
		}

		// пустышки пропускаем
		if(html.IsEmpty() || col==1) continue;
		if(id.Find(_T('№')) > -1) continue;
		id.Remove(_T(' '));

		// корректируем обозначение
		id.Replace(_T('с'), _T('c')); id.Replace(_T('С'), _T('C'));
		id.Replace(_T('к'), _T('k')); id.Replace(_T('К'), _T('K'));
		id.Replace(_T('а'), _T('a')); id.Replace(_T('А'), _T('A'));

		// обнуляем указатель
		Iter = mapParents.end();

		// ищем родительское требование
		if(!id.IsEmpty() && id.Find(_T('.')) > -1) 
		{
			// весь накопленный текст помещеаем в предыдущее требование
			if(ciLastParent)	
			{
				// устанавливаем межстрочный интервал
				prevHTML = _T("<DIV Style='LINE-HEIGHT:1'>") + prevHTML + _T("</DIV>");
				m_api->m_data.PutAttr(ciLastParent, a_req_html, prevHTML);
				prevHTML=_T("");
			}

			// из html вычленяем первое предожение, это будет наименование требования
			int nDotInd = html.Find(_T('.'));
			if(nDotInd == -1) { name = html; html=_T(""); } 
			else { name = html.Left(nDotInd+1); html.Replace(name, _T("")); }

			// из 2.52. делаем 2.52
			CString sParentId = id.Left( id.GetLength()-1 );

			// из 2.52 делаем 2.
			sParentId = sParentId.Left( sParentId.ReverseFind(_T('.')) + 1 );

			// ищем родителя			
			if(!sParentId.IsEmpty())
				Iter = mapParents.find(sParentId);

			if(Iter == mapParents.end()) 
			{
				bRoot = true;
				ciLastParent = ciParent;
			}
			else 
			{
				bRoot = false;
				ciLastParent = Iter->second;			
			}			

			// создаем сущность
			CaplInstance *ciRequirement = CreateRequirementInderect(ciLastParent, id, name, html);
			if(notes ==  APL_T("не требуется") || notes ==  APL_T("не относится"))
				m_api->m_data.PutAttr(ciRequirement, a_req_no_need, true);

			// запоминаем нового родителя
			if(bRoot) aeRootItems.Add(ciRequirement);			
			ciLastParent = ciRequirement;

			// добавляем нового родителя
			mapParents.insert(std::make_pair(id, ciRequirement));

			prevHTML += html;
		}
		else
		{			
			if(!prevHTML.IsEmpty()) prevHTML += _T("<br><br>");
			prevHTML +=  id + _T("  ") + html;			
		}				
	}	

	m_api->SaveChanges();
	aplEndWaitDlg(dID);

	AfxMessageBox( APL_T("Данные успешно импортированы."), MB_ICONINFORMATION);
	return true; 
}

CString CaplRequirementMgr::ConvertFromUTF8toWIN1251(CString sSource)
{
	IMultiLanguage *pMultiLanguage;
	IMLangConvertCharset* convertCharset;
	UINT sizeT = 0; 
	UINT sizeS = sSource.GetLength();
	CString sTarget;

	CoInitialize(NULL);
	HRESULT hr = CoCreateInstance(CLSID_CMultiLanguage, NULL,  CLSCTX_INPROC_SERVER, IID_IMultiLanguage, (void**)&pMultiLanguage);
	if (hr == S_OK)
	{
		hr = pMultiLanguage->CreateConvertCharset(CODEPAGE_UTF_8, CODEPAGE_Win_Cyrillic, MLCONVCHARF_NCR_ENTITIZE, &convertCharset);
		if (hr == S_OK)
		{
			// вычисление размера результата
			convertCharset->DoConversion((BYTE*)sSource.GetBuffer(), &sizeS, NULL, &sizeT); 
			sTarget.GetBufferSetLength(sizeT);

			// сама перекодировка
			convertCharset->DoConversion((BYTE*)sSource.GetBuffer(), &sizeS, (BYTE*)sTarget.GetBuffer(), &sizeT); 
		}
	}

	CoUninitialize();
	return sTarget;
}

bool CaplRequirementMgr::GetUnformattedTextFromHTML( CString &sText, CString sHTML )
{
	sText=_T("");
	if(sHTML.IsEmpty()) return false;

	bool bImageInHTML = false;
	if(sHTML.Find(_T("<img")) > -1) bImageInHTML = true;
	if(sHTML.Find(_T("<IMG")) > -1) bImageInHTML = true;

	int nBodyOpen = sHTML.Find(_T("<BODY>"));
	if(nBodyOpen != -1)
	{
		int nBodyClose = sHTML.Find(_T("</BODY>"));
		if(nBodyClose == -1) return false;

		sText = sHTML.Mid(nBodyOpen, nBodyClose - nBodyOpen);
	}
	else
	{
		sText = sHTML;
	}

	// удалем служебные символы
	sText.Remove(_T('\r'));
	sText.Remove(_T('\n'));
	sText.Replace(_T("&nbsp;"), _T(""));

	// удаляем теги
	while(true)
	{
		// находим открывающийся тег
		int nIndexFindOpen = sText.Find(_T("<"));
		if(nIndexFindOpen == -1) break;

		// находим закрывающийся тег
		int nIndexFindClose = sText.Find(_T(">"), nIndexFindOpen);
		if(nIndexFindClose == -1) break;

		// удаляем тег
		sText.Delete(nIndexFindOpen, nIndexFindClose - nIndexFindOpen + 1);		
	}

	if(!sText.IsEmpty()) return true;
	else if(bImageInHTML) return true;
	else return false;
}

CString CaplRequirementMgr::ConvertForRequirementSort( CString str )
{
	int def = 6;
	CString tmp, zeros;
	CString oldStr(str), newStr;

	for(int i=0; i<str.GetLength(); i++)
	{
		if(str[i] == _T('.') || (i == str.GetLength()-1) && str[i] != _T('.'))
		{
			if(i == str.GetLength()-1 && str[i] != _T('.')) 
				tmp += str[i];

			// добавляем нули в конец// или начало
			zeros = _T("");
			for(int j=tmp.GetLength(); j<def; j++) 
				zeros+=_T("0");
			newStr += zeros+tmp;
			tmp = _T("");
		}
		else
		{
			tmp += str[i];
		}
	}

	str = newStr;
	return str;
}

// Функция ЯАИ
bool CaplRequirementMgr::ImportAP25FromTxt(aplExtent &aeRootItems, CaplInstance *ciRequirement, CString sPath)
{
	bad_api_return_bool;
	bad_instance_return_bool(ciRequirement);
	not_requirement_return_bool(ciRequirement);
	//get_file_path_open(sPath, _T("txt"),  APL_T("Текстовые файлы (*.txt)|*.txt||"));

	sPath=_T("C:\\MY_TEMP\\AP_25-2.txt"); 

	CStdioFile file;
	if(!file.Open(sPath, CFile::modeRead)) 
	{
		AfxMessageBox( APL_T("Не удалось открыть файл!"), MB_ICONSTOP);
		return false;
	}

	int i,j;
	CString id, name, text, buf, buf0, sString;

	CaplStrMap strmap;

	CaplInstance *curReq=0,*curReqRazd=0;

	// читаем содержимое файла
	BOOL bResult = TRUE;
	while(bResult)
	{
		bResult = file.ReadString(sString);
		sString.TrimLeft();
		if(sString.IsEmpty()) continue;		

		
		i=sString.Find(_T(' '));
		if(i>0) id=sString.Left(i); else id=sString;

		buf=id;
		buf.MakeLower();

		if(buf==APL_T("раздел") || buf==APL_T("приложение") || buf==APL_T("дополнение"))
		{
			if(text!=_T(""))
			{
				if(curReq!=0) m_api->m_data.PutAttr(curReq, a_req_html, text);
				text=_T("");
			}

			i=sString.Find(_T(' '),i+1);
			if(i>0)
			{
				id=sString.Left(i); 
				name=sString.Right(sString.GetLength()-i-1);
			}
			else 
			{
				id=sString; 
				name=_T("");
				buf.Format(APL_T("Раздел без наименования: %s - возможно ошибка разбора!"),LPCTSTR(id));
				AfxMessageBox(buf);
			}
			curReq=CreateRequirementInderect(ciRequirement, id, name, _T(""));
			curReqRazd=curReq;

			strmap.Clear();
		}
		/*else if(id[0]==_T('(')) // это подпункт (возможна иерархия)
		{

		}*/
		else 
		{
			bool bIsPar=false;
			
			if(sString.GetLength()>2) // 2 символа и менее - это тект
			{
				bIsPar=true;
				for(j=0;j<id.GetLength();j++)
				{
					TCHAR c=id[j];
					if(!((c==_T('.'))||((c>=_T('0'))&&(c<=_T('9'))))){ bIsPar=false; break;}
				}
				if(!bIsPar) // все заглавные - тоже заголовок
				{
					buf0=sString;
					buf0.MakeUpper();
					if(buf0==sString) bIsPar=true;
				}
			}
	
			//if(id.Find(_T('.'))>0) // это новый пункт
			if(bIsPar) // это новый пункт
			{
				if(text!=_T(""))
				{
					if(curReq!=0) m_api->m_data.PutAttr(curReq, a_req_html, text);
					text=_T("");
				}
				j=id.GetLength()-2;
				while(j>0)
				{
					if(id[j]==_T('.')) break;
					j--;
				}
				buf0=id.Left(j+1); // обозначение родительского пункта

				CaplInstance *parReg=(CaplInstance*)strmap.GetP(buf0);
				if(0==parReg) parReg=curReqRazd;

				name=sString.Right(sString.GetLength()-i-1);
				name.TrimLeft();

				j=name.Find(_T('.'));
				if(j>0 && (j!=name.GetLength()-1))
				{
					text=name.Right(name.GetLength()-j-1);
					text.TrimLeft();
					buf=name.Left(j+1);
					name=buf;
				}

				curReq=CreateRequirementInderect(parReg, id, name, _T(""));
				strmap.Add(id,curReq);

				name.MakeLower();
				if(name.Find(APL_T("зарезервирован"))>=0) m_api->m_data.PutAttr(curReq, a_req_no_need, true);
			
			}
			else // это текст
			{
				if(text!=_T("")) text+=_T("<br>");
				text+=sString;
				continue;
			}
		}
	}

	if(text!=_T("") && curReq!=0) m_api->m_data.PutAttr(curReq, a_req_html, text);

	file.Close();
	if(m_api->m_AutoSave) m_api->SaveChanges();

	AfxMessageBox( APL_T("Данные успешно импортированы."), MB_ICONINFORMATION);
	return true;
}




// Функция Акуленко
/*bool CaplRequirementMgr::ImportAP25FromTxt(aplExtent &aeRootItems, CaplInstance *ciRequirement, CString sPath)
{
	bad_api_return_bool;
	bad_instance_return_bool(ciRequirement);
	not_requirement_return_bool(ciRequirement);
	get_file_path_open(sPath, _T("txt"),  APL_T("Текстовые файлы (*.txt)|*.txt||"));

	// все переменные
	BOOL bResult = TRUE;
	int nDashIndex;
	int nDivCount;
	CString sSubDivId;
	CString sId, sName;
	char chDash = _T('–');
	int nIndex;
	CaplInstance *ciLastRequirement = NULL;
	CString sString, sText;
	CaplInstance *ciLastParent = NULL;
	CString sDivision =  APL_T("Раздел ");
	CaplInstance *ciLastSubDivision = NULL;
	CaplInstance *ciLastDivision = NULL;
	TStrInstMap mapParents;
	TStrInstMap_it Iter;

	// открываем файл
	CStdioFile file;
	if(!file.Open(sPath, CFile::modeRead)) 
	{
		AfxMessageBox( APL_T("Не удалось открыть файл!"), MB_ICONSTOP);
		return false;
	}

	// читаем содержимое файла
	while(bResult)
	{
		bResult = file.ReadString(sString);
		if(sString.IsEmpty()) continue;		

		// начался новый раздел
		if(sString.Left(sDivision.GetLength()) == sDivision)
		{
			// пишем в последнее созданное требование все, что насобирали
			if(ciLastRequirement) AddAttrrToLastRequirement(m_api, sText, &ciLastRequirement);

			nDivCount = 1;
			sSubDivId.Format(_T("%d"), nDivCount++);

			// ищем тире
			nDashIndex = sString.ReverseFind(chDash);
			if(nDashIndex == -1)
			{
				AfxMessageBox( APL_T("Неверный формат файла. Импорт отменен."), MB_ICONSTOP);
				return false;
			}

			// создаем требование "Раздел"
			sName = sString.Left(nDashIndex); sName.TrimRight();
			sId = sName; sId.Replace(sDivision, _T(""));

			ciLastDivision = CreateRequirementInderect(ciRequirement, sId, sName, _T(""));
			if(!ciLastDivision)
			{
				AfxMessageBox( APL_T("Не удалось создать требование!"), MB_ICONSTOP);
				return false;
			}
			else
			{
				aeRootItems.Add(ciLastDivision);
			}

			// создаем подраздел
			sId = sSubDivId;
			sName = sString.Right( sString.GetLength() - nDashIndex - 1 );
			sName.TrimLeft();

			ciLastSubDivision = CreateRequirementInderect(ciLastDivision, sId, sName, _T(""));
			if(!ciLastSubDivision)
			{
				AfxMessageBox( APL_T("Не удалось создать требование!"), MB_ICONSTOP);
				return false;
			}

			// очищаем все, что было до этого
			sText=_T("");
			mapParents.clear();
		}
		// началось новое требование
		else if(sString[0] >= _T('1') && sString[0] <= _T('9'))
		{
			// ищем последнюю цифру с точкой
			nIndex = GetRequirementIdLastIndex(sString);
			if(nIndex == -1) continue;

			// пишем в последнее созданное требование все, что насобирали
			if(ciLastRequirement) AddAttrrToLastRequirement(m_api, sText, &ciLastRequirement);		

			sId = sString.Left(nIndex);
			sString.Replace(sId, _T("")); 
			sString.TrimLeft();

			// получаем родителя исходя из обозначения
			// из 2.52. делаем 2.52
			CString sParentId = sId.Left( sId.GetLength()-1 );

			// из 2.52 делаем 2.
			sParentId = sParentId.Left( sParentId.ReverseFind(_T('.')) + 1 );

			// ищем родителя
			if(!sParentId.IsEmpty())
			{
				Iter = mapParents.find(sParentId);
				if(Iter != mapParents.end())
					ciLastParent = Iter->second;
				else
					ciLastParent = ciLastSubDivision;
			}
			else
				ciLastParent = ciLastSubDivision;

			sText = sString;
			ciLastRequirement = CreateRequirementInderect(ciLastParent, sId, _T(""), _T(""));

			// добавляем нового родителя
			mapParents.insert(std::make_pair(sId, ciLastRequirement));
		}
		// текст "страницы и названия документа"
		else if(sString ==  APL_T("Часть 25 Авиационные правила") ||
			sString ==  APL_T("Авиационные правила Часть 25"))
		{
			// пропускаем
			file.ReadString(sString);
			file.ReadString(sString);
			file.ReadString(sString);
		}
		else
		{
			if(AllLettersUppear(sString))
			{
				// пишем в последнее созданное требование все, что насобирали
				if(ciLastRequirement) AddAttrrToLastRequirement(m_api, sText, &ciLastRequirement);
				
				sSubDivId.Format(_T("%d"), nDivCount++);
				sString.Trim();

				ciLastSubDivision = CreateRequirementInderect(ciLastDivision, sSubDivId, sString, _T(""));
				if(!ciLastSubDivision)
				{
					AfxMessageBox( APL_T("Не удалось создать требование!"), MB_ICONSTOP);
					return false;
				}

				// очищаем все, что было до этого
				sText=_T("");
				mapParents.clear();
			}

			sText += sString;
		}
	}

	file.Close();
	if(m_api->m_AutoSave) m_api->SaveChanges();

	AfxMessageBox( APL_T("Данные успешно импортированы."), MB_ICONINFORMATION);
	return true;
}
*/

int CaplRequirementMgr::GetRequirementIdLastIndex(CString str)
{
	bool bLastNum = false, bLastDot = false;;
	if(str.Find(_T('.')) == -1) return -1;

	for(int i=0; i<str.GetLength(); i++)
	{
		if(str[i] >= _T('0') && str[i] <= _T('9'))
		{
			bLastDot = false;
		}
		else if(str[i] == _T('.'))
		{
			bLastDot = true;
		}
		else 
		{
			if(!bLastDot) return -1;
			else return i;
		}
	}

	return -1;
}

CaplInstance* CaplRequirementMgr::CreateAssociation(CaplInstance *ciReq, CaplInstance *ciItem)
{
	bad_api_return_inst;
	bad_instance_return_inst(ciReq);
	bad_instance_return_inst(ciItem);

	CaplInstance *ciAssoc = m_api->m_data.CreateInstance(e_requirement_association);
	if(!ciAssoc) return 0;

	m_api->m_data.PutAttr(ciAssoc, a_req_assoc_item, ciItem);
	m_api->m_data.PutAttr(ciAssoc, a_req_assoc_req, ciReq);

	if(m_api->m_AutoSave) m_api->SaveChanges();
	return ciAssoc;
}

bool CaplRequirementMgr::FindAssociatedReqs(CaplInstance *ciItem, aplExtent &aeReq, aplExtent &aeAssoc, bool bLoadFromBase)
{
	bad_api_return_bool;
	bad_instance_return_bool(ciItem);

	CaplAttrValue val;
	CaplInstance *ciReq = 0;

	val.attr = a_req_assoc_item;
	val.value.Set(ciItem);

	m_api->m_data.NET_FindInstancesWithAttrValues(e_requirement_association, 1, &val, aeAssoc, true);
	if(bLoadFromBase) m_api->LoadExtentInfo(aeAssoc);
	
	for(int i=0; i<aeAssoc.Size; i++)
	{
		m_api->m_data.GetAttr(aeAssoc[i], a_req_assoc_req, ciReq);
		if(ciReq) aeReq.Add(ciReq);
	}

	if(bLoadFromBase) LoadReqInfo(aeReq);
	return true;
}

bool CaplRequirementMgr::FindAssociatedItems(CaplInstance *ciReq, aplExtent &aeItems, aplExtent &aeAssoc, bool bLoadFromBase)
{
	bad_api_return_bool;
	bad_instance_return_bool(ciReq);

	CaplAttrValue val;
	CaplInstance *ciItem = 0;

	val.attr = a_req_assoc_req;
	val.value.Set(ciReq);

	m_api->m_data.NET_FindInstancesWithAttrValues(e_requirement_association, 1, &val, aeAssoc, true);
	if(bLoadFromBase) m_api->LoadExtentInfo(aeAssoc);

	for(int i=0; i<aeAssoc.Size; i++)
	{
		m_api->m_data.GetAttr(aeAssoc[i], a_req_assoc_item, ciItem);
		if(ciItem) aeItems.Add(ciItem);
	}

	if(bLoadFromBase) m_api->LoadExtentInfo(aeItems);
	return true;
}