/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 1, or (at your option)
** any later version.

** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.

** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
 * Author : Jerzy Kaczorowski <kaczoroj@hotmail.com> --- July 2001
 */

// HistComboBoxEx.cpp : implementation file
//

#include "stdafx.h"
#include "wincvs.h"
#include "HistComboBoxEx.h"
#include "FileTraversal.h"
#include "CvsEntries.h"

#include "MainFrm.h"
#include "CvsAlert.h"

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

static PCPStr gOldLoc("P_BrowserLoc", "C:\\");
static CMString gHistoryLocs(100, "P_BrowserLocs");

int TraverseHistory(CHistComboBoxEx& browseHist)
{
	char szPath[MAX_PATH] = "";
	for( int nIndex = 0; nIndex < browseHist.GetCount(); nIndex++ )
	{
		COMBOBOXEXITEM cbi;
		cbi.mask = CBEIF_TEXT;
		cbi.iItem = nIndex;
		cbi.pszText = szPath;
		cbi.cchTextMax = MAX_PATH;
		
		browseHist.GetItem(&cbi);
		browseHist.SetIcon(cbi);
	}

	return nIndex;
}

/////////////////////////////////////////////////////////////////////////////
// CHistComboBoxEx

CHistComboBoxEx::CHistComboBoxEx()
{
}

CHistComboBoxEx::~CHistComboBoxEx()
{
}


BEGIN_MESSAGE_MAP(CHistComboBoxEx, CComboBoxEx)
	//{{AFX_MSG_MAP(CHistComboBoxEx)
	ON_CONTROL_REFLECT(CBN_DROPDOWN, OnDropdown)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CHistComboBoxEx message handlers

const char* CHistComboBoxEx::GetOldLoc()
{
	return gOldLoc;
}

int CHistComboBoxEx::NewRoot(const char* root)
{
	if(stricmp(gOldLoc, root) != 0)
		gOldLoc = root;
	
	// update the history combo
	gHistoryLocs.Insert(root);
	ResetContent();
	const std::vector<CStr> & list = gHistoryLocs.GetList();
	std::vector<CStr>::const_iterator i;
	for(i = list.begin(); i != list.end(); ++i)
	{
		InsertString(-1, *i);
	}
	SetCurSel(0);
	TRACE("Browse History has %d items\n", GetCount());

	return GetCount();
}

int CHistComboBoxEx::InsertString(int nIndex, LPCTSTR lpszString)
{
	int nRes = -1;

	COMBOBOXEXITEM cbi;
	cbi.mask = CBEIF_TEXT;
	cbi.iItem = 0 > nIndex ? GetCount() : nIndex;
	cbi.pszText = (LPTSTR)lpszString;		//this cast is safe because we are Inserting item
	cbi.cchTextMax = 0;

	nRes = InsertItem(&cbi);
	SetIcon(cbi);

	return nRes;
}

int CHistComboBoxEx::AddString(LPCTSTR lpszString)
{
	return InsertString(-1, lpszString);
}

BOOL CHistComboBoxEx::SetIcon(COMBOBOXEXITEM cbi)
{
	//initialize the image list if neccessary
	if( m_ImageList.m_hImageList == 0L )
	{
		m_ImageList.Create(IDB_HISTLOC, HISTLOC_IMAGE_CX, 1, RGB(255, 255, 255));
		SetImageList(&m_ImageList);
	}
	
	cbi.mask = CBEIF_IMAGE | /*CBEIF_OVERLAY |*/ CBEIF_SELECTEDIMAGE;
	cbi.iImage = cbi.iSelectedImage = kLocationIconUnknown;
	//cbi.iOverlay = ;

	CSortList<ENTNODE> entries(200, ENTNODE::Compare);
	vector<CStr> ignlist;
	struct stat sb;
	const char *fullpath = cbi.pszText;
	
	int statres = stat(fullpath, &sb);
	if( statres != -1 )
	{
		if( S_ISDIR(sb.st_mode) )
		{
			CStr uppath, folder;
			if( !SplitPath(fullpath, uppath, folder) || uppath.empty() )
			{
				uppath = fullpath;
				folder = ".";
			}
			
			BuildIgnoredList(ignlist, uppath);

			EntnodeData *data = Entries_SetVisited(uppath, entries, folder, sb, true, &ignlist);
			if( !data->IsUnknown() )
			{
				cbi.iImage = cbi.iSelectedImage = kLocationIcon;
			}
			if( data->IsIgnored() )
			{
				cbi.iImage = cbi.iSelectedImage = kLocationIconIgnored;
			}
			if( data->IsMissing() )
			{
				cbi.iImage = cbi.iSelectedImage = kLocationIconMissing;
			}
		}
	}
	else
	{
		cbi.iImage = cbi.iSelectedImage = kLocationIconErased;
	}
	
	return SetItem(&cbi);
}

BOOL CHistComboBoxEx::PreTranslateMessage(MSG* pMsg) 
{
	if( pMsg->message == WM_KEYDOWN )
	{
		int nVirtKey = (int)pMsg->wParam;
		if( VK_DELETE == nVirtKey )
		{
			if( GetDroppedState() )
			{
				int sel = GetCurSel();
				if( CB_ERR < sel && GetCount() > 1 )
				{
					CString strItem;
					GetLBText(sel, strItem);
					CString strMessage = "Do you want to remove that item from the list?\nLocation";
					strMessage += (0 == sel ? "(Current)" : "");
					strMessage += ": " + strItem;
					if( AfxMessageBox(strMessage, MB_YESNO | MB_ICONQUESTION) == IDYES )
					{
						if( gHistoryLocs.Remove(strItem) )
						{
							DeleteItem(sel);
							if( GetCount() )
							{
								int nNewSel = (0 == sel ? sel : (GetCount() ? 0 : -1));
								if( 0 != nNewSel || 0 == sel )
								{
									SetCurSel(nNewSel);
									
									//trigger the location change for all views
									CWincvsApp* app = (CWincvsApp *)AfxGetApp();
									CMainFrame* mainFrm = app->GetMainFrame();
									mainFrm->ChangeLocation();
								}
							}
						}
					}
				}
				else if( GetCount() == 1 )
				{
					AfxMessageBox("Can't remove the last item from the history.\n"
						"Add a new location first to remove the current one.", MB_OK | MB_ICONSTOP);
				}
			}
		}
	}
	
	return CComboBoxEx::PreTranslateMessage(pMsg);
}

void CHistComboBoxEx::OnDropdown() 
{
	TraverseHistory(*this);
	
	CClientDC ClientDC(this);
	int savedDc = ClientDC.SaveDC();
    ClientDC.SelectObject(GetFont());
	
	CString strLBText;
	int maxSize = 0;
	for( int nIndex = 0; nIndex < GetCount(); nIndex++ )
	{
		GetLBText( nIndex, strLBText );
		CSize size = ClientDC.GetTextExtent(strLBText);
		
		if( size.cx > maxSize )
		{
			maxSize = size.cx;
		}
	}
	ClientDC.RestoreDC(savedDc);

	maxSize += ::GetSystemMetrics(SM_CXVSCROLL)		//vertical scroll bar
		+ 4*::GetSystemMetrics(SM_CXEDGE)			//the border aroung the text and icon: Edge-Icon-Edge - Edge-Text-Edge
		+ HISTLOC_IMAGE_CX							//the icon width
		+ 2;										//the focus frame width
	
	CRect rect;
	GetWindowRect(rect);
	maxSize = min(ClientDC.GetDeviceCaps(HORZRES) - rect.TopLeft().x, maxSize);

	SetDroppedWidth(maxSize);
}
