/*
 * Copyright 1997, 1999 Perforce Software.  All rights reserved.
 *
 * This file is part of Perforce - the FAST SCM System.
 */

// P4Command.h   
//
// CP4Command is base class for GUI P4 client API command classes
//
// Constructor, client is used for command sequences:
//	CP4Command::CP4Command(CGuiClient *client=NULL); 
//							
// Initialize:
//	CP4Command::Init(HWND replyWnd, BOOL asynch);
// 
// Execution:
//	Command classes should have Run() member functions to set up argc and argv, do
//	setup for result lists, etc, then call the base function: 
//	CP4Command::Run();
//
// Parsing Server Info:
//	Command classes can over-ride the following functions.  The base class functions
//	will just spew the results to the status window:
//	CP4Command::OnOutputInfo(char level, LPCTSTR data, LPCTSTR msg);
//	CP4Command::OnOutputText(LPCTSTR data, int length);
//	CP4Command::OnOutputError(char level, LPCTSTR errBuf, LPCTSTR errMsg);
//	CP4Command::OnErrorPause(LPCTSTR errBuf, Error *e);
//
// Result Set:
//	Command classes should provide access functions as required to fetch results
//
// Destruction:
//	Gui can decide whether to delete result set
//	CP4Command::DeleteResults()
//

#ifndef __P4COMMAND__
#define __P4COMMAND__


#include "GuiClient.h"

#define P4DESCRIBE		1
#define P4BRANCH_SPEC	2
#define P4CHANGE_SPEC	3
#define P4CLIENT_SPEC	4
#define P4DEPOT_SPEC	5
#define P4JOB_SPEC		6
#define P4LABEL_SPEC	7
#define P4PROTECT_SPEC	8
#define P4USER_SPEC		9
#define P4DESCRIBELONG	10
#define	P4GROUP_SPEC	11


#define P4DELETE		1
#define P4EDIT			2
#define P4LOCK			3
#define P4UNLOCK		4
#define P4REVERT		5
#define P4REOPEN		6
#define P4INTEG			7
#define	P4ADD			8
#define P4VIRTREVERT	9
#define P4REVERTUNCHG	10

#define RUN_ASYNC       TRUE
#define RUN_SYNC        FALSE
#define HOLD_LOCK       TRUE
#define LOSE_LOCK       FALSE



// Command reply messagesm sent back to the gui.  These messages will ALWAYS be sent
// with a wParam that is '(WPARAM) this'.

#define	WM_P4ADD				WM_USER+200
#define WM_P4AUTORESOLVE		WM_USER+201
#define WM_P4AUTORESPREVIEW     WM_USER+202
#define WM_P4BRANCHDEL			WM_USER+203
#define WM_P4BRANCHES			WM_USER+205
#define WM_P4BRANCHINTEG		WM_USER+207
#define WM_P4BRANCHINTEGREV     WM_USER+208
#define WM_P4CHANGES			WM_USER+211    // done CCmd_Changes
#define WM_P4CHANGESUBMIT		WM_USER+213
#define WM_P4CLIENTS			WM_USER+216
#define WM_P4CLIENTSPEC			WM_USER+217
#define WM_P4CSTAT				WM_USER+218
#define WM_P4DELETE				WM_USER+219    // done CCmd_Delete
#define WM_P4EXPANDSUBDIR		WM_USER+220

