// aplExListCtrlContent.cpp: implementation of the CaplExListCtrlContent class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "aplExListCtrl.h"

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

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

int		CaplExListItem::m_nDefRowHeight = 16;
int		CaplExHeaderRow::m_HH = CaplExListItem::m_nDefRowHeight+::GetSystemMetrics(SM_CYBORDER);
CPen	CaplExListItem::m_gridPen;
bool	CaplExListItem::m_Repaint = true;
COLORREF CaplExListItem::m_selColor = 0;

int		CaplExListCtrlContent::m_bookmarkInt = 700;
int		CaplExListCtrlContent::m_bookmarkMaxIntInsert = 1100;
int		CaplExListCtrlContent::m_bookmarkMaxIntAdd = 700;
int		CaplExListCtrlContent::m_bookmarkMinInDel = 300;
CString CaplExListCtrlContent::m_sEmptyStr = "";
POSITION CaplExListCtrlContent::sm_curSel = NULL;


CaplExListCtrlContent *CaplExListCtrlContent::m_listWithSel = NULL;

//////////////////////////////////////////////////////////////////////////
// CaplExHeaderRow functions

CaplExHeaderRow::CaplExHeaderRow(CWnd *par, int n, int Id, CFont &fo, bool bBorder)
{
	CRect re, re2;
	re.left = 0;
	re.top = n * m_HH;
	re.bottom = re.top + m_HH;
	par->GetWindowRect(&re2);
	re.right = re2.Width();
	if(bBorder)
	{
		re.left  += APLEXLISTCTL_BORDER;
		re.right -= APLEXLISTCTL_BORDER;
		re.top   += APLEXLISTCTL_BORDER;
		re.bottom+= APLEXLISTCTL_BORDER;
	}
	m_hc.Create(WS_CHILD|WS_VISIBLE|HDS_HORZ|HDS_BUTTONS|HDS_FULLDRAG, re, par, Id);
	m_hc.SetFont(&fo);
	m_subHeader = NULL;
	m_countItems = 0;
}

int  CaplExHeaderRow::Width()
{
	HDITEM hd;
	hd.mask = HDI_WIDTH;
	int w = 0, co = m_hc.GetItemCount();
	for (int i=0; i<co; i++)
	{
		m_hc.GetItem(i, &hd);
		w += hd.cxy;
	}
	return w;
}

void CaplExHeaderRow::SetWidthProp(int w)
{
	int co = m_hc.GetItemCount();
	if(co < 1) return;
	int ow = Width();
	if(ow == w) return;
	/*

	int i,s=0;
	HDITEM hd;
	hd.mask = HDI_WIDTH;
	int *ws = new int[co];
	for (i=0; i<co; i++)
	{
		m_hc.GetItem(i, &hd);
		ws[i] = hd.cxy * w / ow;
		s += ws[i];
	}
	
	for (i=0; i<co; i++)
	{
		hd.cxy = ws[i];
		m_hc.SetItem(i, &hd);
	}
	*/
}

void CaplExHeaderRow::SetWidth(int w)
{
	int co = m_hc.GetItemCount();
	if(co < 1) return;
	int ow = Width();
	if(ow == w) return;
	HDITEM hd;
	hd.mask = HDI_WIDTH;
	int dw;
	
	if(ow < w)
	{
		dw = w - ow;
		m_hc.GetItem(co-1, &hd);
		hd.cxy += dw;
		m_hc.SetItem(co-1, &hd);
		return;
	}

	dw = ow - w;
	int md = 4;
	if(w < (co<<2)) md = 0;
	int dxy, i = co-1;
	while((dw > 0) && (i>=0))
	{
		m_hc.GetItem(i, &hd);
		dxy = hd.cxy - dw;
		if(dxy < md) dxy = md;
		if(hd.cxy <= dxy)
		{
			i--;
			continue;
		}
		dw -= hd.cxy - dxy;
		hd.cxy = dxy;
		m_hc.SetItem(i, &hd);
		i--;
	}
}

