// ClientListCtrl.cpp : implementation file
//

#include "stdafx.h"
#include "p4win.h"
#include "ClientListCtrl.h"
#include "ClientWizSheet.h"
#include "MainFrm.h"
#include "cmd_editspec.h"
#include "cmd_delete.h"
#include "cmd_describe.h"
#include "cmd_diff2.h"
#include "cmd_clients.h"
#include "cmd_get.h"
#include "cmd_changes.h"
#include "newclientdlg.h"
#include "TemplateNameDlg.h"
#include "Diff2ObjsDlg.h"
#include "ClientFilterDlg.h"
#include "MsgBox.h"
#include "ImageList.h"

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

#define IMG_INDEX(x) (x-IDB_PERFORCE)

static LPCTSTR sRegValue_ClientList = _T("Client List");

enum ClientSubItems
{
	CLIENT_NAME,
	CLIENT_OWNER,
	CLIENT_HOST,
	CLIENT_ACCESSDATE,
	CLIENT_ROOT,
	CLIENT_DESC,
	CLIENT_MAXCOL
};

/////////////////////////////////////////////////////////////////////////////
// CClientListCtrl

IMPLEMENT_DYNCREATE(CClientListCtrl, CP4ListCtrl)

BEGIN_MESSAGE_MAP(CClientListCtrl, CP4ListCtrl)
	ON_COMMAND(ID_CLIENT_DELETE, OnClientDelete)
	ON_UPDATE_COMMAND_UI(ID_CLIENT_DELETE, OnUpdateClientDelete)
	ON_UPDATE_COMMAND_UI(ID_VIEW_UPDATE_RIGHT, OnUpdateViewUpdate)
	ON_WM_CONTEXTMENU()
	ON_COMMAND(ID_CLIENT_TEMPLATE, OnClientTemplate)
	ON_UPDATE_COMMAND_UI(ID_CLIENT_TEMPLATE, OnUpdateClientTemplate)
	ON_COMMAND(ID_CLIENT_USEASLOCALTEMPLATE, OnUseAsLocalTemplate)
	ON_UPDATE_COMMAND_UI(ID_CLIENT_USEASLOCALTEMPLATE, OnUpdateUseAsLocalTemplate)
	ON_COMMAND(ID_CLIENT_CLEARLOCALTEMPLATE, OnClearLocalTemplate)
	ON_UPDATE_COMMAND_UI(ID_CLIENT_CLEARLOCALTEMPLATE, OnUpdateClearLocalTemplate)
	ON_UPDATE_COMMAND_UI(ID_CLIENT_DESCRIBE, OnUpdateClientDescribe)
	ON_COMMAND(ID_CLIENT_DESCRIBE, OnDescribe)
	ON_WM_LBUTTONDBLCLK()
	ON_COMMAND(ID_CLIENTSPEC_SWITCH, OnClientspecSwitch)
	ON_UPDATE_COMMAND_UI(ID_CLIENTSPEC_SWITCH, OnUpdateClientspecSwitch)
	ON_COMMAND(ID_SETDEFCLIENT, OnSetDefClient)
	ON_UPDATE_COMMAND_UI(ID_SETDEFCLIENT, OnUpdateSetDefClient)
	ON_COMMAND(ID_VIEW_UPDATE_RIGHT, OnViewUpdate)
	ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnclick)
	ON_NOTIFY_REFLECT(LVN_DELETEITEM, OnDeleteitem)
	ON_COMMAND(ID_CLIENTSPEC_NEW, OnClientspecNew)
	ON_UPDATE_COMMAND_UI(ID_CLIENTSPEC_NEW, OnUpdateClientspecNew)
	ON_WM_CREATE()
	ON_UPDATE_COMMAND_UI(ID_ADD_TOVIEW, OnUpdateAddToClientView)
	ON_COMMAND(ID_ADD_TOVIEW, OnAddToClientView)
	ON_COMMAND(ID_PERFORCE_OPTIONS, OnPerforceOptions)
	ON_UPDATE_COMMAND_UI(ID_FILE_DIFF2, OnUpdateDiff2Clients)
	ON_COMMAND(ID_FILE_DIFF2, OnDiff2Clients)
	ON_UPDATE_COMMAND_UI(ID_FILTERCLIENTS, OnUpdateFilterClients)
	ON_COMMAND(ID_FILTERCLIENTS, OnFilterClients)
	ON_UPDATE_COMMAND_UI(ID_CLEARCLIENTFILTER, OnUpdateClearClientFilter)
	ON_COMMAND(ID_CLEARCLIENTFILTER, OnClearClientFilter)
	ON_MESSAGE(WM_P4CLIENTS, OnP4ClientList )
	ON_MESSAGE(WM_P4EDITSPEC, OnP4ClientSpec )
	ON_MESSAGE(WM_P4ENDSPECEDIT, OnP4EndSpecEdit )
	ON_MESSAGE(WM_P4DELETE, OnP4Delete )
	ON_MESSAGE(WM_P4DESCRIBE, OnP4Describe )
    ON_MESSAGE(WM_P4ENDDESCRIBE, OnP4EndDescribe )
	ON_MESSAGE(WM_P4GET, OnP4Sync )
	ON_MESSAGE(WM_NEWUSER, NewUser )
	ON_MESSAGE(WM_P4DESCRIBEALT, OnP4UseAsLocalTemplate )
END_MESSAGE_MAP()

CClientListCtrl::CClientListCtrl()
{
	m_SortAscending=TRUE;
	m_LastSortCol=0;
	m_OldClient = GET_P4REGPTR()->GetP4Client();
	m_ClientNew.Empty();
	m_NewClicked = m_NewClient = FALSE;
	m_viewType = P4CLIENT_SPEC;
	m_OldDefClient = m_OldCurClient = _T("@");
	m_PrevNbrCli = -1;

	m_CF_DEPOT = RegisterClipboardFormat(LoadStringResource(IDS_DRAGFROMDEPOT));
	m_CF_CLIENT= RegisterClipboardFormat(LoadStringResource(IDS_DRAGFROMCLIENT));
	m_caption =  m_captionplain = LoadStringResource(IDS_PERFORCE_CLIENTS);
}

CClientListCtrl::~CClientListCtrl()
{
}




/////////////////////////////////////////////////////////////////////////////
// CClientListCtrl diagnostics

#ifdef _DEBUG
void CClientListCtrl::AssertValid() const
{
	CP4ListCtrl::AssertValid();
}

void CClientListCtrl::Dump(CDumpContext& dc) const
{
	CP4ListCtrl::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CClientListCtrl message handlers


/*
	_________________________________________________________________

	let user edit the client spec s/he clicked on.
	_________________________________________________________________
*/

void CClientListCtrl::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	int index = GetHitItem ( point );
	if(index > -1)
	{
		SetItemState( index, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED );
		OnDescribe( );
	}
	else
		CP4ListCtrl::OnLButtonDblClk(nFlags, point);
}


/*
	_________________________________________________________________
*/

void CClientListCtrl::OnDeleteitem(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	
	delete (CP4Client *) GetItemData(pNMListView->iItem);
			
	*pResult = 0;
}


/*
	_________________________________________________________________

	define a new client, which means
		set the current client to this new one (true? maybe i should ask the user)
		sometimes change the registry
		edit this new client's spec

	this used to be done in the options dialogue's connection
	parameters
	_________________________________________________________________
*/

void CClientListCtrl::OnUpdateClientspecNew(CCmdUI* pCmdUI) 
{
	pCmdUI->SetText ( LoadStringResource( IDS_NEW ) );
	pCmdUI->Enable( !SERVER_BUSY() && !m_EditInProgress && !MainFrame()->IsModlessUp() );
}


/*
	_________________________________________________________________
*/

void CClientListCtrl::ClientspecNew()
{
	OnClientspecNew( ) ;
}


/*
	_________________________________________________________________
*/

void CClientListCtrl::OnClientspecNew() 
{
	DoClientspecNew(FALSE, NULL);
}

