#include "stdafx.h"
#include "emule.h"
#include "LogListCtrl.h"

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


#ifndef LVS_EX_LABELTIP
#define LVS_EX_LABELTIP         0x00004000 // listview unfolds partly hidden labels if it does not have infotip text
#endif

#define DFLT_MAX_LOG_MESSAGES	1000

IMPLEMENT_DYNAMIC(CLogListCtrl, CListCtrl)

BEGIN_MESSAGE_MAP(CLogListCtrl, CListCtrl)
	ON_WM_CONTEXTMENU()
	ON_WM_SIZE()
	ON_NOTIFY_REFLECT(LVN_DELETEALLITEMS, OnLvnDeleteallitems)
	ON_WM_KEYDOWN()
END_MESSAGE_MAP()

CLogListCtrl::CLogListCtrl(){
	m_iMaxLogMessages = DFLT_MAX_LOG_MESSAGES;
	m_bAutoScroll = true;
}

CLogListCtrl::~CLogListCtrl(){
}

void CLogListCtrl::Localize(){
}

void CLogListCtrl::Init(LPCTSTR pszTitle){
	SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_LABELTIP);

	InsertColumn(0, pszTitle);
	
	// if emule is started with minimum width/height of app window, we don't get a WM_SIZE
	SetColumnWidth(0, GetMaxSize());

	m_LogMenu.CreatePopupMenu();
	m_LogMenu.AddMenuTitle(GetResString(IDS_LOGENTRY));
	m_LogMenu.AppendMenu(MF_STRING,MP_COPYSELECTED, GetResString(IDS_COPY));
	m_LogMenu.AppendMenu(MF_SEPARATOR);
	m_LogMenu.AppendMenu(MF_STRING,MP_SELECTALL, GetResString(IDS_SELECTALL));
	m_LogMenu.AppendMenu(MF_STRING,MP_REMOVEALL, GetResString(IDS_PW_RESET));
	m_LogMenu.AppendMenu(MF_SEPARATOR);
	m_LogMenu.AppendMenu(MF_STRING,MP_AUTOSCROLL, GetResString(IDS_AUTOSCROLL));

	m_iMaxLogMessages = theApp.glob_prefs->GetMaxLogMessages();
	if (m_iMaxLogMessages == 0)
		m_iMaxLogMessages = DFLT_MAX_LOG_MESSAGES;
}

void CLogListCtrl::AddEntry(LPCTSTR pszMsg){
	if (m_hWnd == NULL){
		m_astrBuff.Add(pszMsg);
	}
	else{
		// 1) avoid flickering while inserting *and* deleting listview items
		// 2) avoid flickering while inserting listview items *and* calling 'EnsureVisible'
		SetRedraw(FALSE);

		if (m_astrBuff.GetSize() > 0){ // flush buffer
			for (int i = 0; i < m_astrBuff.GetSize(); i++)
				AddListItem(m_astrBuff[i]);
			m_astrBuff.RemoveAll();
		}
		AddListItem(pszMsg);

		SetRedraw(TRUE);
	}
}

void CLogListCtrl::AddListItem(LPCTSTR pszMsg){
	LVITEM Item;
	Item.mask = LVIF_TEXT;
	Item.iItem = INT_MAX;
	Item.iSubItem = 0;
	Item.pszText = (LPTSTR)pszMsg;
	int iItem = InsertItem(&Item);
	if (iItem != -1){
		if (m_iMaxLogMessages != -1){ // '-1' ... No limit!
			if (GetItemCount() > m_iMaxLogMessages)
				VERIFY( DeleteItem(0) );
			ASSERT( GetItemCount() <= m_iMaxLogMessages );
		}
		if (m_bAutoScroll)
			EnsureVisible(iItem, FALSE);
	}
}

void CLogListCtrl::Reset(){
	m_astrBuff.RemoveAll();
	SetRedraw(FALSE);
	DeleteAllItems();
	SetRedraw(TRUE);
}

void CLogListCtrl::OnLvnDeleteallitems(NMHDR *pNMHDR, LRESULT *pResult){
	// To suppress subsequent LVN_DELETEITEM notification messages, return TRUE.
	*pResult = TRUE;
}

void CLogListCtrl::OnSize(UINT nType, int cx, int cy){
	CListCtrl::OnSize(nType, cx, cy);
	int iMaxSize = GetMaxSize();
	if (iMaxSize > 0){
		int iColWidth = GetColumnWidth(0);
		if (iMaxSize > iColWidth)
			SetColumnWidth(0, iMaxSize);
	}
}