void CaplExHeaderRow::InsertItem(int p, LPTSTR text, int w, UINT fmt, aplEditTypes mode, CStringArray *pStrs)
{
	HDITEM item;
	item.mask = HDI_FORMAT|HDI_WIDTH|HDI_TEXT|HDI_LPARAM;
	item.pszText = text;
	item.cxy = w;
	item.fmt = fmt;
	item.cchTextMax = 100;
	item.lParam = (LPARAM)(new CaplHeaderStruct(mode, pStrs, 0));
	item.hbm = NULL;
	
	m_hc.InsertItem(p,&item);
}

void CaplExHeaderRow::SetModes(CaplExListItem *li, int b, int e)
{
	int co = m_hc.GetItemCount();
	if(co<e) e = co;
	HDITEM hdit;
	hdit.mask = HDI_LPARAM;
	for (int i=b; i<e; i++)
	{
		m_hc.GetItem(i, &hdit);
		CaplModeStruct *ms = (CaplModeStruct *)hdit.lParam;
		li->m_smodes.ElementAt(i).Copy(*ms, 1);
	}
}

void CaplExHeaderRow::DeleteItem(int p)
{
	if((p<0)||(p>=m_hc.GetItemCount())) return;
	HDITEM item;
	item.mask = HDI_LPARAM;
	m_hc.GetItem(p, &item);
	CaplModeStruct *ms = (CaplModeStruct*)item.lParam;
	if(ms)
	{
		ms->Free();
		delete ms;
	}
	m_hc.DeleteItem(p);
}

void CaplExHeaderRow::Clear()
{
	int i, co = m_hc.GetItemCount();
	HDITEM item;
	CaplModeStruct *ms;
	item.mask = HDI_LPARAM;
	for (i=co - 1; i>=0; i--)
	{
		m_hc.GetItem(i, &item);
		ms = (CaplModeStruct*)item.lParam;
		if(ms)
		{
			ms->Free();
			delete ms;
		}
		m_hc.DeleteItem(i);
	}
}

void CaplExHeaderRow::HScroll(int pos, CRect &pre, int nb)
{
	int p = pos;
	CRect re;
	m_hc.GetWindowRect(&re);
	re.OffsetRect(-pre.left, -pre.top);
	re.left = -p+nb;
	m_hc.MoveWindow(&re);
}

void CaplExHeaderRow::SetEnableSort(bool bSort)
{
	if(bSort) m_hc.ModifyStyle(0, HDS_BUTTONS);
	else m_hc.ModifyStyle(HDS_BUTTONS, 0);
}

int  CaplExHeaderRow::GetSortType(int n, bool bRevers)
{
	if((n < 0) || (n >= m_hc.GetItemCount())) return 0;
	HDITEM hd;
	hd.mask = HDI_LPARAM;
	m_hc.GetItem(n, &hd);
	CaplHeaderStruct *hs = (CaplHeaderStruct *)hd.lParam;
	if(!hs) return 0;
	int ret = hs->iSortType;
	if(bRevers) hs->iSortType ^= 1;
	return ret;
}

bool CaplExHeaderRow::Split(int col, int count)
{
	HDITEM hdi;
	hdi.mask = HDI_WIDTH|HDI_LPARAM|HDI_FORMAT;
	m_hc.GetItem(col, &hdi);
	UINT fmt = hdi.fmt;
	CaplHeaderStruct *hs = (CaplHeaderStruct *)hdi.lParam;
	hdi.mask = HDI_WIDTH;
	int d = hdi.cxy / count;
	int i,p = hdi.cxy % count;
	
	if(p>0)
		hdi.cxy = d+1;
	else
		hdi.cxy = d;
	m_hc.SetItem(col, &hdi);
	int ww;
	for (i=1; i<count; i++)
	{
		if(p>i) ww = d+1;
		else ww = d;
		InsertItem(col+i, _T(""), ww, fmt, hs->mode, hs->pStrs);
	}
	
	return true;
}

//////////////////////////////////////////////////////////////////////////
// CaplExListItem functions

CaplExListItem::CaplExListItem(CaplExListItem *parent)
{
	m_header = NULL;
	m_parentItem = parent;
	m_absCount = 1;
	m_childCount = 0;
	if(m_parentItem)
	{
		m_parentItem->m_childCount ++;
		m_parentItem->IncAbs(1);
	}
	m_subItems = NULL;
	m_imageIndex = -1;
}

CaplExListItem::~CaplExListItem()
{
	for (int i=0; i<m_smodes.GetSize(); i++)
	{
		m_smodes.ElementAt(i).Free();
	}
	delete m_subItems;
}