void CClientListCtrl::DoClientspecNew(BOOL bUseDefTemplate, LPCTSTR defName ) 
{
	MainFrame()->ViewClients();
	m_ClientNew.Empty();
	m_OldClient= GET_P4REGPTR()->GetP4Client();

	//		let user type in the new name. if it's blank the user bailed.
	//
	CNewClientDlg newdlg;
	newdlg.SetNew( NEWCLIENT );
	if (FindInListAll(m_Active) != -1)
		newdlg.m_Active = m_Active;
	if (defName)
		newdlg.m_Name = defName;
	if( newdlg.DoModal( ) == IDCANCEL )
		return;

	if (newdlg.m_RunWizard)
	{
		CString txt;
		CString port = GET_P4REGPTR()->GetP4Port();
		CString clientname = newdlg.GetName();
		txt.FormatMessage( IDS_NOCLIENT_s_s_s, clientname, port, GET_P4REGPTR()->GetP4User() );
		int i;
		if ((i = txt.Find(_T('\n'))) != -1)
		{
			txt = txt.Mid(i);
			txt.TrimLeft();
		}
		CClientWizSheet dlg(LoadStringResource(IDS_CLIENTWORKSPACEWIZARD), this, 1);
		dlg.SetMsg(txt);
		dlg.SetName(clientname);
		dlg.SetPort(port);
		dlg.AllowBrowse(FALSE);
		int rc;
		while(1)
		{
			if( (rc = dlg.DoModal()) == IDCANCEL )	// user bailed
			{
				break;
			}
			if ( rc == IDIGNORE )	// user chose to browse existing clients
			{
				ViewUpdate();
				break;
			}
			else	// user clicked the Finish button on the create client page
			{
				CString newClient = dlg.GetName();
				CString newRoot   = dlg.GetRoot();
				BOOL bEdit        = dlg.IsEdit();
				BOOL bTmpl        = dlg.IsTmpl();
				CString tmplate   = dlg.GetTmpl();
				while (m_UpdateState == LIST_UPDATING)
					Sleep(100);
				if (FindInListAll(newClient) != -1)
				{
					CString msg;
					msg.FormatMessage(IDS_CANT_RECREATE_EXISTING_CLIENT_s, newClient);
					AfxMessageBox( msg, MB_ICONSTOP );
				}
				else if (!newClient.IsEmpty() && !newRoot.IsEmpty())
				{
					if (AutoCreateClientSpec(newClient, newRoot, bEdit, bTmpl, tmplate))
						break;;
				}
			}
		}
		return;
	}

	CString saveActive = m_Active;
	m_Active = newdlg.GetName( ) ;
	if ( m_Active.IsEmpty( ) )
		return;

	if ( SetP4Client( TRUE ) ) 
	{
		// rather than use the current directory as the default client root
		// switch to the drive's root and use that; switch back at the end.
		TCHAR	buf[MAX_PATH+1];
		TCHAR	root[4];
		if (GetCurrentDirectory(MAX_PATH, buf))
		{
			_tcsncpy(root, buf, 3);
			root[3] = '\0';
			SetCurrentDirectory(root);
		}
		else
		{
			buf[0] = _T('\0');
		}

		// Get the edit of the new spec underway
		m_NewClient  = (saveActive != m_Active);
		m_NewClicked = TRUE;
		OnEditSpec( m_Active, bUseDefTemplate );
		m_ClientNew = m_Active;

		// restore previous working directory
		if (buf[0])
			SetCurrentDirectory(buf);
	}
}


/*
	_________________________________________________________________
*/

void CClientListCtrl::OnUpdateClientDelete(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( OnUpdateShowMenuItem( pCmdUI, IDS_DELETE_s )
			&& GetSelectedItemText() == GET_P4REGPTR()->GetP4Client() 
			&& !MainFrame()->IsModlessUp() );
}

BOOL CClientListCtrl::OKToDelete( ) 
{
	if ( GetSelectedItemText() == GET_P4REGPTR()->GetP4Client() )
		return TRUE;
	else
	{
		AfxMessageBox(IDS_NO_PERMISSION_TO_DELETE_OTHER_CLIENTS, MB_ICONINFORMATION);
		return FALSE;
	}
}


/*
	_________________________________________________________________
*/

void CClientListCtrl::OnClientDelete() 
{
	OnDelete( P4CLIENT_DEL );
}


/*
	_________________________________________________________________
*/

void CClientListCtrl::EditTheSpec(CString *name) 
{
	if (*name == GET_P4REGPTR()->GetP4Client())
		OnClientEditmy();
}

