// ClassifierSelectDlg.cpp : implementation file
//

#include "stdafx.h"
#include "ClassifierSelectDlg.h"

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

/////////////////////////////////////////////////////////////////////////////
// CClassifierSelectDlg dialog
/************************************************************************/
/*                  CTreeItemData                                       */
/************************************************************************/
int CALLBACK CompareItems(LPARAM lParam1, LPARAM lParam2,LPARAM lParamSort)
{
	CTreeItemData* item1 = (CTreeItemData*)lParam1;
	CTreeItemData* item2 = (CTreeItemData*)lParam2;

	CString buf1, buf2;
	item1->m_api->GetItemName(item1->m_inst, buf1);
	item2->m_api->GetItemName(item2->m_inst, buf2);

	return buf1.CompareNoCase(buf2);
}

CTreeItemData::CTreeItemData(CaplAPI* api, CTreeCtrl* tree, CaplInstance* inst, CItemsArray* Arr, int level)
{
	ASSERT(api);
	ASSERT(tree);
	ASSERT(inst);
	ASSERT(Arr);

	m_api = api;
	m_tree = tree;
	m_inst = inst;
	m_ItemsArray = Arr;

	m_ItemLevel = level;

	if(m_api->m_data.IsKindOf(m_inst, m_api->m_classifier_mgr.e_apl_classifier_system))
		m_system = m_inst;
	else
		m_api->m_data.GetAttr(m_inst, m_api->m_classifier_mgr.a_apl_classifier_level_system, m_system);
	ASSERT(m_system);
	m_ItemsArray->Add(this);
}

CTreeItemData::~CTreeItemData()
{
    HTREEITEM item;
	if(::IsWindow(m_tree->m_hWnd))
	{
		while(1)
		{
			item=m_tree->GetChildItem(m_item);
			if(item==0) break;
			CTreeItemData *treeitem=(CTreeItemData*)m_tree->GetItemData(item);
			if(treeitem==this) continue;
			if(treeitem!=0) 
				delete treeitem;
			else m_tree->DeleteItem(item);
		}

		if(m_item)
		{
			m_tree->DeleteItem(m_item);
			m_item = NULL;
		}
	}
	for(int i=0; i<m_ItemsArray->GetSize();i++)
	{
		if(m_ItemsArray->GetAt(i)==this)
		{
			m_ItemsArray->RemoveAt(i);
			break;
		}
	}
}

bool CTreeItemData::Create(HTREEITEM parent)
{
	CString name;
	m_api->GetItemName(m_inst, name);
	int ico = m_api->GetInstIco(m_inst);

	m_item = m_tree->InsertItem(name, ico, ico, parent);
	m_fictive_item = m_tree->InsertItem(name, m_item);

	m_tree->SetItemData(m_item, (DWORD)this);

	return true;	
}

void CTreeItemData::Expand(UINT action, UINT mode)
{
	if(action==TVE_EXPAND)
	{
		if(m_fictive_item)
			m_tree->DeleteItem(m_fictive_item);
		m_fictive_item = NULL;
		CollapseItems();

		//проверяем доступность раскрытия дерева
		bool bConcept, bIsLastLaval;
		int MinLev, MaxLev;
		m_api->m_classifier_mgr.GetConceptLevelParameters(m_system, bConcept, bIsLastLaval, MinLev, MaxLev);
		if(bConcept)
		{
			if(m_inst!=m_system)
			{
				int level = m_api->m_classifier_mgr.GetLevelClassifierLevel(m_inst);
				if(!bIsLastLaval)
				{
					if(MinLev<level || MaxLev>level) return;
				}
			}
		}
		aplExtent ext, ext1;
		if(!(mode==APL_SELECT_CLASSIFIER_SYSTEM))
			m_api->m_classifier_mgr.LoadSubClassifierLevels(m_inst, ext);
		
		m_api->m_classifier_mgr.LoadSubClassifierSystems(m_inst, ext1);
		ext.Append(ext1);
		
		ext1.Clear();
		
		for(int i=0; i<ext.Size; i++)
		{
			CTreeItemData* item = new CTreeItemData(m_api, m_tree, ext[i], m_ItemsArray, m_ItemLevel+1);
			item->Create(m_item);
		}
		Sort(m_item);
	}
	else
	{
		CollapseItems();
		m_fictive_item = m_tree->InsertItem(_T("fictive"), m_item);
	}
}

void CTreeItemData::CollapseItems()
{
    HTREEITEM item;
    while(1)
    {
        item=m_tree->GetChildItem(m_item);
        if(item==0) break;
        CTreeItemData *treeitem=(CTreeItemData*)m_tree->GetItemData(item);
		if(treeitem==this) continue;
        if(treeitem!=0) 
			delete treeitem;
        else m_tree->DeleteItem(item);
    }
}