void CaplExListItem::IncAbs(int n)
{
	CaplExListItem *item = this;
	while (item)
	{
/* //bm
		item->m_bookmark->m_absCount += n;
*/
		item->m_absCount += n;
		item->m_thisList->m_absCount += n;
		item = item->m_parentItem;
	}
}

void CaplExListItem::DecAbs(int n)
{
	CaplExListItem *item = this;
	while (item)
	{
/*  // bm
		item->m_bookmark->m_absCount -= n;
*/
		item->m_absCount -= n;
		item->m_thisList->m_absCount -= n;
		item = item->m_parentItem;
	}
}

void CaplExListItem::SetMode(int n, aplEditTypes mode, CStringArray *pStrs, int bS)
{
	if((n<0)||(n>=m_smodes.GetSize())) return;
	m_smodes.ElementAt(n).Copy(mode, pStrs, bS);
}

void CaplExListItem::ResetArrays(bool text, bool mode)
{
	/*
	if(!m_header) return;
	int co, hco = m_header->m_waI2H.GetSize();
	if(text)
	{
		co = m_cells.GetSize();
		if(co < hco) m_cells.SetSize(hco);
	}
	if(mode)
	{
		co = m_modes.GetSize();
		if(co < hco) 
		{
			m_modes.SetSize(hco);
			m_strsCombo.SetSize(hco);
			m_header->SetModes(this, co, hco);
		}
	}
	*/
}


void CaplExListItem::SetHeader(CaplExHeaderRow *h)
{
	m_header = h;
	int co = h->m_hc.GetItemCount();
	m_cells.SetSize(co);
	m_smodes.SetSize(co);
	h->SetModes(this, 0, co);
	h->m_countItems++;
}

//////////////////////////////////////////////////////////////////////////
// CaplExListCtrlContent functions

CaplExListCtrlContent::CaplExListCtrlContent()
{
	m_header = NULL;
	m_absCount = 0;
	m_parentItem = NULL;
	m_parentList = NULL;
	m_bExpanded = true;
}

int  CaplExListCtrlContent::Height()
{
	return m_absCount * CaplExListItem::m_nDefRowHeight;
}

POSITION CaplExListCtrlContent::GetAt(int n)
{
	if((m_items.GetCount()<=n) || (m_items.GetCount()<1)) return NULL;
	if((m_items.GetCount()-1 == n)||(n<0))
		return m_items.GetTailPosition();
	POSITION pos;

/*  // bm
	pos = m_bookmarks.GetHeadPosition();
	while (m_bookmarks.GetAt(pos)->m_count <= n)
	{
		 n -= m_bookmarks.GetAt(pos)->m_count;
		 m_bookmarks.GetNext(pos);
	}
	pos = m_bookmarks.GetAt(pos)->m_itempos;
*/
	pos = pos = m_items.GetHeadPosition();  // no bm
	while (n > 0)
	{
		 m_items.GetNext(pos);
		 --n;
	}
	return pos;
}

void CaplExListCtrlContent::GetAbsAt(int n, POSITION &itempos, CaplExListCtrlContent *&lst)
{
	if((lst->m_absCount <= n) || (n < 0))
	{
		itempos = NULL;
		lst = NULL;
		return;
	}
	POSITION pos;

/*  // bm
	pos = lst->m_bookmarks.GetHeadPosition();
	while (lst->m_bookmarks.GetAt(pos)->m_absCount <= n)
	{
		 n -= lst->m_bookmarks.GetAt(pos)->m_absCount;
		 lst->m_bookmarks.GetNext(pos);
	}
	pos = lst->m_bookmarks.GetAt(pos)->m_itempos;
*/
	pos = lst->m_items.GetHeadPosition();   // no bm
	while (lst->m_items.GetAt(pos)->m_absCount <= n)
	{
		 n -= lst->m_items.GetAt(pos)->m_absCount;
		 lst->m_items.GetNext(pos);
	}
	if(n<=0) 
	{
		itempos = pos;
		return;
	}
	else	 
	{
		lst = lst->m_items.GetAt(pos)->m_subItems;
		GetAbsAt(n-1, pos, lst);
		itempos = pos;
	}
}

