// aplRecurseFindDlg.cpp : implementation file
//

#include "stdafx.h"
#include <finder.h>
#include "PSM.h"
#include "aplRecurseFindDlg.h"
#include "TreeProductItem.h"
#include "aplClassifierTreeItem.h"
#include "aplFolderTreeItem.h"
#include "aplQueryItem.h"

// CaplRecurseFindDlg dialog

IMPLEMENT_DYNAMIC(CaplRecurseFindDlg, CaplTranslateDialog)

CaplRecurseFindDlg::CaplRecurseFindDlg(CWnd* pParent /*=NULL*/)
	: CaplTranslateDialog(CaplRecurseFindDlg::IDD, pParent), m_item(0), m_api(0)
{
}

CaplRecurseFindDlg::~CaplRecurseFindDlg()
{
}

void CaplRecurseFindDlg::DoDataExchange(CDataExchange* pDX)
{
	CaplTranslateDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_TEXT, m_textEdit);
	DDX_Control(pDX, IDC_FIND_FIRST, m_findBtn);
	DDX_Control(pDX, IDC_FIND_NEXT, m_findNexBtn);
	DDX_Control(pDX, IDC_FIND_PREV, m_findPrevBtn);
}

BEGIN_MESSAGE_MAP(CaplRecurseFindDlg, CaplTranslateDialog)
	ON_BN_CLICKED(IDC_FIND_FIRST, &CaplRecurseFindDlg::OnBnClickedFindFirst)
	ON_BN_CLICKED(IDC_FIND_NEXT, &CaplRecurseFindDlg::OnBnClickedFindNext)
	ON_BN_CLICKED(IDC_FIND_PREV, &CaplRecurseFindDlg::OnBnClickedFindPrev)
END_MESSAGE_MAP()

BOOL CaplRecurseFindDlg::OnInitDialog()
{
	BOOL ret = __super::OnInitDialog();

	InitButtons();

	return ret;
}

void CaplRecurseFindDlg::InitButtons()
{
	m_findBtn.SetFlat(FALSE); 
	m_findNexBtn.SetFlat(FALSE); 
	m_findPrevBtn.SetFlat(FALSE);

	m_findBtn.SetIcon(GetAplTableIco((APL_TABLE_FIND)));
	m_findNexBtn.SetIcon(GetAplTableIco((APL_TABLE_BOTTOM)));
	m_findPrevBtn.SetIcon(GetAplTableIco((APL_TABLE_TOP)));

	m_findBtn.SetTooltipText(APL_T("Начать новый поиск"));
	m_findNexBtn.SetTooltipText(APL_T("Найти далее"));
	m_findPrevBtn.SetTooltipText(APL_T("Найти предыдущий"));
}

// CaplRecurseFindDlg message handlers

int CaplRecurseFindDlg::LoadRecursiveDataProduct(CaplProductTreeItem *item)
{
	CString text;
	m_textEdit.GetWindowText(text);

	m_findNexBtn.EnableWindow(TRUE);
	m_findPrevBtn.EnableWindow(TRUE);

	// найдем изделия, которые подходят
	CaplFinder ff(DEF_SOURCE);
	m_searchedItems.Clear();
	m_validExtent.Clear();

	aplExtent ext_rel,ext_unit;
	aplRealArray count_array;

	CaplInstance *rootInst = item->GetItemInstance(item);
	m_api->m_prd_mgr.DisassemblyProduct(0,rootInst,ext_rel,m_validExtent,count_array,ext_unit);

	int prdIndex = ff.CreateExt(m_api->m_prd_mgr.e_prd);
	ff.AddAttr(prdIndex, m_api->m_prd_mgr.a_prd_id, text, CaplFinder::cmpLike);

	int pdfIndex = ff.CreateExt(m_api->m_prd_mgr.e_pdf);
	ff.AddAttr(pdfIndex, m_api->m_prd_mgr.a_pdf_prd, prdIndex);

	ff.AddToResult(pdfIndex);
	ff.Find(m_api->m_data, m_searchedItems, true, false, false, false, true);

	// загрузим состав "наверх"
	
	if(m_searchedItems.Size > 0)
	{
		int index_q = 0;
		int index_i = 0;
		int i=0;
		int j;

		aplExtent realtions;
		CaplLoadData ld(&m_api->m_data, DEF_SOURCE);
		
		while(index_i < m_searchedItems.Size)
		{
			for(i=0; (i<2000 && index_i<m_searchedItems.Size); ++i)
			{
				ld.AddQuery(0, m_searchedItems[index_i], true);
				++index_i;
			}
			index_q = 0;

			for(j=0; j<100; ++j)
			{
				int m0 = ld.AddQuery(_T('r'), index_q, m_api->m_prd_mgr.e_pdr, m_api->m_prd_mgr.a_pdr_r_ted, true, true);
				int m1 = ld.AddQuery(_T('d'), m0, m_api->m_prd_mgr.e_pdr, m_api->m_prd_mgr.a_pdr_r_ting, true, true);

				index_q = m1;
			}
			ld.LoadEx(true, &realtions);

			// соберем все в единую структуру	
			CaplInstance *edItem = 0, *ingItem = 0;
			for(i=0; i<realtions.Size; ++i)
			{
				if(realtions[i]->GetAccessmode()==aplNO) continue;
				if(!m_api->m_data.IsKindOf(realtions[i], m_api->m_prd_mgr.e_pdr)) continue;
				m_api->m_data.GetAttr(realtions[i], m_api->m_prd_mgr.a_pdr_r_ted, edItem);
				m_api->m_data.GetAttr(realtions[i], m_api->m_prd_mgr.a_pdr_r_ting, ingItem);
				m_relations[ingItem].push_back(edItem);		
			}	
		}
	}


	return GetSearchResultCount(item->m_pdf);
}