#define WM_P4DESCRIBE			WM_USER+230	   // done CCmd_Describe	
#define WM_P4DIFF				WM_USER+232
#define WM_P4DIFF2				WM_USER+233
#define WM_P4DIFF2_FILE1		WM_USER+234
#define WM_P4DIFF2_FILE2		WM_USER+235
#define WM_P4EDITSPEC			WM_USER+236    // done CCmd_EditSpec
#define WM_P4ERROR				WM_USER+237
#define WM_P4FIX				WM_USER+238
#define WM_P4FIXES				WM_USER+239
#define WM_P4FSTAT				WM_USER+240
#define WM_P4GET				WM_USER+241
#define WM_P4GETWHATIF			WM_USER+242
#define WM_P4HISTORY			WM_USER+243
#define WM_P4INTEGRATE			WM_USER+244
#define WM_P4INTEGRATE2			WM_USER+245
#define WM_P4INFO				WM_USER+246
#define WM_P4JOBS				WM_USER+247
#define WM_P4JOBSPEC			WM_USER+248
#define WM_P4UNRESOLVED			WM_USER+249
#define WM_P4DIRS				WM_USER+250
#define WM_P4DEPOTS				WM_USER+251
#define WM_P4DIRSTAT            WM_USER+252
#define WM_P4FILEINFORMATION	WM_USER+253
#define	WM_P4FILES				WM_USER+254
#define	WM_P4REVERT				WM_USER+255

#define WM_P4LABELS				WM_USER+261
#define WM_P4LABELSPEC			WM_USER+262
#define WM_P4LABELSYNC			WM_USER+263
#define WM_P4LISTOPSTAT			WM_USER+264
#define WM_P4MAXCHANGE			WM_USER+265    // done CCmd_MaxChange
#define WM_P4MERGE2				WM_USER+266
#define WM_P4MERGE3				WM_USER+267
#define WM_P4OSTAT				WM_USER+268
#define WM_P4OPENED				WM_USER+270	
#define WM_P4PASSWORD			WM_USER+271	
#define WM_P4PREPBROWSE			WM_USER+273
#define WM_P4PREPEDIT			WM_USER+274
#define WM_P4PREPEDITGET		WM_USER+275
#define WM_P4REFRESH			WM_USER+276
#define WM_P4LISTOP				WM_USER+277
#define WM_P4RESOLVE			WM_USER+278
#define WM_P4SENDSPEC			WM_USER+279
#define WM_P4FILEREVERT			WM_USER+280
#define WM_P4RESOLVED			WM_USER+281
#define WM_P4DESCRIBEALT		WM_USER+282	   // alternate done CCmd_Describe
#define WM_P4INTEGCHG			WM_USER+283	   // alternate done CCmd_Describe
#define	WM_P4DIFFCHANGEEDIT		WM_USER+284	   // alternate done CCmd_Diff
#define	WM_P4RECOVER			WM_USER+285
#define	WM_THEIRFINDINDEPOT		WM_USER+286		// alternate done CCmd_AutoResolve
#define	WM_THEIRHISTORY			WM_USER+287		// alternate done CCmd_AutoResolve
#define	WM_THEIRPROPERTIES		WM_USER+288		// alternate done CCmd_AutoResolve
#define	WM_P4ENDDESCRIBE		WM_USER+289		// Posted when modeless describe dialog closed
#define	WM_P4ENDFILEINFORMATION	WM_USER+290		// Posted when modeless file info dialog closed
#define	WM_P4ENDHISTORY			WM_USER+291		// Posted when modeless rev hsotory dialog closed
#define WM_P4LOGIN				WM_USER+292
#define WM_P4TICKETS			WM_USER+293
#define	WM_P4ENDSPECEDIT		WM_USER+294		// Posted when modeless spec edit dialog closed
#define	WM_P4ENDDIFF2OUTPUT		WM_USER+295		// Posted when modeless diff2 output dialog closed
#define	WM_P4ENDFINDFILES		WM_USER+296		// Posted when modeless find files dialog closed


#define	WM_DOCUSTOMGET			WM_USER+308
#define	WM_DOINTEGRATE1			WM_USER+309
#define WM_P4UNFIX				WM_USER+310
#define WM_P4UNGET				WM_USER+311
#define WM_P4USERS				WM_USER+315
#define WM_P4USERSPEC			WM_USER+316
#define WM_P4WHERE				WM_USER+317
#define	WM_P4CHGROLLBACK		WM_USER+318
#define WM_P4CHGROLLBACKPREVIEW	WM_USER+319
#define	WM_P4REVHISTFORANNOTATE	WM_USER+320
#define WM_DOLABELDELFILES		WM_USER+321
#define WM_DOLABELSYNCCLI		WM_USER+322
#define WM_DOLABELSYNC			WM_USER+323
#define	WM_ONDODELETEFIXES		WM_USER+324
#define	WM_UPDATEHAVEREV		WM_USER+325
#define WM_P4UPPERBOUND			WM_USER+398     // Used to test command values only, not a command
#define WM_P4STATUS				WM_USER+399