void CClientListCtrl::OnClientEditmy() 
{
	m_Active = GET_P4REGPTR()->GetP4Client();
	m_OldClient= m_Active;
	m_NewClicked = m_NewClient = FALSE;

	int index = FindInList( m_Active ) ;
	if ( index  > -1 )
	{
		SetItemState(index, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
		EnsureVisible(index, FALSE);
	}

	OnEditSpec( m_Active );
}


void CClientListCtrl::OnUpdateClientTemplate(CCmdUI* pCmdUI) 
{
	m_Active = GetSelectedItemText();
	CString sCurrentClient = GET_P4REGPTR()->GetP4Client();

    CString prompt;
    prompt.FormatMessage(IDS_CREATE_UPDATE_CLIENT_USING_s_AS_TEMPLATE,
        m_Active.IsEmpty( ) ? TruncateString(sCurrentClient, 50) : TruncateString(m_Active, 50));
	pCmdUI->SetText ( prompt );

	pCmdUI->Enable(	!SERVER_BUSY() && !m_EditInProgress
					&& !m_Active.IsEmpty() 
					&& !MainFrame()->IsModlessUp() );
}


/*
	_________________________________________________________________
*/

void CClientListCtrl::OnClientTemplate() 
{
	m_Template = GetSelectedItemText(); 
	m_OldClient= GET_P4REGPTR()->GetP4Client();
	m_Active.Empty();

	// rather than use the current directory as the default client root
	// switch to the drive's root and use that; switch back at the end.
	TCHAR	buf[MAX_PATH+1];
	TCHAR	root[4];
	if (GetCurrentDirectory(MAX_PATH, buf))
	{
		_tcsncpy(root, buf, 3);
		root[3] = '\0';
		SetCurrentDirectory(root);
	}
	else
	{
		buf[0] = _T('\0');
	}

	OnEditTemplate( m_Template );

	// restore previous working directory
	if (buf[0])
		SetCurrentDirectory(buf);
}

void CClientListCtrl::OnUpdateClearLocalTemplate(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(	!CString(GET_P4REGPTR()->GetLocalCliTemplate()).IsEmpty() );
}

void CClientListCtrl::OnClearLocalTemplate()
{
	GET_P4REGPTR()->SetLocalCliTemplate(_T(""));
}

void CClientListCtrl::OnUpdateUseAsLocalTemplate(CCmdUI* pCmdUI) 
{
	m_Active = GetSelectedItemText();
	CString sCurrentClient = GET_P4REGPTR()->GetP4Client();

    CString prompt;
    prompt.FormatMessage(IDS_CLIENT_USEASLOCALTEMPLATE,
        m_Active.IsEmpty( ) ? TruncateString(sCurrentClient, 50) : TruncateString(m_Active, 50));
	pCmdUI->SetText ( prompt );

	pCmdUI->Enable(	!SERVER_BUSY() && !m_EditInProgress
					&& !m_Active.IsEmpty() 
					&& !MainFrame()->IsModlessUp()
					&& GET_P4REGPTR()->LocalCliTemplateSw() );
}

void CClientListCtrl::OnUseAsLocalTemplate()
{
	m_Active = GetSelectedItemText();

	if ( m_Active.IsEmpty( ) )
		return;

	CCmd_Describe *pCmd = new CCmd_Describe;
	pCmd->Init( m_hWnd, RUN_ASYNC );
	pCmd->SetAlternateReplyMsg( WM_P4DESCRIBEALT );
	if( pCmd->Run( m_viewType, m_Describing = m_Active ) )
	{
		MainFrame()->UpdateStatus( LoadStringResource(IDS_FETCHING_SPEC) );	
		return;
	}
	else
	{
		delete pCmd;
		return;
	}
}

LRESULT CClientListCtrl::OnP4UseAsLocalTemplate(WPARAM wParam, LPARAM lParam)
{
	CCmd_Describe *pCmd = (CCmd_Describe *) wParam;
	CString ref = pCmd->GetReference();
	CString tmplate = pCmd->GetDescription();
	int i;
	if ((i = tmplate.Find(_T("\n\nClient:\t"))) != -1)
	{
		tmplate = tmplate.Mid(i);
		tmplate.Replace(ref, LOCALDEFTEMPLATE);
		if (GET_P4REGPTR()->SetLocalCliTemplate(tmplate))
		{
			CString msg;
			msg.FormatMessage(IDS_LOCALDEFTEMPLATESET_s, ref);
			AddToStatus(msg, SV_COMPLETION);
		}
	}
	delete pCmd;
	MainFrame()->ClearStatus();
	return 0;
}


void CClientListCtrl::OnUpdateClientDescribe(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable( OnUpdateShowMenuItem( pCmdUI, IDS_DESCRIBEIT_s ) 
					&& !MainFrame()->IsModlessUp() );	
}


/*
	_________________________________________________________________

	whether to show or grey out the F5 menu item on the context menu
	_________________________________________________________________
*/

void CClientListCtrl::OnUpdateViewUpdate(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(!SERVER_BUSY() && !MainFrame()->IsModlessUp());
}


/*
	_________________________________________________________________

	user hit F5 or equiv
	_________________________________________________________________
*/

void CClientListCtrl::OnViewUpdate() 
{
	m_Active = GetSelectedItemText();
	SetCaption();
	CCmd_Clients *pCmd= new CCmd_Clients;
	pCmd->Init( m_hWnd, RUN_ASYNC);
	if( pCmd->Run( ) )
	{
		MainFrame()->UpdateStatus(LoadStringResource(IDS_REQUESTING_CLIENT_LISTING));
		MainFrame()->SetClientUpdateTime(GetTickCount());
		Clear();
		CP4ListCtrl::OnViewUpdate();
	}
	else
		delete pCmd;
}

CString CClientListCtrl::SetCaption()
{
	int i = GET_P4REGPTR()->GetClientFilteredFlags();
	if (i)
    {
        CString filter;
		CString txt;

		if (i & 0x10)
			txt = LoadStringResource(IDS_CURRENT_USER);
		else if (i & 0x01)
			txt = GET_P4REGPTR()->GetClientFilterOwner();
		if (i & 0x22)
		{
			if (!txt.IsEmpty())
				txt += _T(", ");
			txt += i & 0x20 ? GET_P4REGPTR()->GetHostname() : GET_P4REGPTR()->GetClientFilterHost();
		}
		if (i & 0x04)
		{
			if (!txt.IsEmpty())
				txt += _T(", ");
			txt += CString(_T("\"")) + GET_P4REGPTR()->GetClientFilterDesc() + _T("\"");
		}
		filter.FormatMessage(IDS_FILTERED, txt);
		m_caption = LoadStringResource(IDS_PERFORCE_CLIENTS) + filter;
    }
	else
		m_caption = LoadStringResource(IDS_PERFORCE_CLIENTS);

	CP4PaneContent::GetView()->SetCaption();

	return m_caption;
}


/*
	_________________________________________________________________
*/

LRESULT CClientListCtrl::NewUser(WPARAM wParam, LPARAM lParam)
{
	if (GET_P4REGPTR()->GetClientFilteredFlags() & 0x10)
		Clear();
	return 0;
}

void CClientListCtrl::Clear() 
{
    SetRedraw(FALSE);
	DeleteAllItems();
    SetRedraw(TRUE);

	CP4ListCtrl::Clear();
}


/*
	_________________________________________________________________

	called when user right clicks on a clientspec. create one of two
	menus, depending on where the user clicked.

	if user has highlighted a client, allow them to do the usual
	things to a client view. (describe it, switch to it, use it as 
	a template to create a new client)
	(edit and delete -- i need to know the owner. but delete is already there!)
	
	if the user clicked on a random part of the pane, show
	only the general choices, like refresh, create a new client
	-- and maybe edit the current client?
	_________________________________________________________________
*/

void CClientListCtrl::OnContextMenu(CWnd* pWnd, CPoint point) 
{
	//		make sure window is active
	//
	GetParentFrame()->ActivateFrame();

	///////////////////////////////
	// See ContextMenuRules.txt for order of menu commands!

	//		create an empty context menu
	//
	CP4Menu popMenu;
	popMenu.CreatePopupMenu();

 	int	index;
    SetIndexAndPoint( index, point );

	// Can always create a new client
	popMenu.AppendMenu( stringsON, ID_CLIENTSPEC_NEW );

	// Only offer edit if no other client is selected
	if ( index == -1 || GetSelectedItemText() == GET_P4REGPTR()->GetP4Client() )
		popMenu.AppendMenu( stringsON, ID_CLIENT_EDITMY );

	if( index != -1 )
	{
		// Make sure item gets selected
		SetItemState( index, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED );
			
		popMenu.AppendMenu( stringsON, ID_CLIENT_DESCRIBE ); //or client edit if user is the owner
		popMenu.AppendMenu( stringsON, ID_CLIENT_DELETE );

		popMenu.AppendMenu( MF_SEPARATOR );

		// Can only switch to a client if its not my current client
		if ( GetSelectedItemText() != GET_P4REGPTR()->GetP4Client() )
			popMenu.AppendMenu( stringsON, ID_CLIENTSPEC_SWITCH );
		else	// can only set as default if it is my current client
			popMenu.AppendMenu( stringsON, ID_SETDEFCLIENT );

		popMenu.AppendMenu( stringsON, ID_CLIENT_TEMPLATE );
		if (GET_P4REGPTR()->LocalCliTemplateSw())
		{
			popMenu.AppendMenu( MF_SEPARATOR );
			popMenu.AppendMenu( stringsON, ID_CLIENT_USEASLOCALTEMPLATE, LoadStringResource(IDS_CLIENT_USEASLOCALTEMPLATE) );
			popMenu.AppendMenu( stringsON, ID_CLIENT_CLEARLOCALTEMPLATE, LoadStringResource(IDS_CLIENT_CLEARLOCALTEMPLATE) );
		}
	}
	popMenu.AppendMenu( MF_SEPARATOR );
	popMenu.AppendMenu( stringsON, ID_FILTERCLIENTS, LoadStringResource(IDS_FILTERCLIENTS) );
	popMenu.AppendMenu( stringsON, ID_CLEARCLIENTFILTER, LoadStringResource(IDS_CLEARCLIENTFILTER) );
	popMenu.AppendMenu( MF_SEPARATOR );
	CString txt = GetSelectedItemText();
	if (txt.IsEmpty())
		txt = GET_P4REGPTR()->GetP4Client( );
	txt = LoadStringResource(IDS_CHGS_BY_CLIENT) + txt;
	txt = TruncateString(txt, 50);
	popMenu.AppendMenu( stringsON, ID_CHGS_BY_CLIENT, txt );
	popMenu.AppendMenu( stringsON, ID_VIEW_UPDATE, LoadStringResource(IDS_REFRESH) );

	MainFrame()->AddToolsToContextMenu(&popMenu);

	//		put up the menu 
	//
	popMenu.TrackPopupMenu( TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, AfxGetMainWnd( ) );
}


/////////////////////////////////////////////////////////////////////////////
// CClientListCtrl message handlers

/*
	_________________________________________________________________
*/

void CClientListCtrl::OnUpdateClientspecSwitch(CCmdUI* pCmdUI) 
{
	CString selClient = GetSelectedItemText();
    CString prompt;
    prompt.FormatMessage(IDS_SWITCH_TO_s, TruncateString(selClient, 50));
	pCmdUI->SetText ( prompt );
	pCmdUI->Enable( !SERVER_BUSY() 
					&& !selClient.IsEmpty()
					&& selClient != GET_P4REGPTR()->GetP4Client( )
					&& !MainFrame()->IsModlessUp());
}


/*
	_________________________________________________________________
*/

void CClientListCtrl::OnClientspecSwitch() 
{
	ClientSpecSwitch(GetSelectedItemText());
}

BOOL CClientListCtrl::ClientSpecSwitch(CString switchTo, BOOL bAlways /*=FALSE*/, BOOL portWasChanged /*= FALSE*/) 
{
	CCmd_Describe *pCmd = new CCmd_Describe;
	pCmd->Init( NULL, RUN_SYNC );
	BOOL cmdStarted= pCmd->Run( P4CLIENT_SPEC, switchTo );
	if(cmdStarted && !pCmd->GetError())
	{
		CString options= TheApp()->GetClientSpecField( _T("Options"), pCmd->GetDescription() );
		if (( options.Find(_T("unlocked")) == -1 ) && ( options.Find(_T("locked")) != -1 ))
		{
			CString lockedby= TheApp()->GetClientSpecField( _T("Owner"), pCmd->GetDescription() );
			if ( lockedby.Compare( GET_P4REGPTR()->GetP4User() ) != 0 )
			{
				CString errmsg;
                errmsg.FormatMessage(IDS_CLIENT_s_IS_LOCKED_BY_USER_s_AND_CANT_BE_USED_BY_s,
                    switchTo, lockedby, GET_P4REGPTR()->GetP4User());
				AddToStatus( errmsg, SV_WARNING );  
				AfxMessageBox( errmsg, MB_ICONEXCLAMATION );
				delete pCmd;
				return FALSE;
			}
		}
	}
	delete pCmd;

	m_Active = switchTo;

	if ( SetP4Client( bAlways ) )
		MainFrame()->OnPerforceOptions( FALSE, portWasChanged ) ;
	return TRUE;
}


/*
	_________________________________________________________________
*/

void CClientListCtrl::OnUpdateSetDefClient(CCmdUI* pCmdUI) 
{
	CString selClient = GetSelectedItemText();
    CString prompt;
    prompt.FormatMessage(IDS_SETDEFCLIENT_s, TruncateString(selClient, 50));
	pCmdUI->SetText ( prompt );
	pCmdUI->Enable( !SERVER_BUSY() 
					&& !selClient.IsEmpty()
					&& selClient == GET_P4REGPTR()->GetP4Client( FALSE )
					&& selClient != GET_P4REGPTR()->GetP4Client( TRUE )
					&& !MainFrame()->IsModlessUp() );
}


/*
	_________________________________________________________________
*/

void CClientListCtrl::OnSetDefClient() 
{
	if (m_Active != GetSelectedItemText())
	{
		ASSERT(0);
		return;
	}

	if (GET_P4REGPTR()->GetExpandFlag() == 1)
		GET_P4REGPTR()->AddMRUPcuPath(MainFrame()->GetCurrentItemPath());

	if( !GET_P4REGPTR()->SetP4Client( m_Active, TRUE, TRUE, TRUE ) )
	{
		AfxMessageBox(IDS_UNABLE_TO_WRITE_P4CLIENT_TO_THE_REGISTRY, MB_ICONEXCLAMATION);
		m_Active = GetSelectedItemText();
	}
	else
    {
        CString msg;
        msg.FormatMessage(IDS_DEFAULT_CLIENT_SET_TO_s, m_Active);
		AddToStatus( msg );
    }
}


/*
	_________________________________________________________________
*/

//fanny: damn! p4clients doesn't give you the owner! how can i put up an
//edit menu item without checking first?

void CClientListCtrl::InsertClient(CP4Client *client, int index, 
								   CString *curclient, CString *defclient, CString *user)
{
	ASSERT(client != NULL);
	m_iImage = CP4ViewImageList::VI_CLIENT;

	LV_ITEM lvItem;
	int iActualItem = -1;
	CString txt;
	BOOL bFilteredOut = MainFrame()->IsClientFilteredOut(client, user, curclient, defclient);

	for(int subItem=0; subItem < CLIENT_MAXCOL; subItem++)
	{
		lvItem.mask=LVIF_TEXT | 
					((subItem==0) ? LVIF_IMAGE : 0) |
					((subItem==0) ? LVIF_PARAM : 0);

		lvItem.iItem= (subItem==0) ? index : iActualItem;
        ASSERT(lvItem.iItem != -1 || bFilteredOut);

		lvItem.iSubItem= subItem;

		switch(subItem)
		{
		case CLIENT_NAME: 
			{
			lvItem.pszText = const_cast<LPTSTR>(client->GetClientName());
			bool isCurrent = curclient->Compare(lvItem.pszText) == 0;
			bool isDefault = defclient->Compare(lvItem.pszText) == 0;
			lvItem.iImage = CP4ViewImageList::GetClientIndex(isCurrent, isDefault);
			if(isDefault)
				m_OldDefClient = lvItem.pszText;
			if(isCurrent)
				m_OldCurClient = lvItem.pszText;
	        lvItem.lParam=(LPARAM) client;
			}
			break;
		case CLIENT_OWNER: 
			lvItem.pszText = const_cast<LPTSTR>( (LPCTSTR) client->GetOwner()); break;
		case CLIENT_HOST: 
			lvItem.pszText = const_cast<LPTSTR>( (LPCTSTR) client->GetHost()); break;
		case CLIENT_ACCESSDATE: 
			lvItem.pszText = const_cast<LPTSTR>( (LPCTSTR) client->GetDate()); break;
		case CLIENT_ROOT: 
			lvItem.pszText = const_cast<LPTSTR>( (LPCTSTR) client->GetRoot()); break;
		case CLIENT_DESC: 
			txt= PadCRs(client->GetDescription());
			lvItem.pszText = const_cast<LPTSTR>( (LPCTSTR) txt); break;
		default:
			ASSERT( 0 ); lvItem.pszText = _T("@"); break;
		}

		m_ListAll.column[subItem].SetAtGrow(index, lvItem.pszText);
		if (bFilteredOut)
			continue;
			
		if (subItem==0)
		{
			static	BOOL	bErrDispalyed=FALSE;
			iActualItem=InsertItem(&lvItem);
			if (iActualItem==-1 && !bErrDispalyed)
			{
				AfxMessageBox(_T("Client item insert failure"), MB_ICONSTOP);
				bErrDispalyed = TRUE;
			}
		}
		else
			SetItem(&lvItem);
	}
	if (bFilteredOut)
		delete client;
}

/*
	_________________________________________________________________
*/

void CClientListCtrl::UpdateClient(CP4Client *client, int index)
{
	// After a spec edit, update the appropriate list item
	// First, switch the client data
	CP4Client *oldClient= (CP4Client *) GetItemData(index);
	delete oldClient;
	SetItemData(index, (LPARAM) client);

	// Then update the text
	SetItemText(index, CLIENT_NAME,    const_cast<LPTSTR>( (LPCTSTR) client->GetClientName()));
	SetItemText(index, CLIENT_OWNER,   const_cast<LPTSTR>( (LPCTSTR) client->GetOwner()));
	SetItemText(index, CLIENT_HOST,    const_cast<LPTSTR>( (LPCTSTR) client->GetHost()));
	SetItemText(index, CLIENT_ACCESSDATE, const_cast<LPTSTR>( (LPCTSTR) client->GetDate()));
	SetItemText(index, CLIENT_ROOT,    const_cast<LPTSTR>( (LPCTSTR) client->GetRoot()));
	CString	txt= PadCRs(client->GetDescription());
	SetItemText(index, CLIENT_DESC,    const_cast<LPTSTR>((LPCTSTR)txt));
}

void CClientListCtrl::UpdateClientAll(CP4Client *client, int index)
{
	m_ListAll.column[CLIENT_NAME].SetAt(index, const_cast<LPTSTR>((LPCTSTR)client->GetClientName()));
	m_ListAll.column[CLIENT_OWNER].SetAt(index, const_cast<LPTSTR>((LPCTSTR)client->GetOwner()));
	m_ListAll.column[CLIENT_HOST].SetAt(index, const_cast<LPTSTR>((LPCTSTR)client->GetHost()));
	m_ListAll.column[CLIENT_ACCESSDATE].SetAt(index, const_cast<LPTSTR>((LPCTSTR)client->GetDate()));
	m_ListAll.column[CLIENT_ROOT].SetAt(index, const_cast<LPTSTR>((LPCTSTR)client->GetRoot()));
	CString	txt= PadCRs(client->GetDescription());
	m_ListAll.column[CLIENT_DESC].SetAt(index, const_cast<LPTSTR>((LPCTSTR)txt));
}


/*
	_________________________________________________________________

	Receives ak for client spec edit
	_________________________________________________________________
*/

LRESULT CClientListCtrl::OnP4ClientSpec(WPARAM wParam, LPARAM lParam)
{
	m_PrevNbrCli = m_UpdateState == LIST_CLEAR ? -1 : GetItemCount();
	m_saveclientnew = m_ClientNew;	// save name of freshly created client
	CCmd_EditSpec *pCmd = (CCmd_EditSpec *) wParam;

	if (pCmd->GetUseLocalDefTmplate())
	{
        CString specIn(pCmd->GetSpecIn());
		int i;
		if ((i = specIn.Find(_T("\n\nClient:\t"))) != -1)
		{
			CString tmplate = GET_P4REGPTR()->GetLocalCliTemplate();
			tmplate.Replace(LOCALDEFTEMPLATE, pCmd->GetItemName());
			pCmd->SetSpecIn(specIn.Left(i) + tmplate);
		}
	}

	m_ClientNew.Empty();

	// let the dialogbox know whether this is a new client or an edit of an existing one
	int index= FindInListAll(m_Active.IsEmpty() ? pCmd->GetItemName() : m_Active);
	if ((index == -1) || !GetItemCount())	// if name not in client list
		 index = m_NewClient ? -1 : -2;		//	it's new if and only if they clicked 'New'
	pCmd->SetIsNewClient(m_isNew = (index == -1));
	pCmd->SetIsRequestingNew(m_NewClicked);
	pCmd->SetOldClient(m_OldClient);
	pCmd->SetCaller(DYNAMIC_DOWNCAST(CView, GetParent()));
	m_NewClicked = m_NewClient = FALSE;	// clear these now, cuz no longer needed
    if (m_AddToViewList.GetCount() > 0)	// We have files to add to the Reviews list
	{
        CString specIn(pCmd->GetSpecIn());
		int i;
		if ((i = specIn.Find(_T("\n\nView:\n"))) == -1)
		{
			i = specIn.GetLength();
			specIn += _T("\n\nView:\n");
		}
		else
			specIn += _T("\t@\t@\n");	//	A view that is @[TAB]@ means
											//	put a blank line in the list here.
		POSITION pos;
		CString filename;
		CString localname;
		BOOL b = GET_P4REGPTR()->UseDepotInClientView();
		for (pos = m_AddToViewList.GetHeadPosition(); pos != NULL; )
		{
			filename = m_AddToViewList.GetNext(pos);
			if ((i = filename.Find(_T("<contains no files or folders>"))) != -1)
				filename = filename.Left(i-1) + _T("/...");
			localname = CString ( _T("//") ) + GET_P4REGPTR()->GetP4Client();
			if (!b && ((i = filename.Find(_T('/'), 2)) > 2))
				localname += filename.Right(filename.GetLength() - i);
			else
				localname += filename.Right(filename.GetLength() - 1);
			if (filename.Find(_T(' ')))
				filename = _T('\"') + filename + _T('\"');
			if (localname.Find(_T(' ')))
				localname = _T('\"') + localname + _T('\"');
			specIn += _T('\t') + filename + _T('\t') + localname + _T('\n');
		}
		m_AddToViewList.RemoveAll();		// this info is no longer needed
        pCmd->SetSpecIn(specIn);
	}
	// show the dialog box
	if(!pCmd->GetError() && !m_EditInProgress && pCmd->DoSpecDlg(this))
	{
		m_EditInProgress = TRUE;
		m_EditInProgressWnd = pCmd->GetSpecSheet();
	}
	else
	{
		if (GET_P4REGPTR()->GetExpandFlag() == 1)
			GET_P4REGPTR()->AddMRUPcuPath(MainFrame()->GetCurrentItemPath());
		m_Active = m_OldClient;
		GET_P4REGPTR()->SetP4Client( m_Active, TRUE, FALSE, FALSE);
		MainFrame()->UpdateCaption( ) ;	
        delete m_pNewSpec;

		if (pCmd->HaveServerLock())
			pCmd->ReleaseServerLock();
		delete pCmd;
	}

	MainFrame()->ClearStatus();
	return 0;
}

LRESULT CClientListCtrl::OnP4EndSpecEdit( WPARAM wParam, LPARAM lParam )
{
	CCmd_EditSpec *pCmd= (CCmd_EditSpec *) wParam;
	BOOL chainedCommand = FALSE;
	BOOL need2Refresh = FALSE;

	if (lParam != IDCANCEL && lParam != IDABORT)
	{
		// Get the Sync flag
		int syncAfter = SYNC_DONT;
		BOOL bHasChgs = TRUE;
		if (m_PrevNbrCli < 1)
		{
			int key= pCmd->HaveServerLock() ? pCmd->GetServerKey() : 0;
			CCmd_Changes *pCmd2= new CCmd_Changes;
			pCmd2->Init( m_hWnd, RUN_SYNC, key ? HOLD_LOCK : LOSE_LOCK, key);
			if( pCmd2->Run(SUBMITTED_CHANGES, FALSE, NULL, 1) )
			{
				if (!pCmd2->GetChanges()->GetCount())
					bHasChgs = FALSE;
			}
			delete pCmd2;
		}
		if (m_isNew && !GET_P4REGPTR()->DontShowYouHaveCr8NewClient() && bHasChgs)
		{
			BOOL b;
			switch(MsgBox(IDS_YOU_HAVE_CREATED_NEW_CLIENT,
						MB_ICONEXCLAMATION | MB_DEFBUTTON1, 0, this, &b))
			{
			case IDC_BUTTON1:
				syncAfter = SYNC_HEAD;
				break;
			case IDC_BUTTON2:
				syncAfter = SYNC_DONT;
				break;
			}
			GET_P4REGPTR()->SetDontShowYouHaveCr8NewClient(b);
		}
		else if ((pCmd->IsSyncAfter() || pCmd->IsAutoUpdateSpec())
			  && !GET_P4REGPTR()->DontShowYouHaveChgClientView() && bHasChgs)
		{
			BOOL b;
			switch(MsgBox(pCmd->IsAutoUpdateSpec() ? IDS_DOYOUWANTOTSYNCYOURNEWCLIENT 
												   : IDS_YOU_HAVE_CHANGED_CLIENTS_VIEW,
												   MB_ICONQUESTION | MB_DEFBUTTON1, 0, this, 
												   pCmd->IsAutoUpdateSpec() ? NULL : &b))
			{
			case IDC_BUTTON1:
				syncAfter = SYNC_HEAD;
				break;
			case IDC_BUTTON2:
				syncAfter = pCmd->IsAutoUpdateSpec() ? SYNC_DONT : SYNC_HAVE;
				break;
			case IDC_BUTTON3:
				syncAfter = SYNC_DONT;
				break;
			}
			if (!pCmd->IsAutoUpdateSpec())
				GET_P4REGPTR()->SetDontShowYouHaveChgClientView(b);
		}

		BOOL bDeld = FALSE;
		if (m_UpdateState == LIST_UPDATED)
		{
			// we have to set 'index' again in case client's name got changed
			int index= FindInList(m_pNewSpec->GetClientName());
			int ixAll= FindInListAll(m_pNewSpec->GetClientName());
			if (ixAll == -1)	// not in either list
			{
				ASSERT(index == -1);
				CString curclient = GET_P4REGPTR()->GetP4Client();
				CString defclient = GET_P4REGPTR()->GetP4Client(TRUE);
				InsertClient(m_pNewSpec, GetItemCount(), &curclient, &defclient);
			}
			else if (index > -1)	// in both lists
			{
				ASSERT(ixAll > -1);
				if (MainFrame()->IsClientFilteredOut(m_pNewSpec))	// should it no longer be shown?
				{
					need2Refresh = TRUE;
					delete m_pNewSpec;
				}
				else
				{
					UpdateClient(m_pNewSpec, index);
					UpdateClientAll(m_pNewSpec, ixAll);
				}
			}
			else	// not in visible list; is in list of all
			{
				if (MainFrame()->IsClientFilteredOut(m_pNewSpec))	// should it now be shown?
					need2Refresh = TRUE;
				else
					UpdateClientAll(m_pNewSpec, ixAll);
				if (pCmd->IsAutoUpdateSpec())
					m_OldClient = m_pNewSpec->GetClientName();
				delete m_pNewSpec;
				bDeld = TRUE;
			}
			ReSort();
			if (pCmd->IsAutoUpdateSpec() || pCmd->IsSpecForceSwitch())
			{
				if (bDeld)
					need2Refresh = TRUE;
				else
				{
					int i = FindInList(m_OldClient = m_pNewSpec->GetClientName());
					if (i < 0)	
						i = 0;
					SetItemState(i, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
					EnsureVisible(i, FALSE);
				}
				m_Active = _T("@");			// force switch to new client
			}
		}
		else
			if ( m_pNewSpec ) delete m_pNewSpec;

		int key= pCmd->HaveServerLock() ? pCmd->GetServerKey() : 0;
		if( m_Active == m_saveclientnew )	// active-client == saved new client name
			m_OldClient = m_saveclientnew;	//   means they decided to edit the current client
		if( m_Active != m_OldClient )		// If current client is not now the client when this
		{									//   all started, switch to the new current client
			if (GET_P4REGPTR()->GetExpandFlag() == 1)
				GET_P4REGPTR()->AddMRUPcuPath(MainFrame()->GetCurrentItemPath());
			m_Active = m_OldClient;
			GET_P4REGPTR()->SetP4Client( m_Active, TRUE, FALSE, FALSE);
			MainFrame()->UpdateCaption( );
			if (syncAfter)
				chainedCommand = SyncAfter(key, syncAfter);
        }
		else if( syncAfter || GET_P4REGPTR()->GetClearAndReload()
				|| AfxMessageBox(IDS_YOU_HAVE_UPDATED_YOUR_CLIENT_WORKSPACE__CLEAR_AND_RELOAD, 
								MB_YESNO |MB_ICONQUESTION ) == IDYES )
		{
			if (syncAfter)
				chainedCommand = SyncAfter(key, syncAfter);
			else
			{
				int key= pCmd->HaveServerLock() ? pCmd->GetServerKey() : 0;
				MainFrame()->UpdateDepotandChangeViews(REDRILL, key);
				chainedCommand=TRUE;
			}
		}
		if (GET_SERVERLEVEL() >= 22)
			TheApp()->Set_m_ClientSubOpts(TheApp()->GetClientSpecField( _T("SubmitOptions"), pCmd->GetSpecOut()));
    }
	else
	{
		if ( m_pNewSpec )
			delete m_pNewSpec;
		if (lParam == IDCANCEL && pCmd->GetIsRequestingNew())
		{
			m_Active = pCmd->GetOldClient();	// switch back to the previous client
			GET_P4REGPTR()->SetP4Client( m_Active, TRUE, FALSE, FALSE);
			MainFrame()->UpdateCaption( );
		}
	}

	if (lParam != IDABORT)
	{
		MainFrame()->ClearStatus();
		if (!chainedCommand && pCmd->HaveServerLock())
			pCmd->ReleaseServerLock();
		CDialog *dlg = (CDialog *)pCmd->GetSpecSheet();
		dlg->DestroyWindow();
	}
	delete pCmd;
	m_EditInProgress = FALSE;

	if (need2Refresh && !chainedCommand)
		OnViewUpdate();

	if (TheApp()->m_RunClientWizOnly && !chainedCommand)
		::PostMessage(MainFrame()->m_hWnd, WM_COMMAND, ID_APP_EXIT, 0);
	return 0;
}

// After a client spec has been update, this may get called to sync the client
BOOL CClientListCtrl::SyncAfter(int key, int syncAfter)
{
	CCmd_Get *pCmd= new CCmd_Get;
	pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK, key);
	m_AddToViewList.RemoveAll();
	m_AddToViewList.AddHead(CString(syncAfter == SYNC_HEAD ? _T("#head") : _T("#have")));
	if( pCmd->Run( &m_AddToViewList, FALSE, FALSE ) )
	{
		MainFrame()->UpdateStatus( LoadStringResource(IDS_FILE_SYNC) );
		return TRUE;
	}
	else
	{
		delete pCmd;
		return FALSE;
	}
}

LRESULT CClientListCtrl::OnP4Sync(WPARAM wParam, LPARAM lParam)
{
	CCmd_Get *pCmd= (CCmd_Get *) wParam;
	if (TheApp()->m_RunClientWizOnly)
	{
		if (pCmd->GetWarningsCount() == 0)
		{
			pCmd->ReleaseServerLock();
			::PostMessage(MainFrame()->m_hWnd, WM_COMMAND, ID_APP_EXIT, 0);
		}
		else
		{
			TheApp()->m_RunClientWizOnly = FALSE;
			::ShowWindow(MainFrame()->m_hWnd, SW_RESTORE);
			MainFrame()->UpdateDepotandChangeViews(REDRILL, pCmd->GetServerKey());
		}
	}
	else
		MainFrame()->UpdateDepotandChangeViews(REDRILL, pCmd->GetServerKey());
	delete pCmd;
	return 0;
}

/*
	_________________________________________________________________
*/

LRESULT CClientListCtrl::OnP4ClientList(WPARAM wParam, LPARAM lParam)
{
	CCmd_Clients *pCmd= (CCmd_Clients *) wParam;

	if(!pCmd->GetError())
	{
		CString msg;
		CObList const *clients= pCmd->GetList();
		int count = clients->GetCount();

		SetRedraw(FALSE);
    	int index = 0;
		CString curclient = GET_P4REGPTR()->GetP4Client();
		CString defclient = GET_P4REGPTR()->GetP4Client(TRUE);
		CString user      = GET_P4REGPTR()->GetP4User();
		for(int subItem=0; subItem < CLIENT_MAXCOL; subItem++)
			m_ListAll.column[subItem].SetSize(clients->GetCount(), 100);
		for(POSITION pos= clients->GetHeadPosition(); pos != NULL; index++)
		{
			CP4Client *client=(CP4Client *) clients->GetNext(pos);
			InsertClient(client, index, &curclient, &defclient, &user);
			if ((index & 0x1FFF) == 0)
			{
				msg.FormatMessage(IDS_INSERTING_CLIENTS, count - index);
				MainFrame()->UpdateStatus(msg);
			}
		}
        SetRedraw(TRUE);

		msg.FormatMessage( IDS_NUMBER_OF_CLIENTS_n, index );
		AddToStatus( msg, SV_COMPLETION );

		ReSort();

		// Make sure previous item is re-selected
		if(clients->GetCount() > 0)
		{
			int i = FindInList(m_Active.IsEmpty() ? GET_P4REGPTR()->GetP4Client() : m_Active);
			if (i < 0)	i=0;
			SetItemState(i, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
			EnsureVisible(i, FALSE);
		}

		CP4ListCtrl::SetUpdateDone();
		// Notify the mainframe that we have finished getting the clients,
		// hence the entire set of async command have finished.
		MainFrame()->ExpandDepotIfNeedBe();
		if (m_PostViewUpdateMsg)
			PostMessage(m_PostViewUpdateMsg, m_PostViewUpdateWParam, m_PostViewUpdateLParam);
	}
	else
		CP4ListCtrl::SetUpdateFailed();
	
	delete pCmd;
	m_PostViewUpdateMsg = 0;
	MainFrame()->ClearStatus();
	return 0;
}


/*
	_________________________________________________________________

	Sort callback, not in class
	_________________________________________________________________
*/

int CClientListCtrl::OnCompareItems(LPARAM lParam1, LPARAM lParam2, int subItem)
{
    ASSERT(lParam1 && lParam2);
    CP4Client const *client1 = (CP4Client const *)lParam1;
    CP4Client const *client2 = (CP4Client const *)lParam2;
	CString txt1, txt2;
	switch(subItem)
	{
	case CLIENT_NAME:
		txt1 = client1->GetClientName();
		txt2 = client2->GetClientName();
		break;

	case CLIENT_OWNER:
		txt1 = client1->GetOwner();
		txt2 = client2->GetOwner();
		break;

	case CLIENT_HOST:
		txt1 = client1->GetHost();
		txt2 = client2->GetHost();
		break;

	case CLIENT_ACCESSDATE:
		txt1 = client1->GetDate();
		txt2 = client2->GetDate();
		ConvertDates( txt1, txt2 );
		break;

	case CLIENT_ROOT:
		txt1 = client1->GetRoot();
		txt2 = client2->GetRoot();
		break;

	case CLIENT_DESC:
		txt1 = client1->GetDescription();
		txt2 = client2->GetDescription();
		break;

	default:
		ASSERT(0);
		return 0;
	}

	txt1.MakeUpper();
	txt2.MakeUpper();

	int rc;

	if(m_SortAscending)
		rc = txt1.Compare(txt2);
	else
		rc = txt2.Compare(txt1);

	return rc;
}


/*
	_________________________________________________________________
	
	when creating a new client or switching to another one.
	_________________________________________________________________
*/

BOOL CClientListCtrl::SetP4Client( BOOL bAlways )
{
	//		not that we'd ever get here... but if they are the same, there 
	//		is nothing to do, so bail.
	//
	if ( !bAlways && ( m_Active == GET_P4REGPTR()->GetP4Client() ) )
		return FALSE;

	if (GET_P4REGPTR()->GetExpandFlag() == 1)
		GET_P4REGPTR()->AddMRUPcuPath(MainFrame()->GetCurrentItemPath());

	//		okay, change the session's client. 
	//		(either we're setting the active client back to the registered one 
	//		after using another client, or we are officially resetting 
	//		the registered client to the new active one.)
	//

	if( !GET_P4REGPTR()->SetP4Client( m_Active, TRUE, FALSE, FALSE ) )
	{
		AfxMessageBox(IDS_UNABLE_TO_WRITE_P4CLIENT_TO_THE_REGISTRY, MB_ICONEXCLAMATION);
		m_Active  = GET_P4REGPTR()->GetP4Client();
		return FALSE;
	}

	MainFrame()->UpdateCaption( ) ;	

	return TRUE;
}


/*
	_________________________________________________________________
*/

BOOL CClientListCtrl::AutoCreateClientSpec(LPCTSTR clientName, LPCTSTR clientRoot, 
										   BOOL bEdit, BOOL bTmpl, LPCTSTR tmplate)
{
	m_pNewSpec= new CP4Client;

	CCmd_EditSpec *pCmd= new CCmd_EditSpec;
	pCmd->Init(m_hWnd, RUN_ASYNC, HOLD_LOCK);
	if (bTmpl && !(CString(GET_P4REGPTR()->GetLocalCliTemplate()).IsEmpty())
	 && CString(tmplate) == CString(LOCALDEFTEMPLATE))
	{
		pCmd->SetUseLocalDefTmplate(TRUE);
		bTmpl = FALSE;
		bEdit = TRUE;
	}
	else
		pCmd->SetNewClientRoot(clientRoot);
	pCmd->SetAutoUpdateSpec(bEdit ? FALSE : TRUE);
	BOOL b;
	if (bTmpl)
		b = pCmd->Run( P4CLIENT_SPEC, clientName, tmplate, m_pNewSpec );
	else
		b = pCmd->Run( P4CLIENT_SPEC, clientName, m_pNewSpec );
	if( b )
	{
		MainFrame()->UpdateStatus( LoadStringResource(IDS_EDITING_CLIENT_SPEC) ) ;
		return TRUE;
	}
	delete pCmd;
	delete m_pNewSpec;
	return FALSE;
}

void CClientListCtrl::OnEditSpec( LPCTSTR clientName, BOOL bUseDefTemplate /*=FALSE*/ )
{
	if (m_EditInProgress)
	{
		CantEditRightNow(IDS_CLIENT);
		return;
	}

	m_pNewSpec= new CP4Client;

	CCmd_EditSpec *pCmd= new CCmd_EditSpec;
	pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK);
	pCmd->SetUseLocalDefTmplate(bUseDefTemplate);
	if( pCmd->Run( P4CLIENT_SPEC, clientName, m_pNewSpec ) )
		MainFrame()->UpdateStatus( LoadStringResource(IDS_EDITING_CLIENT_SPEC) ) ;
	else
	{
		delete pCmd;
		delete m_pNewSpec;
	}
}

void CClientListCtrl::OnEditTemplate( LPCTSTR templateName )
{
    // Get a list of all clients, so the dialog can check
    // for a bungle like trying to create a client that
    // already exists
    CStringList list;
    int index=-1;
	m_NewClicked=m_NewClient=FALSE;
	if( GET_SERVERLEVEL() >= 6 )
		list.AddHead( templateName );
	else
	{
		while(1)
		{
			index=GetNextItem(index, LVNI_ALL);
			if( index == -1)
				break;

			TCHAR str[ 1024 ];
			GetItemText(index, 0, str, 1024 );
			list.AddHead(str);
		}
    }

    // Prompt for the new client name, using p4client as a
    // default value
    CTemplateNameDlg dlg;
    dlg.SetTemplateName(templateName);
    dlg.SetVerbotenSpecNames(&list);
    dlg.SetNewSpecName(GET_P4REGPTR()->GetP4Client( ));
	dlg.SetSpecType( P4CLIENT_SPEC );

    if(dlg.DoModal() != IDCANCEL)
    {
		CString saveActive = m_Active;
        m_Active = dlg.GetNewSpecName();	//set and switch to new client
		if (SetP4Client( TRUE ))
		{
			m_pNewSpec= new CP4Client;
			CCmd_EditSpec *pCmd= new CCmd_EditSpec;
			pCmd->Init( m_hWnd, RUN_ASYNC, HOLD_LOCK);
			if( pCmd->Run( P4CLIENT_SPEC, m_Active, templateName, m_pNewSpec ) )
			{
				MainFrame()->UpdateStatus( LoadStringResource(IDS_EDITING_CLIENT_SPEC) ) ;
				m_NewClicked = m_NewClient = TRUE;
				m_ClientNew = m_Active;
			}
			else
			{
				delete pCmd;
				delete m_pNewSpec;
				m_Active = saveActive;
				SetP4Client( TRUE );
			}
		}
    }
}

/////////////////////////////////////////////////////////////////////
// OLE drag-drop support, to accept depot files or folders
// which will define a view to be used to filter the submitted
// changes that this window displays
/////////////////////////////////////////////////////////////////////

DROPEFFECT CClientListCtrl::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) 
{
	m_DropEffect=DROPEFFECT_NONE;
	m_DragDataFormat=0;
	CString fname;

	// Dont allow a drop if the server is busy, since a drop immediately attempts to
	// invoke a server command
	// Also don't allow a drop if we are in local syntax because
	// the left side of the view needs to be specified in depot syntax
	if(SERVER_BUSY() || m_EditInProgress || GET_P4REGPTR( )->ShowEntireDepot( ) > SDF_DEPOT)
		return DROPEFFECT_NONE;
		
	if(pDataObject->IsDataAvailable( (unsigned short) m_CF_DEPOT))
	{
		m_DropEffect=DROPEFFECT_COPY;
		m_DragDataFormat=m_CF_DEPOT;
	}
	
	return m_DropEffect;
}