POSITION CaplExListCtrlContent::Insert(CaplExListItem *item, POSITION pos)
{
	if((item->m_header != NULL) && (item->m_header != m_header)) return NULL;
	POSITION rpos = m_items.InsertBefore(pos, item);
	item->m_thisList = this;
	m_absCount += item->m_absCount;
	item->SetHeader(m_header);

/*  //bm

	CaplExListItem *li = m_items.GetAt(pos);
	CaplBookmarkItem *bi = li->m_bookmark;

	if(bi->m_count >= m_bookmarkMaxIntInsert)
	{
		POSITION fp = pos;
		if(bi->m_itempos == pos)
			fp = rpos;
		bi->m_absCount += item->m_absCount;
		bi->m_count++;
		CaplBookmarkItem *nbi = new CaplBookmarkItem(fp, 0);
		nbi->m_bmpos = m_bookmarks.InsertBefore(bi->m_bmpos, nbi);
		int d = m_bookmarkMaxIntInsert - m_bookmarkInt;
		for (int i=0; i<d; i++)
		{
			li = m_items.GetNext(fp);
			li->m_bookmark = nbi;
			nbi->m_absCount += li->m_absCount;
			bi->m_absCount -= li->m_absCount;
		}
		nbi->m_count = d;
		bi->m_itempos = fp;
		bi->m_count -= d;
	}
	else
	{
		bi->m_count++;
		bi->m_absCount += item->m_absCount;
		if(bi->m_itempos == pos)
			bi->m_itempos = rpos;
		item->m_bookmark = bi;
	}
*/

	return rpos;
}

POSITION CaplExListCtrlContent::Add(CaplExListItem *item)
{
	if((item->m_header != NULL) && (item->m_header != m_header)) return NULL;
	POSITION rpos = m_items.AddTail(item);
	item->m_thisList = this;
	m_absCount += item->m_absCount;
	item->SetHeader(m_header);
	
/*  // bm
	CaplBookmarkItem *bi = NULL;
	if(m_bookmarks.GetCount() == 0)
	{
		bi = new CaplBookmarkItem(rpos, item->m_absCount);
		bi->m_bmpos = m_bookmarks.AddTail(bi);
	}
	else
	{
		bi = m_bookmarks.GetTail();
		if(bi->m_count >= m_bookmarkMaxIntAdd)
		{
			bi = new CaplBookmarkItem(rpos, item->m_absCount);
			bi->m_bmpos = m_bookmarks.AddTail(bi);
		}
		else
		{
			bi->m_count++;
			bi->m_absCount += item->m_absCount;
		}
	}
	item->m_bookmark = bi;
*/
	return rpos;
}

void CaplExListCtrlContent::Delete(int pos)
{
	
}

