// ListSortCtrl.cpp : 实现文件
//

#include "stdafx.h"
#include "ListSortCtrl.h"
//#include "..\MD5\MD5.h"
#include <strsafe.h>

// CListSortCtrl
bool CListSortCtrl::IsNumber( LPCTSTR pszText )
{
	ASSERT_VALID_STRING( pszText );
	for( int i = 0; i < lstrlen( pszText ); i++ )
		if( ! (_istdigit( pszText[ i ] )||pszText[ i ]=='.'||pszText[ i ]=='-') )
			return false;

	return true;
}

int CListSortCtrl::NumberCompare( LPCTSTR pszNumber1, LPCTSTR pszNumber2 )
{
	ASSERT_VALID_STRING( pszNumber1 );
	ASSERT_VALID_STRING( pszNumber2 );

	const float iNumber1 = _tstof( pszNumber1 );
	const float iNumber2 = _tstof( pszNumber2 );

	if( iNumber1 < iNumber2 )
		return -1;

	if( iNumber1 > iNumber2 )
		return 1;

	return 0;
}

bool CListSortCtrl::IsDate( LPCTSTR pszText )
{
	ASSERT_VALID_STRING( pszText );
	// format should be 99/99/9999.
	if( lstrlen( pszText ) != 10 )
		return false;

	return _istdigit( pszText[ 0 ] )
		&& _istdigit( pszText[ 1 ] )
		&& _istdigit( pszText[ 2 ] )
		&& _istdigit( pszText[ 3 ] )
		&& pszText[ 4 ] == _T('-')
		&& _istdigit( pszText[ 5 ] )
		&& _istdigit( pszText[ 6 ] )
		&& pszText[ 7 ] == _T('-')
		&& _istdigit( pszText[ 8 ] )
		&& _istdigit( pszText[ 9 ] );
}

int CListSortCtrl::DateCompare( const CString& strDate1, const CString& strDate2 )
{
	if(strDate1.GetLength ()!=10)return -1;
	if(strDate2.GetLength ()!=10)return -1;
	const int iYear1 = _tstoi( strDate1.Mid( 0, 4 ) );
	const int iYear2 = _tstoi( strDate2.Mid( 0, 4 ) );

	if( iYear1 < iYear2 )
		return -1;

	if( iYear1 > iYear2 )
		return 1;

	const int iMonth1 = _tstoi( strDate1.Mid( 5, 2 ) );
	const int iMonth2 = _tstoi( strDate2.Mid( 5, 2 ) );

	if( iMonth1 < iMonth2 )
		return -1;

	if( iMonth1 > iMonth2 )
		return 1;

	const int iDay1 = _tstoi( strDate1.Mid( 8, 2 ) );
	const int iDay2 = _tstoi( strDate2.Mid( 8, 2 ) );

	if( iDay1 < iDay2 )
		return -1;

	if( iDay1 > iDay2 )
		return 1;

	return 0;
}

int  CListSortCtrl::CompareByLabel( const void *elem1, const void *elem2)
{
	CStringArray *p1 = (CStringArray*)elem1;
	CStringArray *p2 = (CStringArray*)elem2;

	if( IsDate( p1->ElementAt (CListSortCtrl::m_nCompareColumn) ) )
		return CListSortCtrl::m_bSortAscending ? DateCompare( p1->ElementAt (CListSortCtrl::m_nCompareColumn), p2->ElementAt (CListSortCtrl::m_nCompareColumn) ) : DateCompare( p2->ElementAt (CListSortCtrl::m_nCompareColumn), p1->ElementAt (CListSortCtrl::m_nCompareColumn) );
	else if( IsNumber( p1->ElementAt (CListSortCtrl::m_nCompareColumn) ) )
		return CListSortCtrl::m_bSortAscending ? NumberCompare( p1->ElementAt (CListSortCtrl::m_nCompareColumn), p2->ElementAt (CListSortCtrl::m_nCompareColumn) ) : NumberCompare( p2->ElementAt (CListSortCtrl::m_nCompareColumn), p1->ElementAt (CListSortCtrl::m_nCompareColumn) );
	else
		// text.
		return CListSortCtrl::m_bSortAscending ? lstrcmp( p1->ElementAt (CListSortCtrl::m_nCompareColumn), p2->ElementAt (CListSortCtrl::m_nCompareColumn) ) : lstrcmp( p2->ElementAt (CListSortCtrl::m_nCompareColumn), p1->ElementAt (CListSortCtrl::m_nCompareColumn) );

	return true;
}