DROPEFFECT CClientListCtrl::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point) 
{
	// Dont allow a drop if the server is busy, since a drop immediately attempts to
	// invoke a server command
	if(SERVER_BUSY() || m_EditInProgress)
		m_DropEffect= DROPEFFECT_NONE;
		
	return m_DropEffect;
}

BOOL CClientListCtrl::OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point) 
{
	CString fname;
	
	if(SERVER_BUSY() || m_EditInProgress)
	{
		// OnDragEnter() and OnDragOver() should avoid a drop at 
		// the wrong time!
		ASSERT(0);
		return FALSE;
	}
	
	if(m_DragDataFormat == m_CF_DEPOT)
	{
		ClientToScreen(&point);
		::SendMessage(m_depotWnd, WM_DROPTARGET, CLIENTVIEW, MAKELPARAM(point.x,point.y));
		return TRUE;
	}
	// Return false, so depot window doesnt start a file-open operation
	return FALSE;
}

int CClientListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CP4ListCtrl::OnCreate(lpCreateStruct) == -1)
		return -1;

	CStringArray colnames;
	colnames.Add ( LoadStringResource(IDS_CLIENT) );
	colnames.Add ( LoadStringResource(IDS_OWNER) );
	colnames.Add ( LoadStringResource(IDS_HOST) );
	colnames.Add ( LoadStringResource(IDS_DATE) );
	colnames.Add ( LoadStringResource(IDS_ROOT) );
	colnames.Add ( LoadStringResource(IDS_DESCRIPTION) );
	ASSERT( CLIENT_MAXCOL == colnames.GetSize( ) );
    //FIXTHIS: default column widths should be in resource
	int width[ CLIENT_MAXCOL ]={90,90,90,90,150,150};
	RestoreSavedWidths(width, colnames.GetSize( ), sRegValue_ClientList );
	InsertColumnHeaders( colnames, width );

	return 0;
}

