// UnitConvertionDlg.cpp : implementation file
//

#include "stdafx.h"
#include "UnitConvertionDlg.h"

bool IsNumber(const CString &str)
{
	int nCount = str.GetLength();

	for(int i=0; i<nCount; ++i)
		if(false == ((str[i]>=_T('0') && str[i]<=_T('9')) || str[i]==_T('.') || str[i]==_T(',') || str[i]==_T('-')) )
			return false;

	return true;
}


// CUnitConvertionDlg dialog

IMPLEMENT_DYNAMIC(CUnitConvertionDlg, CaplResizableDialog)

CUnitConvertionDlg::CUnitConvertionDlg(CaplAPI *api, CaplInstance *pdf, CaplInstance *unit, double baseCount, CWnd* pParent /*=NULL*/)
	: CaplResizableDialog(CUnitConvertionDlg::IDD, pParent),
	m_api(api), m_pdf(pdf), m_baseCount(baseCount), m_baseUnit(unit)
{
	m_currentCtrl = 0;

	m_item = -1;
	m_subItem = -1;

	m_bReadOnly=false;

	m_processSetFocusEvent = true;
}

CUnitConvertionDlg::~CUnitConvertionDlg()
{
}

void CUnitConvertionDlg::DoDataExchange(CDataExchange* pDX)
{
	CaplResizableDialog::DoDataExchange(pDX);

	DDX_Control(pDX, IDOK, m_okBtn);
	DDX_Control(pDX, IDCANCEL, m_cancelBtn);
	DDX_Control(pDX, IDC_ADD, m_addBtn);
	DDX_Control(pDX, IDC_DELETE, m_deleteBtn);
	DDX_Control(pDX, IDC_LIST, m_list);
	DDX_Control(pDX, IDC_EDIT, m_edit);
	DDX_Control(pDX, IDC_COMBO, m_combo);
}


BEGIN_MESSAGE_MAP(CUnitConvertionDlg, CaplResizableDialog)
	ON_WM_DESTROY()
	ON_WM_SIZE()
	ON_NOTIFY(NM_DBLCLK, IDC_LIST, &CUnitConvertionDlg::OnNMDblclkList)
	ON_NOTIFY(NM_SETFOCUS, IDC_LIST, &CUnitConvertionDlg::OnNMSetfocusList)
	ON_BN_CLICKED(IDC_ADD, &CUnitConvertionDlg::OnBnClickedAdd)
	ON_BN_CLICKED(IDC_DELETE, &CUnitConvertionDlg::OnBnClickedDelete)
END_MESSAGE_MAP()

BOOL CUnitConvertionDlg::OnInitDialog()
{
	CaplResizableDialog::OnInitDialog();
	if(m_api==NULL)
	{
		EndDialog(0);
		return FALSE;
	}

	// предотвращаем потерю модальности после диалога с бочками из aplSocketTransport
	CORRECT_LOOSE_MODAL_ON_CLASS(&(m_api->m_data));

	InitGui();
	GetAllUnits();
	ShowUnits();

	if(m_bReadOnly)
	{
		m_okBtn.EnableWindow(FALSE);
		m_addBtn.EnableWindow(FALSE);
		m_deleteBtn.EnableWindow(FALSE);
	}
	
	return TRUE;
}

void CUnitConvertionDlg::InitGui()
{
	InitButtons();
	InitList();
	InitAnchors();
	InitCtrlsParent();
}

void CUnitConvertionDlg::InitButtons()
{
	m_cancelBtn.SetIcon(GetAplStdIco16(APLSTDICO_CANCEL));
	m_cancelBtn.SetFlat(FALSE);
	m_okBtn.SetIcon(GetAplStdIco16(APLSTDICO_OK));
	m_okBtn.SetFlat(FALSE);

	m_addBtn.SetIcon(aplGetButtonIco(APL_24_PLUS));
	m_addBtn.SetFlat(FALSE);
	m_deleteBtn.SetIcon(aplGetButtonIco(APL_24_DELETE));
	m_deleteBtn.SetFlat(FALSE);
}