/************************************************************************/
/*                                                                      */
/************************************************************************/
CClassifierSelectDlg::CClassifierSelectDlg(CaplAPI* api, CWnd* pParent /*=NULL*/)
	: CaplTranslateDialog(CClassifierSelectDlg::IDD, pParent)
{
	ASSERT(api);
	//{{AFX_DATA_INIT(CClassifierSelectDlg)
	m_sDescr = _T("");
	//}}AFX_DATA_INIT
	m_BaseClassifierSystem = NULL;
	m_SelectedElement = NULL;
	m_api = api;
}


void CClassifierSelectDlg::DoDataExchange(CDataExchange* pDX)
{
	CaplTranslateDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CClassifierSelectDlg)
	DDX_Control(pDX, IDOK, m_ok_btn);
	DDX_Control(pDX, IDCANCEL, m_cancel_btn);
	DDX_Control(pDX, IDC_TREE, m_TreeCtrl);
	DDX_Text(pDX, IDC_ELEM_DESCRIPTION, m_sDescr);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CClassifierSelectDlg, CaplTranslateDialog)
	//{{AFX_MSG_MAP(CClassifierSelectDlg)
	ON_NOTIFY(TVN_ITEMEXPANDING, IDC_TREE, OnItemexpandingTree)
	ON_NOTIFY(TVN_SELCHANGED, IDC_TREE, OnSelchangedTree)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CClassifierSelectDlg message handlers

