#ifndef _COMMON_PROCESS_HPP_
#define _COMMON_PROCESS_HPP_
#ifndef _COMMON_WINDOWS_HPP_
#include <common/windows.hpp>
#endif
#ifndef _COMMON_STRING_HPP_
#include <common/string.hpp>
#endif
#ifndef _COMMON_PUREPROCESS_HPP_
#include <common/pureprcs.hpp>
#endif
#ifndef _COMMON_CREATIONFLAGS_HPP_
#include <common/cflags.hpp>
#endif

class Process : public PureProcess
{
public:
enum AccessFlags{AllAccess=PROCESS_ALL_ACCESS,CreateProcess=PROCESS_CREATE_PROCESS,
                 CreateThread=PROCESS_CREATE_THREAD,DupHandle=PROCESS_DUP_HANDLE,
								 QueryInformation=PROCESS_QUERY_INFORMATION,SetInformation=PROCESS_SET_INFORMATION,
								 Terminate=PROCESS_TERMINATE,VMOperation=PROCESS_VM_OPERATION,VMRead=PROCESS_VM_READ,
								 VMWrite=PROCESS_VM_WRITE,Synchronize=SYNCHRONIZE};																
	Process(void);
	Process(HANDLE hProcess);
	virtual ~Process();
	Process &operator=(HANDLE hProcess);
#if defined(__FLAT__)
	WORD readProcessMemory(LPCVOID lpBaseAddress,LPVOID lpBuffer,DWORD cbRead,LPDWORD lpNumRead)const;
	WORD writeProcessMemory(LPVOID lpBaseAddress,LPVOID lpBuffer,DWORD cbWrite,LPDWORD lpNumWritten)const;
	BOOL flushInstructionCache(LPCVOID lpvBase,DWORD cbFlush)const;
	BOOL createProcess(String moduleNameString,bool modNameIsFirstArg,String currentDirectory,String cmdLineString);
	BOOL createProcess(String moduleNameString,String cmdLineString=String(),bool modNameIsFirstArg=TRUE,const CreationFlags &creationFlags=CreationFlags(),WORD showWindow=SW_SHOWNORMAL,BOOL inheritHandles=FALSE,String currentDirectory=String());
	BOOL setPriorityClass(DWORD priority);
	DWORD getPriorityClass(void);
  void waitForProcess(DWORD waitTime=INFINITE);
  BOOL openProcess(DWORD processID,AccessFlags accessFlags=AccessFlags(QueryInformation|VMRead),BOOL ineritHandles=FALSE);
#else
	BOOL createProcess(String moduleNameString,String cmdLineString=String(),WORD showWindow=SW_SHOWNORMAL);
#endif
	BOOL terminateProcess(BOOL waitForProcess=FALSE);
  BOOL safeTerminateProcess(BOOL waitForProcess=FALSE);
	void waitForInputIdle(void);
	WORD isOkay(void)const;
private:
  enum Disposition{FreeHandle,AssumeHandle,None};
	void closeHandle(void);
#if defined(__FLAT__)
	STARTUPINFO mStartupInfo;
#endif
  Disposition mDisposition;
  WORD mIsOkay;
};

#if defined(__FLAT__)
inline
WORD Process::readProcessMemory(LPCVOID lpBaseAddress,LPVOID lpBuffer,DWORD cbRead,LPDWORD lpNumRead)const
{
  *lpNumRead=0;
	if(!isOkay())return FALSE;
	return ::ReadProcessMemory(getProcess(),lpBaseAddress,lpBuffer,cbRead,lpNumRead);
}

inline
WORD Process::writeProcessMemory(LPVOID lpBaseAddress,LPVOID lpBuffer,DWORD cbWrite,LPDWORD lpNumWritten)const
{
  *lpNumWritten=0;
	if(!isOkay())return FALSE;
	return ::WriteProcessMemory(getProcess(),lpBaseAddress,lpBuffer,cbWrite,lpNumWritten);
}

inline
BOOL Process::flushInstructionCache(LPCVOID lpvBase,DWORD cbFlush)const
{
  if(!isOkay())return FALSE;
	return ::FlushInstructionCache(getProcess(),lpvBase,cbFlush);
}

inline
BOOL Process::setPriorityClass(DWORD priority)
{
	if(!isOkay())return FALSE;
	return ::SetPriorityClass(getProcess(),priority);
}

inline
DWORD Process::getPriorityClass(void)
{
	if(!isOkay())return FALSE;
	return ::GetPriorityClass(getProcess());
}

inline
void Process::waitForProcess(DWORD waitTime)
{
	if(!isOkay())return;
  ::WaitForSingleObject(getProcess(),waitTime);
}
#endif

inline
WORD Process::isOkay(void)const
{
  return mIsOkay;
}
#endif