int CaplRecurseFindDlg::GetSearchResultCount(CaplInstance *pdf)
{
	int count = 0;
	std::map<CaplInstance*, std::vector<CaplInstance*>>::iterator it = m_relations.find(pdf);

	if(it != m_relations.end())
	{
		std::vector<CaplInstance*> &vec = it->second;
		for(unsigned int i=0; i<vec.size(); ++i)
		{
			if(-1 != m_searchedItems.Find(vec[i]))
				count++;

			count = count + GetSearchResultCount(vec[i]);
		}
	}	

	return count;
}

void CaplRecurseFindDlg::FillClassifierRelationMap(CaplInstance *edItem, std::map<CaplInstance*, CaplInstance*> &backwardRelations)
{
	std::map<CaplInstance*, CaplInstance*>::iterator it = backwardRelations.find(edItem);
	if(it != backwardRelations.end())
	{
		m_relations[it->second].push_back(it->first);
		FillClassifierRelationMap(it->second, backwardRelations);
	}
}

int CaplRecurseFindDlg::LoadRecursiveDataClassifier(CaplClassifierTreeItem *item)
{
	CaplInstance *rootInst = item->GetItemInstance(item);
	if(rootInst == 0)
		return 0;

	// если ищем через classifier_lvl, то возьмем его систему (для обобщенности алгоритма)
	if(m_api->m_data.IsKindOf(rootInst, m_api->m_classifier_mgr.e_apl_classifier_level))
		m_api->m_data.GetAttr(rootInst, m_api->m_classifier_mgr.a_apl_classifier_level_system, rootInst);

	int i,count;
	aplExtent ext_tmp;
	CString text;
	m_textEdit.GetWindowText(text);

	m_findNexBtn.EnableWindow(TRUE);
	m_findPrevBtn.EnableWindow(TRUE);

	// найдем изделия, которые подходят
	m_searchedItems.Clear();
	m_validExtent.Clear();

	m_api->m_classifier_mgr.LoadSubClassifierSystems(rootInst,m_validExtent,true);
	m_validExtent.Add(rootInst);
	count = m_validExtent.GetSize();
	for(i=0;i<count;i++)
	{
		m_api->m_classifier_mgr.LoadSubClassifierLevels(m_validExtent[i],ext_tmp,true);
		m_validExtent.Append(ext_tmp);
	}

	CaplFinder ff(DEF_SOURCE);
	std::map<CaplInstance*, CaplInstance*> backwardRelations;

	int prdIndex = ff.CreateExt(m_api->m_prd_mgr.e_prd);
	ff.AddAttr(prdIndex, m_api->m_prd_mgr.a_prd_id, text, CaplFinder::cmpLike);

	int pdfIndex = ff.CreateExt(m_api->m_prd_mgr.e_pdf);
	ff.AddAttr(pdfIndex, m_api->m_prd_mgr.a_pdf_prd, prdIndex);

	int lvlIndex = ff.CreateExt(m_api->m_classifier_mgr.e_apl_classifier_level, 0, 0, CaplFinder::grpOR);
	ff.AddAttr(lvlIndex, m_api->m_classifier_mgr.a_apl_classifier_level_name, text, CaplFinder::cmpLike);
	ff.AddAttr(lvlIndex, m_api->m_classifier_mgr.a_apl_classifier_level_id, text, CaplFinder::cmpLike);

	ff.SetResultGrpType(CaplFinder::grpOR);
	ff.AddToResult(lvlIndex);
	ff.AddToResult(pdfIndex);
	ff.Find(m_api->m_data, m_searchedItems, true, false, false, false, true);

	// найдем структуру справочника
	aplExtent subSystems;
	m_api->m_classifier_mgr.LoadSubClassifierSystems(rootInst, subSystems, true, true);
	subSystems.Add(rootInst);

	ff.Clear();
	aplExtent subItems;
	lvlIndex = ff.CreateExt(m_api->m_classifier_mgr.e_apl_classifier_level);
	ff.AddAttr(lvlIndex, m_api->m_classifier_mgr.a_apl_classifier_level_system, ff.CreateExt(subSystems, true));
	ff.AddToResult(lvlIndex);
	ff.Find(m_api->m_data, subItems, true, false, false, true, true);	

	aplExtent lvls;
	CaplInstance *ingItem = 0, *edItem = 0;

	subItems.Append(subSystems);
	for(i=0; i<subItems.Size; ++i)
	{		
		if(m_api->m_data.IsKindOf(subItems[i], m_api->m_classifier_mgr.e_apl_classifier_system))
		{
			edItem = subItems[i];
			m_api->m_data.GetAttr(subItems[i], m_api->m_classifier_mgr.a_apl_classifier_system_parent, ingItem);
		}
		else if(m_api->m_data.IsKindOf(subItems[i], m_api->m_classifier_mgr.e_apl_classifier_level))
		{
			lvls.Add(subItems[i]);
			edItem = subItems[i];
			m_api->m_data.GetAttr(subItems[i], m_api->m_classifier_mgr.a_apl_classifier_level_parent, ingItem);

			// если парента уже нет, значит входит в систему
			if(ingItem == 0)
				m_api->m_data.GetAttr(subItems[i], m_api->m_classifier_mgr.a_apl_classifier_level_system, ingItem);
		}

		backwardRelations[edItem] = ingItem;
	}		

	// найдем содержание справочника
	aplExtent relations;
	ff.Clear();

	aplExtent tmpItems, tmpRelations;
	int index = ff.CreateExt(m_api->m_classifier_mgr.e_apl_classifier_association);
	for(int i=0; i<m_searchedItems.Size; ++i)
	{
		tmpItems.Add(m_searchedItems[i]);
		if(tmpItems.Size == 100 || i == m_searchedItems.Size - 1)
		{
			ff.AddAttr(index, m_api->m_classifier_mgr.a_apl_classifier_association_item, ff.CreateExt(tmpItems, true));
			ff.AddToResult(index);
			ff.Find(m_api->m_data, tmpRelations, true, false, false, true, true);

			for(int j=0; j<tmpRelations.Size; ++j)
			{
				m_api->m_data.GetAttr(tmpRelations[j], m_api->m_classifier_mgr.a_apl_classifier_association_classifier, ingItem);
				if(lvls.Find(ingItem) != -1)
					relations.Add(tmpRelations[j]);
			}

			tmpItems.Clear();
			tmpRelations.Clear();

			ff.Clear();
			index = ff.CreateExt(m_api->m_classifier_mgr.e_apl_classifier_association);
		}
	}

	count = 0;
	for(i=0; i<relations.Size; ++i)
	{
		m_api->m_data.GetAttr(relations[i], m_api->m_classifier_mgr.a_apl_classifier_association_classifier, ingItem);
		m_api->m_data.GetAttr(relations[i], m_api->m_classifier_mgr.a_apl_classifier_association_item, edItem);
		m_relations[ingItem].push_back(edItem);

		if(m_searchedItems.Find(edItem) != -1)
			count++;

		FillClassifierRelationMap(ingItem, backwardRelations);
	}

	// это на тот случай если нашлись только уровни справочников
	for(i=0; i<lvls.Size; ++i)
	{
		if(m_searchedItems.Find(lvls[i]) != -1)
		{
			FillClassifierRelationMap(lvls[i], backwardRelations);
			count++;		
		}
	}

	return count;
}