int CLogListCtrl::GetMaxSize(){
	// can't use LVSCW_AUTOSIZE_USEHEADER because it does not spare out the size of the vertical scrollbar
	//SetColumnWidth(0, LVSCW_AUTOSIZE_USEHEADER);
	CRect rcClient;
	GetClientRect(&rcClient);
	if (rcClient.Width() == 0)
		return 0;
	// Get max. size of listview column excluding the size of the vertical scrollbar
	// WinXP: GetSystemMetrics(SM_CXVSCROLL)
	// Win98: GetSystemMetrics(SM_CXVSCROLL) - GetSystemMetrics(SM_CXEDGE)*2
	int iWidth = rcClient.Width() - GetSystemMetrics(SM_CXVSCROLL);
	if (theApp.m_dwCommCtrlMjr < 6)
		iWidth -= GetSystemMetrics(SM_CXEDGE)*2;
	if (iWidth < 16)
		iWidth = rcClient.Width();
	return iWidth;
}

void CLogListCtrl::OnContextMenu(CWnd* pWnd, CPoint point){
	int iItemCount = GetItemCount();
	UINT uSelCount = GetSelectedCount();
	m_LogMenu.EnableMenuItem(MP_COPYSELECTED, uSelCount > 0 ? MF_ENABLED : MF_GRAYED);
	m_LogMenu.EnableMenuItem(MP_REMOVEALL, iItemCount > 0 ? MF_ENABLED : MF_GRAYED);
	m_LogMenu.EnableMenuItem(MP_SELECTALL, iItemCount > 0 ? MF_ENABLED : MF_GRAYED);
	m_LogMenu.CheckMenuItem(MP_AUTOSCROLL, m_bAutoScroll ? MF_CHECKED : MF_UNCHECKED);

	if (point.x == -1 && point.y == -1){
		int iIdxItem = GetNextItem(-1, LVNI_SELECTED | LVNI_FOCUSED);
		if (iIdxItem != -1){
			RECT rc;
			if (GetItemRect(iIdxItem, &rc, LVIR_BOUNDS)){
				point.x = rc.left + GetColumnWidth(0) / 2;
				point.y = rc.top + (rc.bottom - rc.top) / 2;
				ClientToScreen(&point);
			}
		}
		else{
			point.x = 16;
			point.y = 32;
			ClientToScreen(&point);
		}
	}
	m_LogMenu.TrackPopupMenu(TPM_LEFTALIGN |TPM_RIGHTBUTTON, point.x, point.y, this);
}

BOOL CLogListCtrl::OnCommand(WPARAM wParam, LPARAM lParam){
	switch (wParam) {
	case MP_COPYSELECTED:
		CopySelectedItems();
		break;
	case MP_SELECTALL:
		SelectAllItems();
		break;
	case MP_REMOVEALL:
		Reset();
		break;
	case MP_AUTOSCROLL:
		m_bAutoScroll = !m_bAutoScroll;
		break;
	}
	return TRUE;
}

CString CLogListCtrl::GetLastLogEntry(){
	CString strLog;
	int iItems = GetItemCount();
	if (iItems > 0){
		ASSERT( m_astrBuff.GetSize() == 0 );
		strLog = GetItemText(iItems - 1, 0);
	}
	else if (m_astrBuff.GetSize() > 0)
		strLog = m_astrBuff[m_astrBuff.GetSize()-1];
	return strLog;
}

CString CLogListCtrl::GetAllLogEntries(){
	CString strLog;
	int iItems = GetItemCount();
	if (iItems > 0){
		ASSERT( m_astrBuff.GetSize() == 0 );
		for (int i = 0; i < iItems; i++)
			strLog += GetItemText(i, 0) + _T("\r\n");
	}
	else{
		for (int i = 0; i < m_astrBuff.GetSize(); i++)
			strLog += m_astrBuff[i] + _T("\r\n");
	}
	return strLog;
}

void CLogListCtrl::SelectAllItems()
{
	SetItemState(-1, LVIS_SELECTED, LVIS_SELECTED);
}

void CLogListCtrl::CopySelectedItems()
{
	CString strItems;
	int iItem = -1;
	while ((iItem = GetNextItem(iItem, LVNI_SELECTED)) != -1){
		if (!strItems.IsEmpty())
			strItems += _T("\r\n");
		strItems += GetItemText(iItem, 0);
	}
	theApp.CopyTextToClipboard(strItems);
}

void CLogListCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	if (nChar == 'A' && (GetKeyState(VK_CONTROL) & 0x8000))
	{
		//////////////////////////////////////////////////////////////////
		// Ctrl+A: Select all items
		//
		if ((GetStyle() & LVS_SINGLESEL) == 0)
			SelectAllItems();
	}
	else if (nChar == 'C' && (GetKeyState(VK_CONTROL) & 0x8000))
	{
		//////////////////////////////////////////////////////////////////
		// Ctrl+C: Copy listview items to clipboard
		//
		CopySelectedItems();
	}

	CListCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
}