void CaplExListCtrlContent::Delete(POSITION pos)
{
	if(m_items.GetCount()<1) return;
	CaplExListItem *li = m_items.GetAt(pos);
	
	if(m_items.GetCount() == 1)
	{
//		li->m_parentItem->m_childCount--;
		if(li->m_parentItem)
			li->m_parentItem->DecAbs(li->m_absCount);
		DeleteAll();
		m_absCount = 0;
		m_header->m_countItems --;
		return;
	}
	if(li->m_parentItem)
		li->m_parentItem->DecAbs(li->m_absCount);
	m_absCount -= li->m_absCount;
	m_header->m_countItems--;
/*  // bm
//////////////////////////////////////////////////////////////////////////
	li->m_bookmark->m_absCount -= li->m_absCount;
	li->m_bookmark->m_count--;

	if(li->m_bookmark->m_count == 0) 
	{
		m_bookmarks.RemoveAt(li->m_bookmark->m_bmpos);
		delete li->m_bookmark;
		m_items.RemoveAt(pos);
		delete li;
		return;
	}

	POSITION bp = li->m_bookmark->m_bmpos; // закладка данного елемента
	POSITION fip = li->m_bookmark->m_itempos; // первый элемент закладки
	if(fip == pos) // удаляемый элемент - это первый элемент закладки
	{
		m_items.GetNext(fip);
		li->m_bookmark->m_itempos = fip; // сдвигаем закладку вправо
	}
	
	if((li->m_bookmark->m_count <= m_bookmarkMinInDel) && (m_bookmarks.GetCount()>1))
	{
		int i;
		POSITION bpr, bpl;
		bpr = bpl = bp;
		CaplBookmarkItem *bidr, *bidl;
		CaplExListItem *li1;
		if(bp == m_bookmarks.GetHeadPosition()) // наша закладка - первая
		{
			m_bookmarks.GetNext(bpr);
			bidr = m_bookmarks.GetAt(bpr); // закладка справа от нашей
			POSITION eip = bidr->m_itempos; // первый элемент закладки справа

			// если общее число элементов этих закладок меньше максимального
			// то объединяем закладки
			if(bidr->m_count + li->m_bookmark->m_count <= m_bookmarkMaxIntInsert)
			{
				bidr->m_itempos = fip;
				while (fip != eip)
				{
					li1 = m_items.GetNext(fip);
					li1->m_bookmark = bidr;
					bidr->m_count++;
					bidr->m_absCount += li1->m_absCount;
				}
				delete li->m_bookmark;
				m_bookmarks.RemoveAt(bp);
			}
			else  // иначе часть элементов закладки справа передаем нашей
			{
				int d = bidr->m_count - m_bookmarkInt;
				for (i=0; i<d; i++)
				{
					li1 = m_items.GetNext(eip);
					li1->m_bookmark = li->m_bookmark;
					li->m_bookmark->m_count ++;
					li->m_bookmark->m_absCount += li1->m_absCount;
					bidr->m_count --;
					bidr->m_absCount -= li1->m_absCount;
				}
				if(d>0) bidr->m_itempos = eip;
			}
			
		}

		else if(bp != m_bookmarks.GetTailPosition()) // наша закладка - не первая(и не послед.)
		{
			m_bookmarks.GetNext(bpr);
			m_bookmarks.GetPrev(bpl);
			bidr = m_bookmarks.GetAt(bpr);
			bidl = m_bookmarks.GetAt(bpl);

			POSITION p2 = pos;
			CaplExListItem *li2;

			int summ = bidr->m_count + bidl->m_count + li->m_bookmark->m_count;
			

			// если число элементов в 3 закладках меньше 2 максимальных, то делаем из 3 2
			if(summ < (m_bookmarkMaxIntInsert<<1))
			{
				pr = pos;
				
				int psumm1, psumm2 = summ>>1;
				if((summ & 1) == 1) psumm1 = psumm2+1;
				else psumm1 = psumm2;
				while(bidl->m_count>psumm1)
				{

				}
			}
			else
			{
	// перераспределение элементов между 3-мя закладками
			}
		}
	}
//////////////////////////////////////////////////////////////////////////
//*/
	m_items.RemoveAt(pos);
	delete li;
}

void CaplExListCtrlContent::DeleteAll()
{
	if(m_header)
		m_header->m_countItems -= m_items.GetCount();
	POSITION p;
/*  // bm
	p = m_bookmarks.GetHeadPosition();
	while(p)
		delete m_bookmarks.GetNext(p);

	m_bookmarks.RemoveAll();
//*/
	
	p=m_items.GetHeadPosition(); // no bm
	while(p)
	{
		delete m_items.GetNext(p);
	}

	m_items.RemoveAll();
	m_absCount = 0;
	
}

const CString &CaplExListCtrlContent::GetItemText(POSITION p, int i)
{
	CaplExListItem *li = m_items.GetAt(p);
	if((i < 0) || (i >= li->m_cells.GetSize()))
		return m_sEmptyStr;
	return li->m_cells.ElementAt(i);
}

bool CaplExListCtrlContent::SetItemText(POSITION p, int i, LPCTSTR str)
{
	
	CaplExListItem *li = m_items.GetAt(p);
	if((i < 0) || (i >= li->m_cells.GetSize()))
		return false;
	li->m_cells.SetAt(i, str);
	return true;
}

bool CaplExListCtrlContent::SetItemData(POSITION p, DWORD da)
{
	m_items.GetAt(p)->m_data = da;
	return true;
}

DWORD CaplExListCtrlContent::GetItemData(POSITION p)
{
	return m_items.GetAt(p)->m_data;
}