// A magic number indicating the maximum number of times
// we will try to find nodes in the depot pane or changelist
// pane before throwing in the towel and just redrawing both
// windows
#define MAX_FILESEEKS 500
#define MAX_FILESTATS MAX_FILESEEKS

#define MAX_P4ARGS 30

class CGuiClientUser;

class P4KeepAlive : public KeepAlive
{
    public:
		int IsAlive();
} ;

class CP4Command : public CObject
{
    friend CGuiClientUser;

// Construction
public:
	CP4Command(CGuiClient *client=NULL);

	DECLARE_DYNCREATE(CP4Command)

	virtual ~CP4Command();

    CGuiClient * GetClient() { return m_pClient; }
// Attributes	
protected:

    ///////////////////////
    // Support for threading:
    // A pointer to the singlelock, which can be accessed by public functions
    // GetServerKey() and SetServerKey()
    int m_ServerKey;

    // Do we have a valid key?
    BOOL m_HaveServerLock;

    // Should we unlock at the end of ExecCommand() (for m_Asynchronous commands only)
    BOOL m_HoldServerLock;

    // Are we running asynchronous from the thread that called Run()?
    BOOL m_Asynchronous;

    // A pointer to our own thread if asynchronous
    CWinThread *m_pTaskThread;  

    // Are we running (always synchronously) as a child task
	BOOL m_IsChildTask;

	BOOL m_UsedTagged;
	BOOL m_RanInit;
	BOOL m_ClosedConn;
	CString m_TaskName;
	CString m_Function;
	CGuiClient *m_pClient;

	// The reply window for messages
	HWND m_ReplyWnd;
	UINT m_ReplyMsg;

	// The keep alive instance for supporting cancel
	P4KeepAlive m_cb;


	// The arg set
private:
    CStringArray m_args;
    CArray<char*,char*> m_argsA;
protected:
    int GetArgc() const { return m_args.GetSize(); }
    LPCTSTR GetArgv(int index) const { return m_args.GetAt(index); }
	int m_BaseArgs;

	// Basic list-in and list-out support
	POSITION m_posStrListIn;
	CStringList *m_pStrListIn;
	CStringList m_StrListOut;

	// Did the output exceed the number of file swe are
	// willing to update in the tree views?
	BOOL m_HitMaxFileSeeks;

	// Was the depot filtered on open files? See mainfraime.h enum _dft for values
	int m_RedoOpenedFilter;

    // Basic context storage
    HTREEITEM m_CallerItemRef;
    CString m_CallerTextRef;

	// P4 error and return values
	BOOL m_FatalError;			// Use to track warning-level errors that blow a command sequence
	BOOL m_FatalErrorCleared;	// set if m_FatalError was cleared because it was considered minor
	BOOL m_TriggerError;		// Use to record a trigger error
	BOOL m_SyntaxError;
    BOOL m_PWD_DlgCancelled;
	BOOL m_IgnorePermissionErrs;// Set TRUE to ignore permission errors
	CString m_ErrorTxt;			// Alternate error text

	BOOL m_RetryUnicodeMode;
 	
public:
    BOOL GetServerLock(DWORD timeout);
    void ReleaseServerLock();
    int  GetServerKey( );
    void SetServerKey(int key);
    BOOL HaveServerLock() { return m_HaveServerLock; }
	BOOL HitMaxFileSeeks() { return m_HitMaxFileSeeks; }
	void SetHitMaxFileSeeks(BOOL b) { m_HitMaxFileSeeks = b; }
	int  GetRedoOpenedFilter() { return m_RedoOpenedFilter; }
	void SetRedoOpenedFilter(int i) { m_RedoOpenedFilter = i; }