//////////////////////////////////////////////////////////////////////////
// 静态变量;
INT CListSortCtrl::m_nCompareColumn = 0;
BOOL CListSortCtrl::m_bSortAscending = FALSE;

IMPLEMENT_DYNAMIC(CListSortCtrl, CListCtrl)

CListSortCtrl::CListSortCtrl()
:m_bSortSupport(TRUE)
,m_nSortColumns(-1)
,m_strSection(_T(""))
,m_nNumColumns(0)
,m_clrLightGrid(RGB(204,204,204))
,m_clrDarkGrid(RGB(190,190,190))
{
	m_strSection = _T("");
	m_nCompareColumn = -1;
}

CListSortCtrl::~CListSortCtrl()
{
	
}

BEGIN_MESSAGE_MAP(CListSortCtrl, CListCtrl)
	ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, &CListSortCtrl::OnLvnColumnclick)
	ON_NOTIFY_REFLECT(LVN_GETDISPINFO, &CListSortCtrl::OnLvnGetdispinfo)
#ifndef __LIST_DRAW__
	ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CListSortCtrl::OnNMCustomdraw)
#endif
	ON_WM_DESTROY()
END_MESSAGE_MAP()

// CListSortCtrl 消息处理程序
void CListSortCtrl::PreSubclassWindow()
{
	// TODO: 在此添加专用代码和/或调用基类
	ASSERT( GetStyle() & LVS_REPORT );
	CListCtrl::PreSubclassWindow();
	VERIFY( m_Ctrlheader.SubclassWindow( GetHeaderCtrl()->GetSafeHwnd() ) );
}

void CListSortCtrl::RemoveAll()
{
	DeleteAllItems();
	for ( int i = 0; i < m_AryList.GetSize(); i++)
	{
		m_AryList.ElementAt(i).RemoveAll();
	}
	m_AryList.RemoveAll();
}

/************************************************************************/
/*  函数：[10/21/2016 IT];
/*  描述：;
/*  参数：;
/*  	[IN] ：;
/*  	[OUT] ：;
/*  	[IN/OUT] ：;
/*  返回：void;
/*  注意：最后一个参数，必须以NULL结尾(请看示例);
/*  示例：CListSortCtrl::SetHeadings(_T("示例1,100"),_T("示例2,100"),NULL);
/*
/*  修改：;
/*  日期：;
/*  内容：;
/************************************************************************/
BOOL CListSortCtrl::SetHeadings( IN LPCTSTR pszText, ... )
{
	if ( pszText == NULL ) return FALSE;

	va_list list;
	INT nCommaPos = 0; // 逗号位置;
	CString strColumn = _T("");
	va_start( list, pszText );
	do 
	{
		strColumn = pszText;
		if ( -1 != (nCommaPos = strColumn.Find(_T(","))))
		{
			m_strSection += strColumn.Left(nCommaPos);
			if( InsertColumn( m_nNumColumns++, strColumn.Left(nCommaPos), LVCFMT_LEFT, _tstoi( strColumn.Mid( nCommaPos + 1) ) ) == -1 )
			{
				va_end( list );
				return FALSE;
			}
		}

		pszText = va_arg( list, LPCTSTR );
	} while (pszText != NULL);

	va_end( list );

	LoadColumnInfo();
	SetExtendedStyle(LVS_EX_FLATSB|LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_HEADERDRAGDROP);

	SetListFont(_T("宋体"), 11);

	return TRUE;
}

/************************************************************************/
/*  函数：SetTextFont[3/6/2017 Jeff];
/*  描述：设置文本字体;
/*  参数：;
/*  	[IN] nTextFontSize：字体大小;
/*  	[IN] bBold：是否粗体;
/*  	[IN] bItalic：是否斜体;
/*  	[IN] strTextFontName：字体名称，如楷体;
/*  返回：void;
/*  注意：;
/*  示例：;
/*
/*  修改：;
/*  日期：;
/*  内容：;
/************************************************************************/
void CListSortCtrl::SetListFont(IN CString strFontName, IN int nFontSize, IN BOOL bBold, IN BOOL bItalic)
{
	LOGFONT lf;
	CClientDC dc(this);
	int dpy = GetDeviceCaps(dc, LOGPIXELSY); // Pixel per inch
	lf.lfHeight = -MulDiv(nFontSize, dpy, 72);
	lf.lfWeight = 0;
	lf.lfEscapement = 0;
	lf.lfOrientation = 0;
	if (bBold)
		lf.lfWeight = FW_BLACK;
	else
		lf.lfWeight = FW_NORMAL;
	lf.lfItalic = bItalic;
	lf.lfUnderline = FALSE;
	lf.lfStrikeOut = 0;
	lf.lfCharSet = ANSI_CHARSET;
	lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
	lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
	lf.lfQuality = DEFAULT_QUALITY;
	lf.lfPitchAndFamily = DEFAULT_PITCH | FF_ROMAN;

	_tcscpy_s(lf.lfFaceName, strFontName);

	// 创建字体;
	//m_cfont = GetFont();// 局部变量会导致字体设置失败,必须是全局或成员变量;
	VERIFY(m_cfont.CreateFontIndirect(&lf));
	// 选入字体;
	this->SetFont(&m_cfont);
}