int CaplExListCtrlContent::GetAbsIndex(POSITION p)
{
	int co = 0;
	POSITION pos;
	if(m_parentList)
	{
		co = m_parentList->GetAbsIndex(m_parentItem) + 1;
	}

/*
	CaplExListItem *li = m_items.GetAt(p);
	CaplBookmarkItem *bi = li->m_bookmark;
	pos = m_bookmarks.GetHeadPosition();
	CaplBookmarkItem *bb = NULL;
	while (bb != bi)
	{
		bb = m_bookmarks.GetNext(pos);
		co += bb->m_absCount;
	}
	pos = bi->m_itempos;
*/
	pos = m_items.GetHeadPosition();

	CaplExListItem *li1 = NULL;
	while ((pos) && (pos != p))
	{
		li1 = m_items.GetNext(pos);
		co += li1->m_absCount;
	}
	if(!pos) return -1;
	return co;
}

aplEditTypes CaplExListItem::GetMode(int cell, CStringArray *&pStrs)
{
	pStrs = NULL;
	if((cell < 0) || (cell >= m_smodes.GetSize()))
		return aplNone;
	pStrs = m_smodes.ElementAt(cell).pStrs;
	return m_smodes.ElementAt(cell).mode;
}

bool CaplExListItem::GetInfo(int x, CRect &re, int &cell)
{
	int i, co = m_header->m_hc.GetItemCount();
	HDITEM hdi;
	hdi.mask = HDI_WIDTH;
	int x0 = 0;
	for (i=0; i<co; i++)
	{
		m_header->m_hc.GetItem(i,&hdi);
		if(hdi.cxy>=x) break;
		x -= hdi.cxy;
		x0 += hdi.cxy;
	}
	if(i == co) return false;
	re.left = x0;
	re.right = x0 + hdi.cxy+1;
	cell = i;
	return true;
}

//////////////////////////////////////////////////////////////////////////
// отрисовка

void CaplExListItem::Paint(CDC &dc, CRect &re, bool grid, bool sel, int iw, CImageList *pImageList)
{
	int i, hco = m_header->m_hc.GetItemCount();
	int lco = m_cells.GetSize();
	CRect re1(re.left, re.top+1, re.left, re.top+m_nDefRowHeight);
	HDITEM hd;
	hd.mask = HDI_WIDTH|HDI_FORMAT;
	UINT uFormat;
	COLORREF oldcl;
	if(sel)
	{
		oldcl = dc.GetBkColor();
		int dww = iw;
		if(iw > 0) dww += 2;
		if(::GetFocus()==m_header->m_hc.GetParent()->m_hWnd)
			dc.FillSolidRect(re.left+dww, re.top+1, re.right - re.left - dww, m_nDefRowHeight, ::GetSysColor(COLOR_HIGHLIGHT));
		else
			dc.FillSolidRect(re.left+dww, re.top+1, re.right - re.left - dww, m_nDefRowHeight, ::GetSysColor(COLOR_3DDKSHADOW));
		dc.SetTextColor(RGB(255, 255, 255));
	}
	if(pImageList)
	{
		if((m_imageIndex >= 0) && (m_imageIndex < pImageList->GetImageCount()) && (re.left > -(iw+6)))
		{
			pImageList->Draw(&dc, m_imageIndex, CPoint(re.left+1, re.top+1), ILD_NORMAL|ILD_TRANSPARENT);
		}
	}
	
	re1.right--;
	for (i=0; i<hco; i++)
	{
		m_header->m_hc.GetItem(i, &hd);

		re1.left = re1.right+3;
		if(i == 0) re1.left += iw;
		re1.right += hd.cxy-2;
		
	//	uFormat = (((hd.fmt&HDF_RIGHT) == HDF_RIGHT) ? HDF_RIGHT : (((hd.fmt&HDF_CENTER) == HDF_CENTER) ? DT_CENTER : DT_LEFT));
	
		if((hd.fmt & HDF_RIGHT) == HDF_RIGHT) uFormat = DT_RIGHT;
		else if((hd.fmt & HDF_CENTER) == HDF_CENTER) uFormat = DT_CENTER;
		else uFormat = DT_LEFT;

		dc.DrawText(m_cells.ElementAt(i), re1, DT_BOTTOM|uFormat|DT_SINGLELINE);
		re1.right+=2;

		if(grid)
		{
			CPen *op = dc.SelectObject(&m_gridPen);
			dc.MoveTo(re1.right, re1.top);
			dc.LineTo(re1.right, re1.bottom);
			dc.SelectObject(op);
		}
	}
	re.top += m_nDefRowHeight;
	if(grid)
	{
		CPen *op = dc.SelectObject(&m_gridPen);
		dc.MoveTo(0, re.top);
		dc.LineTo(re.right, re.top);
		dc.SelectObject(op);
	}
	if(sel)
	{
		dc.SetBkColor(oldcl);
		dc.SetTextColor(0);
	}
}