BOOL CClassifierSelectDlg::OnInitDialog() 
{
	CaplTranslateDialog::OnInitDialog();
	
	ModifyStyleEx(0, WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT);   
	ModifyStyle(0, WS_MAXIMIZEBOX);   
	
	if(!m_sTitle.IsEmpty())
		SetWindowText(m_sTitle);
	else
		SetWindowText( APL_T("Выбор элемента структуры"));
	
	m_cancel_btn.SetIcon(GetAplStdIco16(APLSTDICO_CANCEL));
	m_cancel_btn.SetFlat(FALSE);
	m_ok_btn.SetIcon(GetAplStdIco16(APLSTDICO_OK));
	m_ok_btn.SetFlat(FALSE);

	m_TreeCtrl.SetImageList(aplGetInstImageList(), TVSIL_NORMAL);

	LoadData();

	m_ok_btn.EnableWindow(FALSE);
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

bool CClassifierSelectDlg::LoadData()
{
	if(m_BaseClassifierSystem)
	{
		CTreeItemData* item = new CTreeItemData(m_api, &m_TreeCtrl, m_BaseClassifierSystem, &m_ItemsArray);
		item->Create();
		item->Expand(TVE_EXPAND);
		m_TreeCtrl.Expand(item->m_item, TVE_EXPAND);
	}
	else
	{
		aplExtent ext;
		m_api->m_classifier_mgr.LoadSubClassifierSystems(0,ext);
		
		for(int i=0; i<ext.Size; i++)
		{
			if(ext[i]==NULL) continue;
			if(ext[i]->GetAccessmode()>aplRO) continue;

			CTreeItemData* item = new CTreeItemData(m_api, &m_TreeCtrl, ext[i], &m_ItemsArray, 0);
			item->Create();
		}
	}

	if(m_ItemsArray.GetSize()>0)
		m_ItemsArray[0]->Sort();

	return true;
}


void CClassifierSelectDlg::OnItemexpandingTree(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	// TODO: Add your control notification handler code here
	HTREEITEM item = pNMTreeView->itemNew.hItem;
	if(item)
	{
		CTreeItemData* ItemData = (CTreeItemData*)m_TreeCtrl.GetItemData(item);
		ItemData->Expand(pNMTreeView->action, m_SelectMode);

		TVSORTCB sortcb;
		sortcb.hParent=item;
		sortcb.lpfnCompare=CompareHtreeItem;
		sortcb.lParam=1;
		ItemData->m_tree->SortChildrenCB(&sortcb);
	}
	
	*pResult = 0;
}

int CALLBACK CClassifierSelectDlg::CompareHtreeItem(LPARAM lParam1, LPARAM lParam2,LPARAM lParamSort)
{
	if(lParam1==0) return 0;
	if(lParam2==0) return 0;
	CTreeCtrl *tree=((CTreeItemData*)lParam1)->m_tree;
	if(tree==0) return 0;
	HTREEITEM item1=((CTreeItemData*)lParam1)->m_item;
	HTREEITEM item2=((CTreeItemData*)lParam2)->m_item;
	int img1,img2,img0;
	tree->GetItemImage(item1,img1,img0);
	tree->GetItemImage(item2,img2,img0);

	if(img1<img2) return -1;
	if(img2<img1) return 1;
	CString str1, str2;
	str1 = tree->GetItemText(item1);
	str2 = tree->GetItemText(item2);
	str1.MakeLower();
	str2.MakeLower();
	//	return str1.CompareNoCase(str2);
	//return str1.Compare(str2);*/
	return aplCompare2StringAsClassifier(str1,str2); 
}


void CClassifierSelectDlg::OnSelchangedTree(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	// TODO: Add your control notification handler code here
	HTREEITEM item = pNMTreeView->itemNew.hItem;
	if(item)
	{
		CTreeItemData* ItemData = (CTreeItemData*)m_TreeCtrl.GetItemData(item);
		UpdateData();
		ItemData->GetDescription(m_sDescr);
		UpdateData(FALSE);
		m_ok_btn.EnableWindow(ItemData->IsPossibletoselect(m_SelectMode));
	}
	
	*pResult = 0;
}

BOOL CClassifierSelectDlg::DestroyWindow() 
{
	while(m_ItemsArray.GetSize())
		delete m_ItemsArray[0];
	
	return CaplTranslateDialog::DestroyWindow();
}

void CTreeItemData::GetDescription(CString &descr)
{
	descr=_T("");
	if(m_api->m_data.IsKindOf(m_inst, m_api->m_classifier_mgr.e_apl_classifier_system))
		m_api->m_data.GetAttr(m_inst, m_api->m_classifier_mgr.a_apl_classifier_system_descr, descr);
	else if(m_api->m_data.IsKindOf(m_inst, m_api->m_classifier_mgr.e_apl_classifier_level))
		m_api->m_data.GetAttr(m_inst, m_api->m_classifier_mgr.a_apl_classifier_level_descr, descr);
}

void CClassifierSelectDlg::OnOK() 
{
	if(!UpdateData()) return;

	HTREEITEM item = m_TreeCtrl.GetSelectedItem();
	if(!item)
	{
		AfxMessageBox( APL_T("Необходимо выбрать элемент структуры справочника!"));
		return;
	}
	CTreeItemData* treeitem = (CTreeItemData*)m_TreeCtrl.GetItemData(item);
	if(!treeitem)
		return;

	m_SelectedElement = treeitem->m_inst;
	
	CaplTranslateDialog::OnOK();
}

void CTreeItemData::Sort(HTREEITEM parent)
{
	TVSORTCB tvsort;
	tvsort.hParent = parent;
	tvsort.lpfnCompare = &CompareItems;
	tvsort.lParam = 0;
	m_tree->SortChildrenCB(&tvsort);
}

bool CTreeItemData::IsPossibletoselect(UINT mode)
{
	bool bRes = false;
	bool bUseLevelCtrl;
	bool bLastOnly;
	int min_level, max_level;

	if(mode&APL_SELECT_CLASSIFIER_SYSTEM)
	{
		if(m_inst==m_system) return true;
	}
	
	if(m_inst!=m_system)
	{
		if(mode&APL_SELECT_CLASSIFIER_LEVEL && mode&APL_CONCEPT)
		{
			m_api->m_data.GetAttr(m_system, m_api->m_classifier_mgr.a_apl_classifier_system_is_concept_level_control, bUseLevelCtrl);
			if(!bUseLevelCtrl) return true;
			m_api->m_data.GetAttr(m_system, m_api->m_classifier_mgr.a_apl_classifier_system_is_concept_last_level, bLastOnly);
			if(bLastOnly)
			{
				aplExtent ext;
				m_api->m_data.GetAttr(m_inst, m_api->m_classifier_mgr.a_apl_classifier_level_childs, ext);
				return (ext.GetSize()==0);
			}
			m_api->m_data.GetAttr(m_system, m_api->m_classifier_mgr.a_apl_classifier_system_concept_maxlevel, max_level);
			m_api->m_data.GetAttr(m_system, m_api->m_classifier_mgr.a_apl_classifier_system_concept_minlevel, min_level);
			return (m_ItemLevel>=min_level && (m_ItemLevel<=max_level || max_level==-1));
		}
		if(mode&APL_SELECT_CLASSIFIER_LEVEL && !(mode&APL_CONCEPT))
		{
			m_api->m_data.GetAttr(m_system, m_api->m_classifier_mgr.a_apl_classifier_system_is_object_level_control, bUseLevelCtrl);
			if(!bUseLevelCtrl) return true;
			m_api->m_data.GetAttr(m_system, m_api->m_classifier_mgr.a_apl_classifier_system_is_object_last_level, bLastOnly);
			if(bLastOnly)
			{
				aplExtent ext;
				m_api->m_data.GetAttr(m_inst, m_api->m_classifier_mgr.a_apl_classifier_level_childs, ext);
				return (ext.GetSize()==0);
			}
			m_api->m_data.GetAttr(m_system, m_api->m_classifier_mgr.a_apl_classifier_system_object_maxlevel, max_level);
			m_api->m_data.GetAttr(m_system, m_api->m_classifier_mgr.a_apl_classifier_system_object_minlevel, min_level);
			return (m_ItemLevel>=min_level && (m_ItemLevel<=max_level || max_level==-1));
		}
	}

	return false;
}