void CListSortCtrl::OnLvnColumnclick(NMHDR *pNMHDR, LRESULT *pResult)
{
	// 不排序或无数据时退出;
	if ( !m_bSortSupport || m_AryList.GetSize() == 0)
		return;

	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
	m_bSortAscending = !m_bSortAscending;
	for (int i = 0; i < m_nNumColumns; i++)
	{
		if( i == pNMLV->iSubItem )
		{
			SortByCol(i);
			m_Ctrlheader.SetSortArrow( i, m_bSortAscending );
		}
	}
	Invalidate();
	
	*pResult = 0;
}

void CListSortCtrl::OnLvnGetdispinfo(NMHDR *pNMHDR, LRESULT *pResult)
{
	NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
	LV_ITEM *pItem = &pDispInfo->item;
	ASSERT(pItem);
	if (m_AryList.GetSize() > pItem->iItem && (pItem->mask & LVIF_TEXT) )//valid text buffer?
	{
		//_tcscpy_s(pItem->pszText, pItem->cchTextMax, m_AryList.ElementAt(pItem->iItem).ElementAt(pItem->iSubItem));
		StringCbCopy(pItem->pszText, pItem->cchTextMax, m_AryList.ElementAt(pItem->iItem).ElementAt(pItem->iSubItem));
	}
	*pResult = 0;
}

#ifndef __LIST_DRAW__
void CListSortCtrl::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
{
	NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );
	*pResult = 0;
	if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage )
	{
		*pResult = CDRF_NOTIFYITEMDRAW;
	}
	else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage )
	{
		INT npos = pLVCD->nmcd.dwItemSpec;
		if ( npos % 2 )
			pLVCD->clrTextBk = m_clrLightGrid;
		else 
			pLVCD->clrTextBk = m_clrDarkGrid;

		*pResult = CDRF_DODEFAULT;
	}
}
#endif

void CListSortCtrl::SortByCol(IN const int nColIndex)
{
	m_nCompareColumn = nColIndex;
	::AfxGetApp()->DoWaitCursor(TRUE);
	qsort( static_cast<void*>(&m_AryList[0]), m_AryList.GetSize(), sizeof(m_AryList[nColIndex]), CompareByLabel);
	::AfxGetApp()->DoWaitCursor(FALSE);
}

void CListSortCtrl::LoadColumnInfo()
{
	ASSERT( m_nNumColumns > 0 );
	UINT nBytes = 0;
	BYTE* buf = NULL;
	//CMD5 md5;
	//md5.SetBYTEText((BYTE*)m_strSection.GetString(), m_strSection.GetLength()*sizeof(TCHAR));
	//m_strSection = md5.GetMD5Digest();

	if( AfxGetApp()->GetProfileBinary( _T("sortlist"), m_strSection, &buf, &nBytes ) )
	{
		if( nBytes > 0 )
		{
			CMemFile memFile( buf, nBytes );
			CArchive ar( &memFile, CArchive::load );
			m_Ctrlheader.Serialize( ar );
			ar.Close();
			m_Ctrlheader.Invalidate();
		}
		delete[] buf;
	}
}

void CListSortCtrl::SaveColumnInfo()
{
	ASSERT( m_nNumColumns > 0 );
	CMemFile memFile;
	CArchive ar( &memFile, CArchive::store );
	m_Ctrlheader.Serialize( ar );
	ar.Close();
	DWORD dwLen = memFile.GetLength();
	BYTE* buf = memFile.Detach();	
	VERIFY( AfxGetApp()->WriteProfileBinary( _T("sortlist"), m_strSection, buf, dwLen ) );
	free( buf );
}

void CListSortCtrl::OnDestroy()
{
	SaveColumnInfo();
	CListCtrl::OnDestroy();
}