void CUnitConvertionDlg::InitList()
{
	CRect rect;
	m_list.GetClientRect(rect);

	m_list.InsertColumn(0,  APL_T("Базовая единица измерения"), LVCFMT_LEFT, (int)(rect.Width()*0.39));
	m_list.InsertColumn(1,  APL_T("Количество"), LVCFMT_RIGHT, (int)(rect.Width()*0.1));
	m_list.InsertColumn(2,  APL_T("Альтернативная единица измерения"), LVCFMT_LEFT, (int)(rect.Width()*0.39));
	m_list.InsertColumn(3,  APL_T("Количество"), LVCFMT_RIGHT, (int)(rect.Width()*0.1));
	
	m_list.SetRowHeight(20);	
	m_list.SetExtendedStyle(m_list.GetExtendedStyle()|LVS_EX_FULLROWSELECT|
		LVS_EX_SUBITEMIMAGES | LVS_EX_GRIDLINES);

	m_newCountColumn = 3;
	m_newUnitColumn = 2;

	m_srcUnitColumn=0;
	m_srcCountColumn=1;
}

void CUnitConvertionDlg::InitCtrlsParent()
{
	m_edit.SetParent(&m_list);
	m_combo.SetParent(&m_list);
}

void CUnitConvertionDlg::ShowUnits()
{
	CaplAttrValue val[2];
	val[0].attr = m_api->m_charact_mgr.a_apl_unit_convertion_item;
	val[0].value.Set(m_pdf);
	// ЯАИ по просьбе Созвездия сделал чтобы показывалось все
	//val[1].attr = m_api->m_charact_mgr.a_apl_unit_convertion_base_unit;
	//val[1].value.Set(m_baseUnit);

	aplExtent unitConvertions;
	m_api->m_data.NET_FindInstancesWithAttrValues(m_api->m_charact_mgr.e_apl_unit_convertion, 1, &val[0], unitConvertions, false);
	m_api->LoadExtentInfo(unitConvertions);

	for(int i=0; i<unitConvertions.Size; ++i)
	{
		CUnitConvertionItem *unitItem = new CUnitConvertionItem();
		unitItem->m_inst = unitConvertions[i];

		m_api->m_data.GetAttr(unitConvertions[i], m_api->m_charact_mgr.a_apl_unit_convertion_base_unit_koef, unitItem->m_baseCount);
		m_api->m_data.GetAttr(unitConvertions[i], m_api->m_charact_mgr.a_apl_unit_convertion_base_unit, unitItem->m_baseUnit);
		//unitItem->m_baseUnit = m_baseUnit;

		m_api->m_data.GetAttr(unitConvertions[i], m_api->m_charact_mgr.a_apl_unit_convertion_add_unit_koef, unitItem->m_newCount);
		m_api->m_data.GetAttr(unitConvertions[i], m_api->m_charact_mgr.a_apl_unit_convertion_add_unit, unitItem->m_newUnit);		
		
		AddUnitString(unitItem);
	}
}

void CUnitConvertionDlg::InitAnchors()
{
	AddAnchor(IDOK, BOTTOM_RIGHT);
	AddAnchor(IDCANCEL, BOTTOM_RIGHT);
	AddAnchor(IDC_LIST, TOP_LEFT, BOTTOM_RIGHT);
}
// CUnitConvertionDlg message handlers

void CUnitConvertionDlg::OnNMDblclkList(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
	
	if(-1 != pNMItemActivate->iItem && -1 != pNMItemActivate->iSubItem)
	{
		if(m_newCountColumn == pNMItemActivate->iSubItem)
		{
			StartEditField(pNMItemActivate->iItem, pNMItemActivate->iSubItem);			
		}
		else if(m_srcCountColumn == pNMItemActivate->iSubItem)
		{
			StartEditField(pNMItemActivate->iItem, pNMItemActivate->iSubItem);			
		}
		else if(m_newUnitColumn == pNMItemActivate->iSubItem)
		{
			StartComboField(pNMItemActivate->iItem, pNMItemActivate->iSubItem);			
		}
		else if(m_srcUnitColumn == pNMItemActivate->iSubItem)
		{
			StartComboField(pNMItemActivate->iItem, pNMItemActivate->iSubItem);			
		}
	}

	*pResult = 0;
}

void CUnitConvertionDlg::StartComboField(int item, int subItem)
{
	if(m_bReadOnly) return;
	CRect rect;
	if(0==subItem) m_list.GetItemRect(item,  rect, LVIR_LABEL );
	else m_list.GetSubItemRect(item, subItem, LVIR_BOUNDS , rect);

	ClientToScreen(rect);
	ScreenToClient(rect);

	CUnitConvertionItem *unitItem = reinterpret_cast<CUnitConvertionItem*>(m_list.GetItemData(item));

	CaplInstance *def_unit=0;
	if(m_newUnitColumn == subItem) def_unit=unitItem->m_newUnit;
	else def_unit=unitItem->m_baseUnit;

	if(subItem == m_newUnitColumn || subItem == m_srcUnitColumn )
	{
		FillUnitCombo(def_unit);

		for(int i=0; i<m_combo.GetCount(); ++i)
		{
			if( def_unit == reinterpret_cast<CaplInstance*>(m_combo.GetItemData(i)))
			{
				m_combo.SetCurSel(i);
				break;
			}
		}

		m_combo.MoveWindow(rect);
		m_combo.ShowWindow(SW_SHOW);
		//m_combo.SetWindowText(m_list.GetItemText(item, subItem));
		m_combo.SetFocus();

		m_item = item;
		m_subItem = subItem;
		m_currentCtrl = &m_combo;	
	}
}