void CClientListCtrl::OnUpdateAddToClientView(CCmdUI* pCmdUI) 
{
	CString txt;
    txt.FormatMessage(IDS_ADD_FILES_TO_CLIENT_s_VIEW, GET_P4REGPTR()->GetP4Client());
	pCmdUI->SetText ( txt );
	pCmdUI->Enable( !SERVER_BUSY() && !m_EditInProgress
		&& GET_P4REGPTR()->ShowEntireDepot() <= SDF_DEPOT );
}

void CClientListCtrl::OnAddToClientView() 
{
    if( ! SERVER_BUSY() && IDYES == AfxMessageBox(IDS_CONFIRMADDTOVIEW, MB_YESNO|MB_ICONQUESTION))
    {
	    ::SendMessage(m_depotWnd, WM_GETSELLIST, (WPARAM) &m_AddToViewList, 0);
	    if(m_AddToViewList.GetCount() > 0)
		{
			OnClientEditmy();
		}
	}
}

BOOL CClientListCtrl::TryDragDrop( )
{
	// Store the client this is from
	m_DragFromItemName = GetSelectedItemText();

	m_OLESource.DelayRenderData( (unsigned short) m_CF_CLIENT);

	return m_OLESource.DoDragDrop(DROPEFFECT_COPY, &m_DragSourceRect, NULL)
			== DROPEFFECT_NONE ? FALSE : TRUE;
}