void CaplExListCtrlContent::Paint(CDC &dc, int b, CRect &re, bool grid, int iw, CImageList *pImageList)
{
	if(m_items.GetCount() < 1) return;
	
	CaplExListCtrlContent *lst = this;
	POSITION pos = NULL;
	GetAbsAt(b, pos, lst);
	CaplExListItem *li;
	while((pos) && (re.top < re.bottom))
	{
		li = lst->m_items.GetAt(pos);
		li->Paint(dc, re, grid, (pos == sm_curSel), iw, pImageList);
		GetAbsNextItem(pos, lst);
	}
}

void CaplExListCtrlContent::GetAbsNextItem(POSITION &itempos, CaplExListCtrlContent *&lst)
{
	CaplExListItem *item = lst->m_items.GetAt(itempos);
	if(item->m_subItems)
	{
		if (item->m_subItems->m_items.GetCount()>0) //сюда добавить код, если будет сворачивание
		{
			lst = item->m_subItems;
			itempos = lst->m_items.GetHeadPosition();
			return;
		}
	}
	lst->m_items.GetNext(itempos);
	while (itempos == NULL)
	{
		itempos = lst->m_parentItem;
		if(itempos)
		{
			lst = lst->m_parentList;
			lst->m_items.GetNext(itempos);
		}
		else return;
	}
}

bool CaplExListCtrlContent::MoveUp(POSITION pos)
{
	return m_items.MoveUp(pos);
}

bool CaplExListCtrlContent::MoveDown(POSITION pos)
{
	return m_items.MoveDown(pos);
}



void CaplExListItem::DelCell(int c)
{
	m_cells.RemoveAt(c);
	m_smodes.ElementAt(c).Free();
	m_smodes.RemoveAt(c);
}

void CaplExListItem::AddCells(int b, int co)
{
	m_cells.InsertAt(b, "", co);
	CaplModeStruct ms;
	m_smodes.InsertAt(b, ms, co);
	m_header->SetModes(this, b, co);
}

void CaplExListCtrlContent::DelCell(CaplExListCtrlContent *lst, int delcol, int p)
{
	if((delcol<0) || (delcol >= lst->m_header->m_hc.GetItemCount())) return;
	POSITION pos = lst->m_items.GetHeadPosition();
	CaplExListItem *li;
	while (pos)
	{
		li = lst->m_items.GetNext(pos);
		li->DelCell(delcol);
	}
}

void CaplExListCtrlContent::AddCells(CaplExListCtrlContent *lst, int addcol, int n)
{
	if((addcol<0) || (addcol >= lst->m_header->m_hc.GetItemCount())) return;
	POSITION pos = lst->m_items.GetHeadPosition();
	CaplExListItem *li;
	while (pos)
	{
		li = lst->m_items.GetNext(pos);
		li->AddCells(addcol, n);
	}
}

void CaplExListCtrlContent::Sort(CaplExListCtrlContent *lst, int sortcol, int type)
{
	if((sortcol < 0) || (sortcol >= lst->m_header->m_hc.GetItemCount())) return;
	if(type == 0)
		lst->m_items.Sort(sortcol, CaplExListItem::menshe);
	else
		lst->m_items.Sort(sortcol, CaplExListItem::bolshe);
}

void CaplExListCtrlContent::EnumLevelLists(int level, LPFN_ENUMLEVELLIST fn, int p1, int p2)
{
	if(level < 1)
	{
		fn(this, p1, p2);
	}
	else
	{
		CaplExListItem *li;
		POSITION p = m_items.GetHeadPosition();
		while(p)
		{
			li = m_items.GetNext(p);
			if(li->m_subItems)
				li->m_subItems->EnumLevelLists(level-1, fn, p1, p2);
		}
	}
}

//////////////////////////////////////////////////////////////////////////
// добавки к списку

CaplExListItem *CLIList::GetItemByHLI(HLISTITEM item)
{
	return ((CNode *)item)->data;
}