void CUnitConvertionDlg::GetAllUnits()
{
	// берем все си-шные единицы измерения
	m_api->m_unit_exch_mgr.GetPrdUnits(m_allUnits);

	// ищем единицы измерения, которые уже заданы как базовые в переводах, 
	// где наша единица измерения - альтернативная (чтобы не было повторов)
	CaplAttrValue val;
	val.attr = m_api->m_charact_mgr.a_apl_unit_convertion_add_unit;
	val.value.Set(m_baseUnit);

	CaplInstance *baseUnit;
	aplExtent unitConvertions;
	m_api->m_data.NET_FindInstancesWithAttrValues(m_api->m_charact_mgr.e_apl_unit_convertion, 1, &val, unitConvertions, false);
	for(int i=0; i<unitConvertions.GetSize(); ++i)
	{
		m_api->m_data.GetAttr(unitConvertions[i], m_api->m_charact_mgr.a_apl_unit_convertion_base_unit, baseUnit);
		if(baseUnit) m_existUnitConvertions.Add(baseUnit);
	}
}

void CUnitConvertionDlg::FillUnitCombo(CaplInstance *cur_unit)
{
	CString unitName;
	m_combo.ResetContent();

	aplExtent unitInUse;
	GetUnitInUse(unitInUse);
	
	for(int i=0; i<m_allUnits.Size; ++i)
	{
		CaplInstance *unit=m_allUnits[i];
		if( (unit!=cur_unit) && ( -1 != unitInUse.Find(unit)) ) continue;
		if(-1 != m_existUnitConvertions.Find(unit))
			continue;

		m_api->m_charact_mgr.GetUnitName(m_allUnits[i], unitName);
		int index = m_combo.AddString(unitName);
		m_combo.SetItemData(index, reinterpret_cast<DWORD>(m_allUnits[i]));
	}
}

void CUnitConvertionDlg::StartEditField(int item, int subItem)
{
	if(m_bReadOnly) return;

	CRect rect;
	m_list.GetSubItemRect(item, subItem, LVIR_BOUNDS , rect);

	ClientToScreen(rect);
	ScreenToClient(rect);

	m_edit.MoveWindow(rect);
	m_edit.ShowWindow(SW_SHOW);

	m_edit.SetWindowText(m_list.GetItemText(item, subItem));
	m_edit.SetFocus();
	m_edit.SetSel(0, -1);
	m_edit.ShowCaret();

	m_item = item;
	m_subItem = subItem;
	m_currentCtrl = &m_edit;	
}

void CUnitConvertionDlg::OnDestroy()
{
	for(int i=0; i<m_list.GetItemCount(); ++i)
		delete reinterpret_cast<CUnitConvertionItem*>(m_list.GetItemData(i));
}