void CClientListCtrl::OnNewClient(WPARAM wParam, LPARAM lParam)
{
	if (!IsClear())
	{
		CString oldclient = wParam ? m_OldDefClient : m_OldCurClient;
		CString newclient = GET_P4REGPTR()->GetP4Client((BOOL)wParam);
		CString curclient = GET_P4REGPTR()->GetP4Client();
		CString defclient = GET_P4REGPTR()->GetP4Client(TRUE);
		LV_ITEM lvItem;
		lvItem.mask = LVIF_IMAGE;
		lvItem.iSubItem = 0;
		lvItem.state = lvItem.stateMask = 0;

		lvItem.iItem = FindInList(oldclient);
		if(lvItem.iItem > -1)
		{
			lvItem.iImage = CP4ViewImageList::GetClientIndex(false,
				oldclient == defclient);
			SetItem(&lvItem );
		}

		lvItem.iItem = FindInList(newclient);
		if(lvItem.iItem > -1)
		{
	        lvItem.iImage = CP4ViewImageList::GetClientIndex(true,
				newclient == defclient);
			SetItem(&lvItem );
		}
		else if (GET_P4REGPTR()->GetClientFilteredFlags())
		{
			int index = FindInListAll(newclient);
			if (index > -1)
			{
				CP4Client * client = new CP4Client;
				client->Create(m_ListAll.column[CLIENT_NAME].GetAt(index),
							  m_ListAll.column[CLIENT_OWNER].GetAt(index),
							  m_ListAll.column[CLIENT_HOST].GetAt(index),
							  m_ListAll.column[CLIENT_ACCESSDATE].GetAt(index),
							  m_ListAll.column[CLIENT_ROOT].GetAt(index),
							  m_ListAll.column[CLIENT_DESC].GetAt(index));
				m_ListAll.column[0].SetAt(index, _T("@@"));	// Removes from list of all clients
				InsertClient(client, GetItemCount(), &curclient, &defclient);
				ReSort();
			}
		}
		if (wParam)
			m_OldDefClient = newclient;
		else
			m_OldCurClient = newclient;
	}
}