    virtual BOOL Init(HWND replyWnd, BOOL asynch, BOOL holdLock=FALSE, int key=0);
	BOOL Run();
protected:
	virtual void OnOutputInfo(char level, LPCTSTR data, LPCTSTR msg);
	virtual void OnOutputStat( StrDict *varList );
	virtual void OnOutputText(LPCTSTR data, int length);
	virtual void OnOutputError(char level, LPCTSTR errBuf, LPCTSTR errMsg);
	virtual BOOL HandledCmdSpecificError(LPCTSTR errBuf, LPCTSTR errMsg);
	virtual void OnErrorPause(LPCTSTR errBuf, Error *e);
	virtual void DeleteResults();
    virtual BOOL PWDRequired() const { return TRUE; }
    virtual void OnInputData(StrBuf *strBuf, Error *e);
    virtual int OnResolve( ClientMerge *m, Error *e );
	virtual void OnPrompt( const StrPtr &msg, StrBuf &rsp, int noEcho, Error *e );

    // Support for queueable commands
    virtual BOOL IsQueueable() const { return FALSE; }
public:
    HTREEITEM GetItemRef() { return m_CallerItemRef; }
    LPCTSTR GetTextRef() { return m_CallerTextRef; }
    void SetItemRef(HTREEITEM item) { m_CallerItemRef=item; }
    void SetTextRef(LPCTSTR str) { m_CallerTextRef=str; }

public:
	int GetError() const { return m_FatalError; }
	int GetErrorCleared() const { return m_FatalErrorCleared; }
	void ClearError() { m_FatalError = FALSE; }
	int GetTriggerError() const { return m_TriggerError; }
	void SetTriggerError() { m_TriggerError = TRUE; }
    int PWDDlgCancelled() const { return m_PWD_DlgCancelled; }
	LPCTSTR GetErrorText() const { return m_ErrorTxt; }
	LPCTSTR GetTaskName() const { return m_TaskName; }

	HWND GetReplyWnd() const { ASSERT(IsWindow(m_ReplyWnd)); return m_ReplyWnd; }
	UINT GetReplyMsg() const { return m_ReplyMsg; }
	void SetAlternateReplyMsg( UINT msg ) { m_ReplyMsg= msg; }
protected:
	BOOL IsChildTask() const { return m_IsChildTask; }
    BOOL IsAsynchronous() const { return m_Asynchronous; }

protected:	
	int AddArg(LPCTSTR arg);
    int AddArg(int arg);
	void ClearArgs(int baseArgs=0);
	virtual BOOL NextListArgs();	// return TRUE to indicate done; FALSE to keep running
	
	BOOL InitConnection();
public:
	void CloseConn(Error *e);

public:
    void AsyncExecCommand();
	CString GetP4Command( );
	void ExecCommand();    
protected:
	// Inside ExecCommand(), after the connection to server is established:
	// Usefull for calling other commands
	virtual void PreProcess(BOOL& done);
	virtual void PostProcess();

	// Inside ExecCommand(), after invoking a server command (inside the loop)
	// Usefull for calling NextListArgs(), etc
	virtual void ProcessResults(BOOL& done);

    // tell UI that error was caused by a bad client
    void PostClientError();
};

// subclass KeepAlive to implement a customized IsAlive
// function.
	
template <class Cmd>
class CmdPtr
{
    Cmd *m_ptr;
public:
    CmdPtr(WPARAM wParam)
    {
        m_ptr = (Cmd *)wParam;
        ASSERT(m_ptr != 0);
        ASSERT(dynamic_cast<Cmd*>(m_ptr));
    }
    ~CmdPtr()
    {
        delete m_ptr;
    }
    operator Cmd* () { return m_ptr; }
    Cmd* operator -> () { return m_ptr; }
};
/////////////////////////////////////////////////////////////////////////////
#endif //__P4COMMAND__