bool CUnitConvertionDlg::HideEditCtrl(bool copyText)
{
	if(0 == m_currentCtrl) return false;
	if(-1 == m_item || -1 == m_subItem) return false;

	double value;
	bool isStringValue = false;
	bool isNegativeValue = false;
	
	if(copyText && ::IsWindowVisible(m_currentCtrl->GetSafeHwnd()))
	{
		CString str;
		COleDateTime time;

		m_currentCtrl->GetWindowText(str);
		CUnitConvertionItem *unitItem = reinterpret_cast<CUnitConvertionItem*>(m_list.GetItemData(m_item));

		if(m_newCountColumn == m_subItem || m_srcCountColumn == m_subItem) 
		{
			// не проверяет не целые if(IsNumber(str))
			// ЯАИ 20.01.2025 измненена проверка
			bool bIsNum=true;
			int i;
			for(i=0;i<str.GetLength();i++)
			{
				TCHAR c=str[i];
				if(c==_T(',')) { str.SetAt(i,_T('.')); continue;}  // str.Replace(_T(','),_T('.'));
				if(c==_T('.')) continue;
				if(c>=_T('0') && c<=_T('9')) continue;
				bIsNum=false;
				break;
			}
			if(bIsNum)
			{
				value = __atof(str);
				if(value < 0) isNegativeValue = true;
				else
				{
					if(m_newCountColumn == m_subItem) 	unitItem->m_newCount = value;
					else unitItem->m_baseCount = value;
					
					str.Format(_T("%g"), value);
				}
			}
			else
			{
				isStringValue = true;
			}
		}
		else if(m_newUnitColumn == m_subItem || m_srcUnitColumn == m_subItem )
		{
			int index = m_combo.GetCurSel();

			if(-1 != index)
			{
				CaplInstance *unit=reinterpret_cast<CaplInstance*>(m_combo.GetItemData(index));
				m_api->m_charact_mgr.GetUnitName(unit, str);

				if(m_newUnitColumn == m_subItem) unitItem->m_newUnit = unit;
				else unitItem->m_baseUnit = unit;
			}
		
		}		

		if(false == isNegativeValue && false == isStringValue)
			m_list.SetItemText(m_item, m_subItem, str);
	}

	m_currentCtrl->ShowWindow(SW_HIDE);

	// если что то не так, то снова показываем окно редактирования
	if(true == isNegativeValue)
	{
		MessageBox( APL_T("Значение должно быть положительным!"),  APL_T("Некорректные данные"), MB_ICONINFORMATION);
		StartEditField(m_item, m_subItem);

		return false;
	}
	else if(true == isStringValue)
	{
		MessageBox( APL_T("Значение должно быть числом!"),  APL_T("Некорректные данные"), MB_ICONINFORMATION);
		StartEditField(m_item, m_subItem);

		return false;
	}

	return true;
}
void CUnitConvertionDlg::OnNMSetfocusList(NMHDR *pNMHDR, LRESULT *pResult)
{
	if(m_processSetFocusEvent)
		HideEditCtrl(true);

	*pResult = 0;
}

BOOL CUnitConvertionDlg::PreTranslateMessage( MSG* pMsg )
{
	if(pMsg->message == WM_KEYDOWN)
	{
		if(m_currentCtrl)
		{
			if(m_currentCtrl->IsWindowVisible())
			{
				if(pMsg->wParam == VK_RETURN)
				{
					HideEditCtrl(true);
					return TRUE;
				}
				else if(pMsg->wParam == VK_ESCAPE)
				{
					m_processSetFocusEvent = false;
					HideEditCtrl(false);
					m_processSetFocusEvent = true;

					return TRUE;
				}			
			}
		}
	}
	else if(WM_LBUTTONDOWN == pMsg->message)
	{
		if(pMsg->hwnd == m_list.GetHeaderCtrl()->GetSafeHwnd())
			HideEditCtrl(true);
	}

	return CaplResizableDialog::PreTranslateMessage(pMsg);
}

void CUnitConvertionDlg::OnSize( UINT nType, int cx, int cy )
{
	CaplResizableDialog::OnSize(nType, cx, cy);

	if(m_list)
	{
		int k = m_list.GetHeaderCtrl()->GetItemCount();
		CRect rect;
		m_list.GetWindowRect(&rect);
		ScreenToClient(&rect);
		cx = rect.right - rect.left - 12;

		if(k>0)
		{
			int i;
			int dx=0;
			for(i=0;i<k;i++) dx += m_list.GetColumnWidth(i);

			for(i=0; i<m_list.GetHeaderCtrl()->GetItemCount(); i++)
			{
				int l = m_list.GetColumnWidth(i);
				if(l == 0) break;

				HDITEM pHeader;
				pHeader.mask = HDI_WIDTH;
				m_list.GetHeaderCtrl()->GetItem(i, &pHeader);
				pHeader.cxy = ((cx*l)/dx)+1;
				m_list.GetHeaderCtrl()->SetItem(i, &pHeader);				
			}			
		}

		HideEditCtrl(true);
	}
}

void CUnitConvertionDlg::OnBnClickedAdd()
{
	CUnitConvertionItem *unitItem = new CUnitConvertionItem();
	unitItem->m_baseCount = m_baseCount;
	unitItem->m_baseUnit = m_baseUnit;

	AddUnitString(unitItem);
	HideEditCtrl(true);
}