HLISTITEM CLIList::GetNextHLI(HLISTITEM item, bool bNext)
{
	return (HLISTITEM)(bNext ? ((CNode *)item)->pNext : ((CNode *)item)->pPrev);
}

bool CLIList::MoveUp(POSITION pos)
{
	CNode *nodep = (CNode *)pos;
	if(nodep == m_pNodeHead) return false;

	if(nodep->pNext) nodep->pNext->pPrev = nodep->pPrev;	//1
	nodep->pPrev->pNext = nodep->pNext;						//2
	nodep->pNext = nodep->pPrev;							//3
	nodep->pPrev = nodep->pPrev->pPrev;
	if(nodep->pPrev) nodep->pPrev->pNext = nodep;
	nodep->pNext->pPrev = nodep;

	if(nodep->pNext == m_pNodeHead) m_pNodeHead = nodep;
	if(nodep == m_pNodeTail) m_pNodeTail = nodep->pNext;
	
	return true;
}

bool CLIList::MoveDown(POSITION pos)
{
	CNode *nodep = (CNode *)pos;
	if(nodep == m_pNodeTail) return false;
	return MoveUp((POSITION)((CNode *)pos)->pNext);
}

int  CaplExListItem::menshe(CaplExListItem *fi, CaplExListItem *si, int pos)
{
	// if fi < si, ret 1, else 0
	return fi->m_cells.ElementAt(pos).CompareNoCase(si->m_cells.ElementAt(pos))<0 ? 1 : 0;
}

int  CaplExListItem::bolshe(CaplExListItem *fi, CaplExListItem *si, int pos)
{
	// if fi > si, ret 1, else 0
	return fi->m_cells.ElementAt(pos).CompareNoCase(si->m_cells.ElementAt(pos))>0 ? 1 : 0;
}

void CLIList::Cut(CNode *posBeg, int n, CLIList &dest)
{
	CNode *posEnd = posBeg;
	int n1 = n;
	while((n1>1) && (posEnd->pNext))
	{
		posEnd = posEnd->pNext;
		--n1;
	}
	int dn = n - n1 + 1;
	m_nCount -= dn;
	if(posBeg->pPrev) posBeg->pPrev->pNext = posEnd->pNext;
	if(posEnd->pNext) posEnd->pNext->pPrev = posBeg->pPrev;
	if(posBeg == m_pNodeHead) m_pNodeHead = posEnd->pNext;
	if(posEnd == m_pNodeTail) m_pNodeTail = posBeg->pPrev;
	posBeg->pPrev = dest.m_pNodeTail;
	posEnd->pNext = NULL;
	if(dest.m_pNodeHead == NULL)
	{
		dest.m_pNodeHead = posBeg;
	}
	if(dest.m_pNodeTail)
	{
		dest.m_pNodeTail->pNext = posBeg;
	}
	dest.m_pNodeTail = posEnd;
	dest.m_nCount += dn;
}

void CLIList::Sort(int pos, int (*fncmp)(CaplExListItem *,CaplExListItem *,int))
{
	if(m_nCount<2) return;
	int sl = 1, k, l[2];
	CLIList tmp[2];
	while(sl < m_nCount)
	{
		k = 0;
		while(m_nCount)
		{
			Cut(m_pNodeHead, sl, tmp[k]);
			k = k^1;
		}
		l[0] = l[1] = 0;
		while ((tmp[0].m_nCount > 0) && (tmp[1].m_nCount > 0))
		{
			k = fncmp(tmp[1].m_pNodeHead->data, tmp[0].m_pNodeHead->data, pos);
			tmp[k].Cut(tmp[k].m_pNodeHead, 1, *this);
			++l[k];
			if(l[k] == sl)
			{
				k = k ^ 1;
				tmp[k].Cut(tmp[k].m_pNodeHead, sl-l[k], *this);
				l[0] = l[1] = 0;
			}
		}
		  
		if(tmp[0].m_nCount > 0)		 tmp[0].Cut(tmp[0].m_pNodeHead, tmp[0].m_nCount, *this);
		else if(tmp[1].m_nCount > 0) tmp[1].Cut(tmp[1].m_pNodeHead, tmp[1].m_nCount, *this);
		sl<<=1;
	}
}