void CaplRecurseFindDlg::OnBnClickedFindFirst()
{
	CString text;
	int count = 0;
	m_textEdit.GetWindowText(text);

	if(false == text.IsEmpty())
	{
		m_relations.clear();
		long dId = aplStartWaitDlg(APL_T("Поиск..."));

		if(dynamic_cast<CaplProductTreeItem*>(m_item) != 0)
		{			
			count = LoadRecursiveDataProduct(dynamic_cast<CaplProductTreeItem*>(m_item));
		}
		else if(dynamic_cast<CaplClassifierTreeItem*>(m_item) != 0)
		{
			count = LoadRecursiveDataClassifier(dynamic_cast<CaplClassifierTreeItem*>(m_item));
		}
				
		aplEndWaitDlg(dId);

		// покажем сколько всего нашлось совпадений
		SetTreeItem(m_item, m_item->GetItemInstance(m_item));
		CString caption; GetWindowText(caption);
		CString tmpStr; tmpStr.Format(APL_T(". Найдено совпадений %d"), count);
		SetWindowText(caption + tmpStr);

		// будем раскрывать дерево по найденным связям
		m_item->Expand(TVE_EXPAND);
		ShowItem(m_item->m_tree->GetNextItem(m_item->m_item, TVGN_CHILD), 1);
	}
}