void CUnitConvertionDlg::AddUnitString( CUnitConvertionItem *unitItem, int index )
{
	if(-1 == index)
	{
		index = m_list.InsertItem(m_list.GetItemCount(), _T(""));
		m_list.SetItemData(index, reinterpret_cast<DWORD>(unitItem));
	}

	CString baseUnitName, newUnitName;
	CString baseCount, newCount;

	if(unitItem->m_newUnit)
		m_api->m_charact_mgr.GetUnitName(unitItem->m_newUnit, newUnitName);

	if(unitItem->m_baseUnit)
		m_api->m_charact_mgr.GetUnitName(unitItem->m_baseUnit, baseUnitName);

	baseCount.Format(_T("%g"), unitItem->m_baseCount);
	newCount.Format(_T("%g"), unitItem->m_newCount);

	m_list.SetItemText(index, 0, baseUnitName);
	m_list.SetItemText(index, 1, baseCount);
	m_list.SetItemText(index, 2, newUnitName);
	m_list.SetItemText(index, 3, newCount);
}

void CUnitConvertionDlg::OnBnClickedDelete()
{
	HideEditCtrl(true);

	int index = m_list.GetNextItem(-1, LVIS_SELECTED);
	if(-1 == index)
	{
		AfxMessageBox( APL_T("Сначала необходимо выделить строку в списке."), MB_ICONINFORMATION);
		return;
	}

	CUnitConvertionItem *unitItem = reinterpret_cast<CUnitConvertionItem*>(m_list.GetItemData(index));
	if(0 == unitItem)
	{
		AfxMessageBox( APL_T("Объект не существует."), MB_ICONSTOP);
		return;
	}

	if(AfxMessageBox( APL_T("Вы действительно желаете удалить перевод единицы измерения?"), MB_ICONSTOP|MB_YESNO) == IDNO)
		return;

	m_list.DeleteItem(index);
	m_deletedItems.Add(unitItem);
}

void CUnitConvertionDlg::OnOK()
{
	HideEditCtrl(true);

	if(false == CheckUp()) return;
	if(false == Save()) return;

	CaplResizableDialog::OnOK();
}

bool CUnitConvertionDlg::CheckUp()
{
	for(int i=0; i<m_list.GetItemCount(); ++i)
	{
		CUnitConvertionItem *unitItem = reinterpret_cast<CUnitConvertionItem*>(m_list.GetItemData(i));
		if(0 == unitItem) continue;

		if(0 == unitItem->m_newUnit)
		{
			AfxMessageBox( APL_T("Не задана единица измерения."), MB_ICONSTOP);
			m_list.SetItemState(i, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
			return false;
		}

		if(0 == unitItem->m_newCount)
		{
			AfxMessageBox( APL_T("Не задано количество."), MB_ICONSTOP);
			m_list.SetItemState(i, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
			return false;
		}
	}

	return true;
}

bool CUnitConvertionDlg::Save()
{
	// сохраняем изменения
	for(int i=0; i<m_list.GetItemCount(); ++i)
	{
		CUnitConvertionItem *unitItem = reinterpret_cast<CUnitConvertionItem*>(m_list.GetItemData(i));
		if(0 == unitItem) continue;

		if(0 == unitItem->m_inst)
			unitItem->m_inst = m_api->m_data.CreateInstance(m_api->m_charact_mgr.e_apl_unit_convertion);

		m_api->m_data.PutAttr(unitItem->m_inst, m_api->m_charact_mgr.a_apl_unit_convertion_item, m_pdf);
		m_api->m_data.PutAttr(unitItem->m_inst, m_api->m_charact_mgr.a_apl_unit_convertion_base_unit, unitItem->m_baseUnit);
		m_api->m_data.PutAttr(unitItem->m_inst, m_api->m_charact_mgr.a_apl_unit_convertion_add_unit, unitItem->m_newUnit);
		m_api->m_data.PutAttr(unitItem->m_inst, m_api->m_charact_mgr.a_apl_unit_convertion_base_unit_koef, unitItem->m_baseCount);
		m_api->m_data.PutAttr(unitItem->m_inst, m_api->m_charact_mgr.a_apl_unit_convertion_add_unit_koef, unitItem->m_newCount);		
	}

	// удаляем объекты
	for(int j=0; j<m_deletedItems.GetSize(); ++j)
	{
		if(0 == m_deletedItems[j]->m_inst) continue;
		m_api->m_data.DeleteInstance(m_deletedItems[j]->m_inst);
	}

	return m_api->SaveChanges();
}

void CUnitConvertionDlg::GetUnitInUse( aplExtent &unitInUse )
{
	unitInUse.Clear();
	unitInUse.Add(m_baseUnit);

	for(int i=0; i<m_list.GetItemCount(); ++i)
	{
		CUnitConvertionItem *unitItem = reinterpret_cast<CUnitConvertionItem*>(m_list.GetItemData(i));
		if(unitItem) unitInUse.Add(unitItem->m_newUnit);
	}
}