void CClientListCtrl::OnPerforceOptions()
{
	MainFrame()->OnPerforceOptions(TRUE, FALSE, IDS_PAGE_CLIENT);
}

void CClientListCtrl::OnUpdateDiff2Clients(CCmdUI* pCmdUI) 
{
	// For now this feature is permanently turned off
	// Remove the 'FALSE' and the /* */ to turn on again
	//
	// However for now this feature just uses File > Diff 2
	// If this is going out, the Client menu should have Diff 2
	pCmdUI->Enable( FALSE /*!SERVER_BUSY()*/ );
}

void CClientListCtrl::OnDiff2Clients()
{
	CDiff2ObjsDlg dlg;
	dlg.m_Type = COMBO_CLIENT;
	m_Active=GetSelectedItemText();
	if (!m_Active.IsEmpty())
		dlg.m_Edit1 = m_Active;
	SET_APP_HALTED(TRUE);
	int rc=dlg.DoModal();  
	SET_APP_HALTED(FALSE);
	if (rc == IDOK)
	{
		CString x = "";
		CCmd_Diff2 *pCmd= new CCmd_Diff2;
		pCmd->Init( m_depotWnd, RUN_ASYNC);
		pCmd->SetOutput2Dlg(GET_P4REGPTR()->Diff2InDialog());
		if( pCmd->Run( _T("//...@") + dlg.m_Edit1, _T("//...@") + dlg.m_Edit2, 
						0, 0, x, x, FALSE, FALSE, TRUE) )
			MainFrame()->UpdateStatus( LoadStringResource(IDS_DIFFING_FILES) );
		else
			delete pCmd;
	}
}

void CClientListCtrl::OnUpdateFilterClients(CCmdUI* pCmdUI)
{
	pCmdUI->Enable( MainFrame()->SetMenuIcon(pCmdUI, !SERVER_BUSY()) );
}

void CClientListCtrl::OnFilterClients()
{
	CClientFilterDlg dlg;
	if(dlg.DoModal() == IDCANCEL)
		return;
	OnViewUpdate();
}

void CClientListCtrl::OnUpdateClearClientFilter(CCmdUI* pCmdUI)
{
	pCmdUI->Enable( MainFrame()->SetMenuIcon(pCmdUI, !SERVER_BUSY() 
					&& GET_P4REGPTR()->GetClientFilteredFlags()) );
}

void CClientListCtrl::OnClearClientFilter()
{
	GET_P4REGPTR()->SetClientFilteredFlags(0);
	OnViewUpdate();
}