bool CaplRecurseFindDlg::ShowItem(HTREEITEM hItem, int direction)
{
	CaplInstance* inst;
	while(hItem)
	{
		CaplTreeItem *data = reinterpret_cast<CaplTreeItem*>(m_item->m_tree->GetItemData(hItem));
		if(0 != data)
		{
			CaplTreeItem *treeItemData = dynamic_cast<CaplTreeItem*>(data);
			if(0 != treeItemData)
			{
				inst = treeItemData->GetItemInstance(treeItemData);
				// если дошли до папок или запросов - однозначно вышли наружу за первоначальное дерево
				if(dynamic_cast<CaplFolderTreeItem*>(treeItemData) != 0 || dynamic_cast<CaplQueryTreeItem*>(treeItemData) != 0)
				{	
					break;
				}
				else if(dynamic_cast<CaplProductTreeItem*>(m_item) != 0)
				{	
					// если плясали от сборки и дошли до справочников - однозначно вышли наружу за первоначальное дерево
					if(dynamic_cast<CaplClassifierTreeItem*>(treeItemData) != 0)
						break;
// 					// если в дереве
// 					if( dynamic_cast<CaplProductTreeItem*>(treeItemData) != 0)
// 					{
// 						if(-1 == m_validExtent.Find(inst))
// 							break;
// 					}
				}
				else if(dynamic_cast<CaplClassifierTreeItem*>(m_item) != 0 && dynamic_cast<CaplClassifierTreeItem*>(treeItemData) != 0 )
				{
					if(-1 == m_validExtent.Find(inst))
						break;
				}
				if(-1 != m_searchedItems.Find(inst))
				{
				    m_item->m_tree->SelectDropTarget(hItem);
					m_item->m_tree->EnsureVisible(hItem);
					m_item->m_tree->SelectItem(hItem);

					return true;
				}

				if(m_relations.find(inst) != m_relations.end())
				{
					treeItemData->Expand(TVE_EXPAND);
					hItem = aplGetNextTreeItem(m_item->m_tree, hItem, direction);

					continue;
				}
			}
		}

		hItem = aplGetNextTreeItem(m_item->m_tree, hItem, direction);

		// это чтобы не убежать дальше элемента, с которого начали
		if(aplGetNextTreeItem(m_item->m_tree, hItem, -1) == m_item->m_item)
			break;
	}

	AfxMessageBox(APL_T("Совпадений не найдено."), MB_ICONINFORMATION);
	return false;
}

void CaplRecurseFindDlg::ExpandItem(HTREEITEM hItem)
{
	CaplTreeItemData *data = reinterpret_cast<CaplTreeItemData*>(m_item->m_tree->GetItemData(hItem));
	if(0 != data)
		data->Expand(TVE_EXPAND);	
}

void CaplRecurseFindDlg::SetTreeItem( CaplTreeItem *item, CaplInstance *rootItem )
{
	if(0 == rootItem)
		return;

	if(GetSafeHwnd() == 0)
		Create(CaplRecurseFindDlg::IDD, AfxGetApp()->m_pMainWnd);

	ShowWindow(SW_SHOW);
	CenterWindow();

	if(item != 0)
	{
		m_item = item;
		m_api = &m_item->m_doc->m_api;

		SetWindowText(APL_T("Поиск для ") + m_api->GetItemName(rootItem));
	}
}

void CaplRecurseFindDlg::OnBnClickedFindNext()
{
	HTREEITEM selectedItem = m_item->m_tree->GetSelectedItem(); 
	ExpandItem(selectedItem);
	
	ShowItem(aplGetNextTreeItem(m_item->m_tree, selectedItem, 1), 1);
}

void CaplRecurseFindDlg::OnBnClickedFindPrev()
{
	HTREEITEM selectedItem = m_item->m_tree->GetSelectedItem(); 
	ExpandItem(selectedItem);	

	ShowItem(aplGetNextTreeItem(m_item->m_tree, selectedItem, -1), -1);	
}
