#ifndef _xbSTAT_
#define _xbSTAT_
/*<<<***************************************************************************
The MIT License (MIT)

Copyright(C) 2013 - 2015 Marc Mirti Mancinelli, Christophe Lardau and Philippe Pamart (xdcube.org)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
////////////////////////////////////////////////////////////////////////////////
#Title: xbStat
#Project: xdcBase
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<02/09/2013: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#ifndef _xbPTR_
#	include "xbPtr.h"
#endif

#ifndef _xbENGINE_
#	include "xbEngine.h"
#endif

#ifndef _xbCONFIG_
#	include "xbConfig.h"
#endif

#ifndef _xbTHREAD_
#	include "xbThread.h"
#endif

#ifdef XDCBASE_X64
#	define xbSTATINT	int64
#else
#	define xbSTATINT	int32
#endif
/*
Points de mesure
	- types
		compteur: un nombre incrémenté pour chaque mesure -> count ++; unité
			-> xbStatPointCounter
		cumul: un nombre ajouté pour chaque mesure -> cumul += nbr, count ++; unité
			-> xbStatPointSum
		débit: un nombre ajouté pour un temps donné -> cumul += nbr, cumulTime += time, count ++; unité
			-> xbStatPointTput (Tput == Throughput/débit)
		compress/mute: 2 nombres ajoutés pour un temps donné -> cumul1 += nbr1, cumul2 += nbr2, cumulTime += time, count ++; unité
			-> xbStatPointMute

*/
class xbEXPORT __declspec(uuid("{5469681D-BA95-4e54-8483-501CA96E7DFC}"))
	xbStatPointItemBase;

//typedef	void (*xbStatCreateObject)(const xbString &parentPath,const xbString &id,xbRefPtr<xbStatPointItemBase> *pprObj);

xbDclCb(xbEXPORT,xbSTATCREATE,(const xbString &parentPath,const xbString &id,xbRefPtr<xbStatPointItemBase> *pprObj),(parentPath,id,pprObj));

#define xbSTATCREATECB_FolderDflt ((xbSTATCREATECB*)1)

/*************************************************************************************
Stat descriptors structures
**************************************************************************************/
#define xbSTATUNIT_PERSEC			0x8000000000000000ULL
#define xbSTATUNIT_PERSECNOAUTOADJ	0x4000000000000000ULL
struct xbStatUnit
{
	const char	*m_pUnitShortStr;
	const char	*m_pUnitStr;
	const char	*m_pUnitPlurStr;
	uint64		m_unitDiv;
	uint64		m_displayMode;

	static xbString ToString(const xbStatUnit *pUnit, int64 intValue, double dblValue, bool bShort = true); 
	static xbString DblToString(const xbStatUnit *pUnit, double dblValue, bool bShort = true); 
	static xbString IntToString(const xbStatUnit *pUnit, int64 intValue, bool bShort = true); 
};

struct xbStatProp
{
	LPCSTR				m_pId;
	LPCSTR				m_pLabel;
	const xbStatUnit	*m_pUnit;
	int					m_dispId;
	ulong				m_dispMode;
};

enum xbStatPropType
{
	xbStatPropType_eol,
	xbStatPropType_InstantPerSec,
	xbStatPropType_InstantPerMin,
	xbStatPropType_InstantPerHour,
	xbStatPropType_InstantPerDay,
	xbStatPropType_Average,
	xbStatPropType_Sum
};

struct xbStatType
{
	xbStatPropType		m_propType;
	LPCSTR				m_pLabel;
	const xbStatProp	*m_pPropList;
};

struct xbStatDesc
{
	LPCSTR				m_pLabel;
	const xbStatType	*m_pTypeList;
	ulong				m_mode;
};

enum xbStatReportOp
{
	xbStatReport_eol,
	xbStatReport_add,
	xbStatReport_sub
};

class xbStatPointBase;
struct xbStatReport
{
	xbStatReportOp	m_op;
	xbStatPointBase *m_pEngine;
};

enum xbStatPropIdEnum
{
	//Available on counter type								Available types:
	xbStatPropId_cCall = 1,								//InstantPerSec, Average, Sum
	xbStatPropId_cTiStat,								//Sum

	//Available on sum type (+counter props)
	xbStatPropId_cUnit,									//InstantPerSec, Average, Sum
	xbStatPropId_cUnitPeakMin,							//InstantPerSec, Sum
	xbStatPropId_cUnitPeakMax,							//InstantPerSec, Sum
	xbStatPropId_cUnitPerCall,							//InstantPerSec, Average
	xbStatPropId_UnitTimePercent,						//InstantPerSec, Average
	xbStatPropId_UnitTimePercentPeakMax,				//InstantPerSec
	xbStatPropId_UnitTimePercentPeakMin,				//InstantPerSec

	//Available on throughput type (+sum props)
	xbStatPropId_cTi,									//InstantPerSec, Average, Sum
	xbStatPropId_cTiPeakMax,							//InstantPerSec, Sum
	xbStatPropId_cTiPeakMin,							//InstantPerSec, Sum
	xbStatPropId_cTiPerCall,							//InstantPerSec, Average
	xbStatPropId_cUnitPerTi,							//InstantPerSec, Average
	xbStatPropId_cUnitPerTiPeakMax,						//InstantPerSec
	xbStatPropId_cUnitPerTiPeakMin,						//InstantPerSec
	xbStatPropId_TimePercent,							//InstantPerSec, Average
	xbStatPropId_TimePercentPeakMax,					//InstantPerSec
	xbStatPropId_TimePercentPeakMin,					//InstantPerSec

	//Available on mute type (+throughput props)
	xbStatPropId_cUnit2,								//InstantPerSec, Average, Sum
	xbStatPropId_cUnit2PeakMin,							//InstantPerSec, Sum
	xbStatPropId_cUnit2PeakMax,							//InstantPerSec, Sum
	xbStatPropId_cUnit2PerCall,							//InstantPerSec, Average
	xbStatPropId_cUnit2PerTi,							//InstantPerSec, Average
	xbStatPropId_cUnit2PerTiPeakMax,					//InstantPerSec
	xbStatPropId_cUnit2PerTiPeakMin,					//InstantPerSec
	xbStatPropId_UnitPerUnit2Percent,					//InstantPerSec, Average
	xbStatPropId_UnitPerUnit2PercentPeakMax,			//InstantPerSec
	xbStatPropId_UnitPerUnit2PercentPeakMin,			//InstantPerSec
	xbStatPropId_Unit2PerUnitPercent,					//InstantPerSec, Average
	xbStatPropId_Unit2PerUnitPercentPeakMax,			//InstantPerSec
	xbStatPropId_Unit2PerUnitPercentPeakMin				//InstantPerSec
};

#define xbSTAT_NOTDEF	int64(0x7FFFFFFFFFFFFFF0ULL)
#define xbSTAT_ISDBL	int64(0x7FFFFFFFFFFFFFF1ULL)
#define xbSTAT_ISSTR	int64(0x7FFFFFFFFFFFFFF2ULL)
#define xbSTAT_INTMAX	int64(0x7FFFFFFFFFFFFFF0ULL)
#define xbSTAT_INTMIN	int64(0x8000000000000000ULL)

/*************************************************************************************
Predefined units
**************************************************************************************/
xbEXPORT extern const xbStatUnit xbStatUnit_Byte[];
xbEXPORT extern const xbStatUnit xbStatUnit_BytePerSec[];
xbEXPORT extern const xbStatUnit xbStatUnit_Percent[];
xbEXPORT extern const xbStatUnit xbStatUnit_OpCount[];
xbEXPORT extern const xbStatUnit xbStatUnit_OpCountPerSec[];
xbEXPORT extern const xbStatUnit xbStatUnit_MicroSec[];

/*************************************************************************************
Predefined stat descriptors
**************************************************************************************/
xbEXPORT extern const xbStatDesc xbStatDesc_LockTime;
xbEXPORT extern const xbStatType xbStatTypeList_LockTime[];
xbEXPORT extern const xbStatProp xbStatPropList_LockTimeInstant[];
xbEXPORT extern const xbStatProp xbStatPropList_LockTimeAverage[];
xbEXPORT extern const xbStatProp xbStatPropList_LockTimeSum[];

xbEXPORT extern const xbStatDesc xbStatDesc_ByteTputSimple;
xbEXPORT extern const xbStatType xbStatTypeList_ByteTputSimple[];
xbEXPORT extern const xbStatProp xbStatPropList_ByteTputSimpleInstant[];
xbEXPORT extern const xbStatProp xbStatPropList_ByteTputSimpleAverage[];
xbEXPORT extern const xbStatProp xbStatPropList_ByteTputSimpleSum[];

xbEXPORT extern const xbStatDesc xbStatDesc_CompressByteMute;
xbEXPORT extern const xbStatType xbStatTypeList_CompressByteMute[];
xbEXPORT extern const xbStatProp xbStatPropList_CompressByteMuteInstant[];
xbEXPORT extern const xbStatProp xbStatPropList_CompressByteMuteAverage[];
xbEXPORT extern const xbStatProp xbStatPropList_CompressByteMuteSum[];

xbEXPORT extern const xbStatDesc xbStatDesc_UncompressByteMute;
xbEXPORT extern const xbStatType xbStatTypeList_UncompressByteMute[];
xbEXPORT extern const xbStatProp xbStatPropList_UncompressByteMuteInstant[];
xbEXPORT extern const xbStatProp xbStatPropList_UncompressByteMuteAverage[];
xbEXPORT extern const xbStatProp xbStatPropList_UncompressByteMuteSum[];

xbEXPORT extern const xbStatDesc xbStatDesc_Op;
xbEXPORT extern const xbStatType xbStatTypeList_Op[];
xbEXPORT extern const xbStatProp xbStatPropList_OpInstant[];
xbEXPORT extern const xbStatProp xbStatPropList_OpAverage[];
xbEXPORT extern const xbStatProp xbStatPropList_OpSum[];

/*************************************************************************************
Implementation
**************************************************************************************/
#define xbSTATFLAGS_CHKDISABLED		0x8000000000000000ULL
#define xbSTATFLAGS_CHKENABLED		0x4000000000000000ULL
#define xbSTATFLAGS_PARENTDISABLED	0x2000000000000000ULL
#define xbSTATFLAGS_PARENTENABLED	0x1000000000000000ULL
#define xbSTATFLAGS_CFGDISABLED		0x0800000000000000ULL
#define xbSTATFLAGS_CFGENABLED		0x0400000000000000ULL
#define xbSTATFLAGS_USERDISABLED	0x0200000000000000ULL
#define xbSTATFLAGS_USERENABLED		0x0100000000000000ULL
#define xbSTATFLAGS_SNAPSHOT		0x0008000000000000ULL
#define xbSTATFLAGS_CFGLOADED		0x0004000000000000ULL

#define xbSTATMODE_DISABLED					0x80000000
#define xbSTATMODE_ENABLED					0x40000000
#define xbSTATMODE_DONTCREATECFGKEY			0x20000000
#define xbSTATMODE_STARTATBOOT				0x10000000

#define xbSTATFLAGS_DISABLED		uint64(xbSTATMODE_DISABLED)
#define xbSTATFLAGS_ENABLED			uint64(xbSTATMODE_ENABLED)
#define xbSTATFLAGS_SUMPROPAGPARENT	uint64(xbSTATMODE_SUMPROPAGPARENT)
#define xbSTATFLAGS_SUMDISABLED		uint64(xbSTATMODE_SUMDISABLED)

class xbStatEngine;
/*************************************************************************************
Base class for stat point objects
**************************************************************************************/
class xbEXPORT xbStatPointItemBase:public xbObject
{
public:
	xbStatPointItemBase()
	{
		m_flags=0ULL;
		m_pEngine = NULL;
		m_pDesc = NULL;
		m_pReportList = NULL;
	}
	virtual ~xbStatPointItemBase()
	{
		xbRdbgAssert(m_pEngine==NULL);
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbStatPointItemBase);
		return xbObject::GetInterface(riid,ppInterf);
	}

	virtual void Create(xbStatEngine *pEngine,const xbString &parentPath,const xbString &id,const xbStatDesc *pDesc,
		LPCSTR pLabel,const xbStatReport *pReportList,ulong startMode)
	{
		xbObject::Create();

		m_pEngine = pEngine;
		m_parentPath = parentPath;
		m_flags = uint64(startMode);
		m_id = id;
		m_pDesc = pDesc;
		m_pReportList = pReportList;
		if (pLabel && *pLabel)
			m_label = pLabel;
	}
	virtual void Destroy()
	{
		xbArray< xbRefPtr<xbStatPointItemBase> > arrPoint;
		{
			xbSectLock lck(&m_sectData);
			m_pEngine=NULL;
			arrPoint.Attach(&m_arrPoint);
		}
		xbObject::Destroy();
		eProtectBegin();
		xbRefPtr<xbStatPointItemBase> *pprPtr = arrPoint.Begin();
		xbRefPtr<xbStatPointItemBase> *pprPend = arrPoint.End();
		while(pprPtr < pprPend)
		{
			(*pprPtr)->Destroy();
			pprPtr++;
		}
		eProtectEnd();
	}

	virtual xbString GetID() const {return m_id;}
	virtual xbString GetParentPath() {return m_parentPath;}
	virtual xbString GetPath() 
	{
		if (m_id.IsEmpty())
			return xbString();
		if (m_parentPath.IsEmpty())
			return m_id;
		return m_parentPath+"/"+m_id;
	}

	virtual xbString GetLabel() const
	{
		if (m_label.IsValid())
			return m_label;
		return m_id;
	}
	virtual xbString GetLabelOnly() const
	{
		return m_label;
	}
	virtual const xbStatReport *GetReportList() const
	{
		return m_pReportList;
	}
	virtual const xbStatDesc *GetDescriptor() const
	{
		return m_pDesc;
	}
	virtual uint64 GetDescriptorÌD() const
	{
		return uint64(m_pDesc);
	}

	inline bool CheckIfEnabled() const 
	{
		if (!(m_flags & (xbSTATFLAGS_CHKDISABLED|xbSTATFLAGS_CHKENABLED)))
			((xbStatPointItemBase*)this)->onEnabledCalc();
		return (m_flags&xbSTATFLAGS_CHKENABLED)?true:false;
	}
	inline bool CheckIfDisabled() const 
	{
		if (!(m_flags & (xbSTATFLAGS_CHKDISABLED|xbSTATFLAGS_CHKENABLED)))
			((xbStatPointItemBase*)this)->onEnabledCalc();
		return (m_flags&xbSTATFLAGS_CHKDISABLED)?true:false;
	}
	inline bool IsEnabled() const 
	{
		return (m_flags&xbSTATFLAGS_CHKENABLED)?true:false;
	}
	inline bool IsDisabled() const 
	{
		return (m_flags&xbSTATFLAGS_CHKENABLED)?false:true;
	}
	virtual void SetEnabled(bool bVal,bool bRecursive = true,bool bCalledFromParent = false);

	bool IsSnapShot() const {return (m_flags&xbSTATFLAGS_SNAPSHOT)?true:false;}
	virtual void SetSnapShot(bool bVal,bool bRecursive = true);

	virtual void ConfigReload();
	virtual void Reset(bool bRecursive = true);

	virtual void FolderCreateCb(const xbString &parentPath,const xbString &id,xbRefPtr<xbStatPointItemBase> *pprFolder);

	virtual bool HasPointEnabled() const;
	virtual bool HasPoint() const {return m_arrPoint.IsValid();}
	virtual bool PointGet(int idx, xbRefPtr<xbStatPointItemBase> *pprChild);
	virtual bool PointGet(const xbString &path, xbRefPtr<xbStatPointItemBase> *pprChild,xbSTATCREATECB *pCreateCb = NULL);
	virtual bool PointDel(const xbString &path);

	virtual const CLSID &GetClassID() const = 0; 
	virtual bool HasProperty() const = 0;

	virtual bool PropertyTypeEnum(int &idx, xbStatPropType *pType, xbString *pLabel);
	virtual bool HasPropertyType(xbStatPropType type);
	virtual bool PropertyEnum(xbStatPropType type,int &idx, xbString *pLabel, const xbStatUnit	**pUnit, 
					int64 *pIntValue, double *pDblValue, xbString *pStringValue, 
					xbString *pId = NULL, int *pDispId = NULL);
	virtual bool PropertyGet(xbStatPropType type,LPCSTR pId, xbString *pLabel, const xbStatUnit	**pUnit, 
					int64 *pIntValue,double *pDblValue, xbString *pStringValue,int sampleCnt=0,int *pSampleCnt=NULL,
					int *pDispId = NULL);
	virtual bool PropertyGet(xbStatPropType type,int dispId, xbString *pLabel, const xbStatUnit	**pUnit, 
					int64 *pIntValue,double *pDblValue, xbString *pStringValue,int sampleCnt=0,int *pSampleCnt=NULL,
					xbString *pId = NULL);
	virtual bool HasProperty(xbStatPropType type,int dispId);

	void ConfigLoad()
	{
		if (m_flags & xbSTATFLAGS_CFGLOADED)
			return;
		xbSectLock lck(&m_sectData);
		if (m_flags & xbSTATFLAGS_CFGLOADED)
			return;
		onConfigLoad(lck);
	}
	uint64 GetFlags() const {return m_flags;}

	virtual void onPointWatch(int &cDone,uint64 tiStart);
protected:
	virtual void onStatSnapShotStart() = 0;
	virtual void onStatSnapShotStop() = 0;
	virtual void onStatReset() = 0;
	virtual bool onPropertyGet(xbStatPropType type,int dispId,int64 *pIntValue,double *pDblValue, xbString *pStringValue,int sampleCnt,int *pSampleCnt) = 0;

	virtual void onEnabledCalc();
	virtual void onConfigLoad(xbSectLock &sectData);
	virtual void onConfigLoad(xbCfgKey &cfgKey,xbStatPointItemBase *pParent);
protected:
	mutable xbSectShare	m_sectData;
	xbStatEngine				*m_pEngine;

	xbString					m_id,m_parentPath;
	const xbStatDesc			*m_pDesc;
	const xbStatReport			*m_pReportList;
	
	xbString					m_label;

	uint64						m_flags;

	xbArray< xbRefPtr<xbStatPointItemBase> > m_arrPoint;

	static int	findItemCb(const xbRefPtr<xbStatPointItemBase> &prItem,const void *id);
	const xbStatProp *propListFind(xbStatPropType type);
};

/*************************************************************************************
Folder class for stat point objects
**************************************************************************************/
class xbEXPORT __declspec(uuid("{1FA8CF34-59DD-42eb-B403-C0BD8F13B618}"))
	xbStatPointItemFolder:public xbStatPointItemBase
{
public:
	xbStatPointItemFolder()
	{
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbStatPointItemFolder);
		return xbStatPointItemBase::GetInterface(riid,ppInterf);
	}
	virtual const CLSID &GetClassID() const {return __uuidof(xbStatPointItemFolder);} 
	virtual bool HasProperty() const {return false;}
protected:
	virtual void onStatSnapShotStart() {}
	virtual void onStatSnapShotStop() {}
	virtual void onStatReset() {}
	virtual bool onPropertyGet(xbStatPropType type,int dispId,int64 *pIntValue,double *pDblValue, xbString *pStringValue,int sampleCnt,int *pSampleCnt)
	{
		return false;
	}
};

/*************************************************************************************
Stat engine
**************************************************************************************/
#define xbCpuUsage_SAMPLECOUNT	10
class xbEXPORT xbCpuUsage
{
public:
	typedef BOOL ( __stdcall * pfnGetSystemTimes)( LPFILETIME lpIdleTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime );

	xbCpuUsage(HANDLE hProcess = GetCurrentProcess(),bool bSysGet = true);
	~xbCpuUsage();

	void update();
	long processGet() const;
	long systemGet() const;
	bool get(long *pProcCpu,long *pSysCpu) const;
protected:
	mutable xbSectShare m_sect;
	uint64		m_lastTi;	
	uint64		m_lastUserTime;	
	uint64		m_lastKernelTime;	
	uint64		m_lastSysUserTime;
	uint64		m_lastSysKernelTime;
	uint64		m_lastSysIdleTime;
	long		m_noSample;
	bool		m_bSampleFull;
	long		m_cpu[xbCpuUsage_SAMPLECOUNT];
	long		m_sysCpu[xbCpuUsage_SAMPLECOUNT];
//        cpuProcess = int( ( ( ( userTimeProcess - s_userTimeProcess ) + ( kernelTimeProcess - s_kernelTimeProcess ) ) *100 ) / div );
	HANDLE		m_hProcess;
    HINSTANCE	m_hKernel;
    pfnGetSystemTimes m_pfnGetSystemTimes;
};

class xbEXPORT __declspec(uuid("{5469681D-BA95-4e54-8483-501CA96E7DFC}"))
	xbStatEngine:public xbEngine
{
public:
	xbStatEngine(const char *pLabel,const xbEngines &engUsed = xbEngines());
	virtual ~xbStatEngine()
	{
		Destroy();
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbStatEngine);
		return xbEngine::GetInterface(riid,ppInterf);
	}

	void RootGet(xbRefPtr<xbStatPointItemFolder> *pprRoot,bool bStartWatchDog=true);
	bool IsWatchDogStarted() const;
	void WatchDogStart();
	void WatchDogStop();
	bool PointGet(const xbString &path, xbRefPtr<xbStatPointItemBase> *pprChild)
	{
		xbRefPtr<xbStatPointItemFolder> prRoot;
		RootGet(&prRoot,true);
		return prRoot->PointGet(path, pprChild);
	}
	void ConfigReload();
	bool PerfCounterBug() const;

	//reserved to xbStatPointBase classes
	bool pointGet(const xbString &path, xbRefPtr<xbStatPointItemBase> *pprChild,xbSTATCREATECB *pCreateCb = NULL)
	{
		xbRefPtr<xbStatPointItemFolder> prRoot;
		RootGet(&prRoot,false);
		return prRoot->PointGet(path, pprChild, pCreateCb);
	}
	bool pointDel(const xbString &path)
	{
		xbRefPtr<xbStatPointItemFolder> prRoot;
		RootGet(&prRoot,false);
		return prRoot->PointDel(path);
	}
	virtual void onConfigLoad(xbStatPointItemBase *pItem,const xbString &path,xbCfgKey &cfgKey);
	virtual bool isLockedByMe() const {return m_sect.IsLockedByMe();}


	long cpuProcessGet()
	{
		if (!IsWatchDogStarted())
			m_cpu.update();
		return m_cpu.processGet();
	}
	long cpuSystemGet()
	{
		if (!IsWatchDogStarted())
			m_cpu.update();
		return m_cpu.systemGet();
	}
	bool cpuGet(long *pProcCpu,long *pSysCpu)
	{
		if (!IsWatchDogStarted())
			m_cpu.update();
		return m_cpu.get(pProcCpu,pSysCpu);
	}
protected:
	virtual void onStart();
	virtual bool onStop(bool);
	virtual bool onPointWatch();

	xbCpuUsage			m_cpu;
	mutable xbSectShare	m_sect;

	xbRefPtr<xbStatPointItemFolder>	m_prRoot;

	class xbEXPORT Thread:public xbTThreadBase<xbThreadCb>
	{
	public:
		Thread(xbStatEngine *pParent)
			:xbTThreadBase<xbThreadCb>(&pParent->m_sect,xbString(pParent->Label)+" Thread")
		{
			m_pParent = pParent;
		}
/*		virtual void	onStart(sIxbThread *pTh)
		{
			m_bStarted = true;
			xbTThreadBase<xbThreadCb>::onStart(pTh);
		}
		virtual DWORD	onStop(sIxbThread *pTh,DWORD ret)
		{
			m_bStarted = false;
			return xbTThreadBase<xbThreadCb>::onStop(pTh,ret);
		}
*/
		virtual DWORD	onThreadProc(sIxbThread *pTh);

/*		virtual void	onCloseAsked(sIxbThread *pTh,LPCSTR pReason)
		{
			xbTThreadBase<xbThreadCb>::onCloseAsked(pTh,pReason);
			m_bStarted = false;
		}*/

		bool isStarted() const {return m_pTh != NULL && m_eventPtr.ProcessToContinue();}
		void wakeUp() {m_eventPtr->Set();}
	protected:
		xbStatEngine	*m_pParent;
	};
	friend Thread;

	Thread m_th;
	bool m_bRootAccessed;
	virtual void RootCreateCb(xbRefPtr<xbStatPointItemFolder> *pprPoint)
	{
		xbStatPointItemFolder *ptr = xbDnew xbStatPointItemFolder();
		try
		{
			ptr->Create(this,"","",NULL,m_pLabel,NULL,0);
			*pprPoint = ptr;
		}
		catch(...)
		{
			ptr->Release();
			throw;
		}
		ptr->Release();
	}
};

extern xbStatEngine	xbEXPORT g_xbStatEngine;

/*************************************************************************************
Base class for stat point engines
**************************************************************************************/
class xbEXPORT __declspec(uuid("{53DE3333-9959-4a05-A24C-78217E8DD7B5}")) 
	xbStatPointBase:public xbEngine
{
public:
	xbStatPointBase(LPCSTR pPath,const xbStatDesc *pDesc,LPCSTR pLabel,const xbStatReport *pReportList,ulong startMode)
		:xbEngine((startMode&xbSTATMODE_STARTATBOOT)?xbEngineStart_Auto:xbEngineStart_OnUse,pLabel?pLabel:pPath,xbEngines(&g_xbStatEngine)),
		m_ptParent(NULL),m_pPtPath(pPath),m_pPtDesc(pDesc),m_pPtLabel(pLabel),m_pPtReportList(pReportList),m_ptStartMode(startMode)
	{
	}
	xbStatPointBase(xbStatPointBase *pParent,LPCSTR pPath,const xbStatDesc *pDesc,LPCSTR pLabel,const xbStatReport *pReportList,ulong startMode)
		:xbEngine((startMode&xbSTATMODE_STARTATBOOT)?xbEngineStart_Auto:xbEngineStart_OnUse,pLabel?pLabel:pPath,xbEngines(pParent)),
		m_ptParent(pParent),m_pPtPath(pPath),m_pPtDesc(pDesc),m_pPtLabel(pLabel),m_pPtReportList(pReportList),m_ptStartMode(startMode)
	{
	}
	virtual ~xbStatPointBase()
	{
		xbRdbgAssert(m_bStopped);
		Destroy();
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbStatPointBase);
		return xbEngine::GetInterface(riid,ppInterf);
	}
	virtual void Get(xbRefPtr<xbStatPointItemBase> *pprItem) = 0;
	virtual bool pointGet(const xbString &path, xbRefPtr<xbStatPointItemBase> *pprChild,xbSTATCREATECB *pCreateCb = NULL) = 0;
	virtual bool pointDel(const xbString &path) = 0;
	virtual bool isLockedByMe() const {return false;}
protected:
	virtual void onStart() = 0; 
	virtual bool onStop(bool)  = 0;

	xbStatPointBase		*m_ptParent;

	LPCSTR				m_pPtPath;
	const xbStatDesc	*m_pPtDesc;
	const xbStatReport	*m_pPtReportList;
	LPCSTR				m_pPtLabel;
	ulong				m_ptStartMode;
};

/*************************************************************************************
Template for stat point engines
**************************************************************************************/
template<class t_statPointClass> class xbTStatPoint:public xbStatPointBase
{
public:
	xbTStatPoint(LPCSTR pPath,const xbStatDesc *pDesc,LPCSTR pLabel,const xbStatReport *pReportList,ulong startMode)
		:xbStatPointBase(pPath,pDesc,pLabel,pReportList,startMode)
	{
	}
	xbTStatPoint(xbStatPointBase *pParent,LPCSTR pPath,const xbStatDesc *pDesc,LPCSTR pLabel,const xbStatReport *pReportList,ulong startMode)
		:xbStatPointBase(pParent,pPath,pDesc,pLabel,pReportList,startMode)
	{
	}
	~xbTStatPoint()
	{
		Destroy();
	}
	t_statPointClass* operator->()
	{
		if (m_prPoint.IsEmpty())
			Start();
		return (t_statPointClass*)m_prPoint;
	}
	virtual void Get(xbRefPtr<xbStatPointItemBase> *pprItem)
	{
		if (m_prPoint.IsEmpty())
			Start();
		*pprItem = m_prPoint;
	}
	void Get(xbRefPtr<t_statPointClass> *pprItem)
	{
		if (m_prPoint.IsEmpty())
			Start();
		*pprItem = m_prPoint;
	}
	t_statPointClass *Ptr()
	{
		if (m_prPoint.IsEmpty())
			Start();
		return (t_statPointClass*)m_prPoint;
	}
	virtual bool pointGet(const xbString &path, xbRefPtr<xbStatPointItemBase> *pprChild,xbSTATCREATECB *pCreateCb = NULL)
	{
		return Ptr()->PointGet(path,pprChild,pCreateCb);
	}
	virtual bool pointDel(const xbString &path)
	{
		return Ptr()->PointDel(path);
	}
	bool IsEnabled()
	{
		return Ptr()->IsEnabled();
	}
	bool IsDisabled()
	{
		return Ptr()->IsDisabled();
	}
protected:
	virtual void onStart()
	{
		xbRefPtr<xbStatPointItemBase> prPoint;
		if (m_ptParent)
			m_ptParent->pointGet(m_pPtPath,&prPoint,&xbCb(xbSTATCREATE,this,xbTStatPoint<t_statPointClass>::PointCreateCb));
		else
			g_xbStatEngine.pointGet(m_pPtPath,&prPoint,&xbCb(xbSTATCREATE,this,xbTStatPoint<t_statPointClass>::PointCreateCb));
		m_prPoint = xbRefQIPtr<t_statPointClass>(prPoint);
	}
	virtual bool onStop(bool)
	{
		m_prPoint.Empty();
		if (m_ptParent)
			m_ptParent->pointDel(m_pPtPath);
		else
			g_xbStatEngine.pointDel(m_pPtPath);
		return true;
	}
	virtual void PointCreateCb(const xbString &parentPath,const xbString &id,xbRefPtr<xbStatPointItemBase> *pprObj)
	{
		t_statPointClass *ptr = xbDnew t_statPointClass();
		try
		{
			ptr->Create(&g_xbStatEngine,parentPath,id,m_pPtDesc,m_pPtLabel,m_pPtReportList,m_ptStartMode);
			*pprObj = ptr;
		}
		catch(...)
		{
			ptr->Release();
			throw;
		}
		ptr->Release();
	}

	xbRefPtr<t_statPointClass> m_prPoint;
};

/*************************************************************************************
Basic implementation for default stat point objects
**************************************************************************************/
class xbEXPORT __declspec(uuid("{D2445B9B-EF7B-4630-8C04-0AF34D728522}"))
	xbStatPointItemDfltImpl:public xbStatPointItemBase
{
public:
	xbStatPointItemDfltImpl()
	{
		m_cSample = 20;
		m_noSample = 0;
		m_bSampleLoop=false;
		m_peakMin.resetMax();
		m_peakMax.resetMin();
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbStatPointItemDfltImpl);
		return xbStatPointItemBase::GetInterface(riid,ppInterf);
	}
	virtual bool HasProperty() const {return true;}

	struct xbEXPORT StatRecWork
	{
		uint64 m_tiStart;
		volatile xbSTATINT m_cUnit,m_cCall,m_cTi,m_cUnit2;
		StatRecWork()
		{
			reset();
		}
		void reset()
		{
			m_tiStart = 0;
			m_cUnit = m_cCall = m_cTi = m_cUnit2 = 0;
		}
		void reset(uint64 tiStart)
		{
			m_tiStart = tiStart;
			m_cUnit = m_cCall = m_cTi = m_cUnit2 = 0;
		}
		StatRecWork(const StatRecWork &stat)
		{
			m_tiStart = stat.m_tiStart;
			m_cUnit = stat.m_cUnit;
			m_cCall = stat.m_cCall;
			m_cTi = stat.m_cTi;
			m_cUnit2 = stat.m_cUnit2;
		}
		void operator=(const StatRecWork &stat)
		{
			m_tiStart = stat.m_tiStart;
			m_cUnit = stat.m_cUnit;
			m_cCall = stat.m_cCall;
			m_cTi = stat.m_cTi;
			m_cUnit2 = stat.m_cUnit2;
		}
	};
	struct xbEXPORT StatRecStore
	{
		uint64 m_tiStart;
		int64 m_cUnit,m_cCall,m_cTi,m_cUnit2;
		StatRecStore()
		{
			reset();
		}
		void reset()
		{
			m_tiStart = 0;
			m_cUnit = m_cCall = m_cTi = m_cUnit2 = 0;
		}
		void resetMin()
		{
			m_tiStart = 0;
			m_cUnit = m_cCall = m_cTi = m_cUnit2 = xbSTAT_INTMIN;
		}
		void resetMax()
		{
			m_tiStart = 0;
			m_cUnit = m_cCall = m_cTi = m_cUnit2 = xbSTAT_INTMAX;
		}
		void setDiff(const StatRecWork &cur,StatRecWork &old)
		{
			m_cUnit = cur.m_cUnit - old.m_cUnit;
			m_cCall = cur.m_cCall - old.m_cCall;
			m_cTi = cur.m_cTi - old.m_cTi;
			m_cUnit2 = cur.m_cUnit2 - old.m_cUnit2;
			old = cur;
		}
		void add(const StatRecStore &st)
		{
			m_cUnit += st.m_cUnit;
			m_cCall += st.m_cCall;
			m_cTi += st.m_cTi;
			m_cUnit2 += st.m_cUnit2;
		}
		void sub(const StatRecStore &st)
		{
			m_cUnit -= st.m_cUnit;
			m_cCall -= st.m_cCall;
			m_cTi -= st.m_cTi;
			m_cUnit2 += st.m_cUnit2;
		}
	};
protected:
	StatRecWork				m_cur,m_old;
	xbArray<StatRecStore>	m_arrSample;
	StatRecStore			m_sum,m_peakMin,m_peakMax;
	int						m_cSample,m_noSample;
	bool					m_bSampleLoop;

	virtual void onStatSnapShotStart() 
	{
	}
	virtual void onStatSnapShotStop() 
	{
	}
	virtual void onStatReset() 
	{
		m_arrSample.Empty();
		m_noSample = 0;
		m_bSampleLoop=false;
		m_sum.reset();
		m_peakMin.resetMax();
		m_peakMax.resetMin();
	}
	StatRecStore &newSample(uint64 tiStart)
	{
		if (m_arrSample.IsEmpty())
			m_arrSample.Length = m_cSample;
		int no = m_noSample++;
		if (no >= m_cSample)
		{
			no = m_noSample = 0;
			m_bSampleLoop=true;
		}
		StatRecStore &ret = m_arrSample.GetAt(no);
		ret.m_tiStart = tiStart;
		return ret;
	}
	virtual void onPointWatch(int &cDone,uint64 tiStart)
	{
		if (CheckIfEnabled())
		{
			cDone++;
			StatRecWork cur(m_cur);

			xbSectLock lck(&m_sectData);
			if (!cur.m_tiStart)
			{
				m_cur.reset(tiStart);
				m_old.reset();
			}
			else
			{
				StatRecStore &st = newSample(cur.m_tiStart);
				st.setDiff(cur,m_old);
				m_sum.add(st);
				if (!m_sum.m_tiStart)
					m_sum.m_tiStart = st.m_tiStart;
				m_cur.m_tiStart = tiStart;
				//TODO: ici propager st
			}
		}

		xbStatPointItemBase::onPointWatch(cDone,tiStart);
	}
	virtual void onEnabledCalc()
	{
		{
			xbSectLock lck(&m_sectData);
			m_cur.m_tiStart = 0;
		}
		xbStatPointItemBase::onEnabledCalc();
/*		uint64 tiStart = ::xbGetTimeInMicroSec();
		xbSectLock lck(&m_sectData);
		m_cur.reset(tiStart);
		m_old.reset();*/
	}
	bool onPropertyGet_Counter(xbStatPropType type,int dispId,int64 *pIntValue,double *pDblValue, xbString *pStringValue,int sampleCnt,int *pSampleCnt);
	bool onPropertyGet_Sum(xbStatPropType type,int dispId,int64 *pIntValue,double *pDblValue, xbString *pStringValue,int sampleCnt,int *pSampleCnt);
	bool onPropertyGet_Tput(xbStatPropType type,int dispId,int64 *pIntValue,double *pDblValue, xbString *pStringValue,int sampleCnt,int *pSampleCnt);
	bool onPropertyGet_Mute(xbStatPropType type,int dispId,int64 *pIntValue,double *pDblValue, xbString *pStringValue,int sampleCnt,int *pSampleCnt);

	double calcPerSec(int dispId);
	void calcPerSec(int dispId, const StatRecStore &st, double tiDiff, double &ret, int64 &retDiv, int no);
};

/*************************************************************************************
Stat point counter object
**************************************************************************************/
class xbEXPORT __declspec(uuid("{EE68540A-E4BD-4efe-85D4-BC69C6407F57}"))
	xbStatPointItemCounter:public xbStatPointItemDfltImpl
{
public:
	xbStatPointItemCounter()
	{
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbStatPointItemCounter);
		return xbStatPointItemDfltImpl::GetInterface(riid,ppInterf);
	}
	virtual const CLSID &GetClassID() const {return __uuidof(xbStatPointItemCounter);} 

#ifdef XDCBASE_X64
	void inc()
	{
		if (IsDisabled())
			return;
		::xbInterlockIncrement64((LONGLONG*)&m_cur.m_cCall);
	}
#else
	void inc()
	{
		if (IsDisabled())
			return;
		::xbInterlockIncrement32((LONG*)&m_cur.m_cCall);
	}
#endif
	void incUnsafe()
	{
		if (IsDisabled())
			return;
		m_cur.m_cCall++;
	}
protected:
	virtual bool onPropertyGet(xbStatPropType type,int dispId,int64 *pIntValue,double *pDblValue, xbString *pStringValue,int sampleCnt,int *pSampleCnt)
	{
		return onPropertyGet_Counter(type,dispId,pIntValue,pDblValue,pStringValue,sampleCnt,pSampleCnt);
	}
};

/*************************************************************************************
Stat point sum object
**************************************************************************************/
class xbEXPORT __declspec(uuid("{673045FD-99F9-4686-9CE6-B8E80FA4829B}"))
	xbStatPointItemSum:public xbStatPointItemDfltImpl
{
public:
	xbStatPointItemSum()
	{
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbStatPointItemSum);
		return xbStatPointItemDfltImpl::GetInterface(riid,ppInterf);
	}
	virtual const CLSID &GetClassID() const {return __uuidof(xbStatPointItemSum);} 

#ifdef XDCBASE_X64
	void add(int64 cUnit)
	{
		if (IsDisabled())
			return;
		::xbInterlockIncrement64((LONGLONG*)&m_cur.m_cCall);
		::xbInterlockExchangeAdd64((LONGLONG*)&m_cur.m_cUnit, (LONGLONG)cUnit);
	}
	void peakAdd(int64 cUnit)
	{
		if (IsDisabled())
			return;
		::xbInterlockIncrement64((LONGLONG*)&m_cur.m_cCall);
		::xbInterlockExchangeAdd64((LONGLONG*)&m_cur.m_cUnit, (LONGLONG)cUnit);
		if (cUnit < m_peakMin.m_cUnit)
			m_peakMin.m_cUnit = cUnit;
		if (cUnit > m_peakMax.m_cUnit)
			m_peakMax.m_cUnit = cUnit;
	}
#else
	void add(int32 cUnit)
	{
		if (IsDisabled())
			return;
		::xbInterlockIncrement32((LONG*)&m_cur.m_cCall);
		::xbInterlockExchangeAdd32((LONG*)&m_cur.m_cUnit, (LONG)cUnit);
	}
	void peakAdd(int32 cUnit)
	{
		if (IsDisabled())
			return;
		::xbInterlockIncrement32((LONG*)&m_cur.m_cCall);
		::xbInterlockExchangeAdd32((LONG*)&m_cur.m_cUnit, (LONG)cUnit);
		if (cUnit < m_peakMin.m_cUnit)
			m_peakMin.m_cUnit = cUnit;
		if (cUnit > m_peakMax.m_cUnit)
			m_peakMax.m_cUnit = cUnit;
	}
#endif
	void addUnsafe(xbSTATINT cUnit)
	{
		if (IsDisabled())
			return;
		m_cur.m_cCall++;
		m_cur.m_cUnit += cUnit;
	}
	void peakAddUnsafe(xbSTATINT cUnit)
	{
		if (IsDisabled())
			return;
		m_cur.m_cCall++;
		m_cur.m_cUnit += cUnit;
		if (cUnit < m_peakMin.m_cUnit)
			m_peakMin.m_cUnit = cUnit;
		if (cUnit > m_peakMax.m_cUnit)
			m_peakMax.m_cUnit = cUnit;
	}
	void addUnsafeTickCount(ulong tiStart)
	{
		if (IsDisabled())
			return;
		m_cur.m_cCall++;
		m_cur.m_cUnit += xbSTATINT(::GetTickCount() - tiStart)*1000;
	}
	void peakAddUnsafeTickCount(ulong tiStart)
	{
		if (IsDisabled())
			return;
		xbSTATINT cUnit=xbSTATINT(::GetTickCount() - tiStart)*1000;
		m_cur.m_cCall++;
		m_cur.m_cUnit += cUnit;
		if (cUnit < m_peakMin.m_cUnit)
			m_peakMin.m_cUnit = cUnit;
		if (cUnit > m_peakMax.m_cUnit)
			m_peakMax.m_cUnit = cUnit;
	}
protected:
	virtual bool onPropertyGet(xbStatPropType type,int dispId,int64 *pIntValue,double *pDblValue, xbString *pStringValue,int sampleCnt,int *pSampleCnt)
	{
		return onPropertyGet_Sum(type,dispId,pIntValue,pDblValue,pStringValue,sampleCnt,pSampleCnt);
	}
};

/*************************************************************************************
Stat point throughput object
**************************************************************************************/
class xbEXPORT __declspec(uuid("{C5E943CF-3BF2-4d2b-8C1D-163E14C8017F}"))
	xbStatPointItemTput:public xbStatPointItemDfltImpl
{
public:
	xbStatPointItemTput()
	{
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbStatPointItemTput);
		return xbStatPointItemDfltImpl::GetInterface(riid,ppInterf);
	}
	virtual const CLSID &GetClassID() const {return __uuidof(xbStatPointItemTput);} 

#ifdef XDCBASE_X64
	void add(int64 cUnit,int64 cTi)
	{
		if (IsDisabled())
			return;
		::xbInterlockIncrement64((LONGLONG*)&m_cur.m_cCall);
		::xbInterlockExchangeAdd64((LONGLONG*)&m_cur.m_cUnit, (LONGLONG)cUnit);
		::xbInterlockExchangeAdd64((LONGLONG*)&m_cur.m_cTi, (LONGLONG)cTi);
	}
	void peakAdd(int64 cUnit,int64 cTi)
	{
		if (IsDisabled())
			return;
		::xbInterlockIncrement64((LONGLONG*)&m_cur.m_cCall);
		::xbInterlockExchangeAdd64((LONGLONG*)&m_cur.m_cUnit, (LONGLONG)cUnit);
		::xbInterlockExchangeAdd64((LONGLONG*)&m_cur.m_cTi, (LONGLONG)cTi);
		if (cUnit < m_peakMin.m_cUnit)
			m_peakMin.m_cUnit = cUnit;
		if (cUnit > m_peakMax.m_cUnit)
			m_peakMax.m_cUnit = cUnit;
		if (cTi < m_peakMin.m_cTi)
			m_peakMin.m_cTi = cTi;
		if (cTi > m_peakMax.m_cTi)
			m_peakMax.m_cTi = cTi;
	}
#else
	void add(int32 cUnit,int32 cTi)
	{
		if (IsDisabled())
			return;
		::xbInterlockIncrement32((LONG*)&m_cur.m_cCall);
		::xbInterlockExchangeAdd32((LONG*)&m_cur.m_cUnit, (LONG)cUnit);
		::xbInterlockExchangeAdd32((LONG*)&m_cur.m_cTi, (LONG)cTi);
	}
	void peakAdd(int32 cUnit,int32 cTi)
	{
		if (IsDisabled())
			return;
		::xbInterlockIncrement32((LONG*)&m_cur.m_cCall);
		::xbInterlockExchangeAdd32((LONG*)&m_cur.m_cUnit, (LONG)cUnit);
		::xbInterlockExchangeAdd32((LONG*)&m_cur.m_cTi, (LONG)cTi);
		if (cUnit < m_peakMin.m_cUnit)
			m_peakMin.m_cUnit = cUnit;
		if (cUnit > m_peakMax.m_cUnit)
			m_peakMax.m_cUnit = cUnit;
		if (cTi < m_peakMin.m_cTi)
			m_peakMin.m_cTi = cTi;
		if (cTi > m_peakMax.m_cTi)
			m_peakMax.m_cTi = cTi;
	}
#endif
	void addUnsafe(xbSTATINT cUnit,xbSTATINT cTi)
	{
		if (IsDisabled())
			return;
		m_cur.m_cCall++;
		m_cur.m_cUnit += cUnit;
		m_cur.m_cTi += cTi;
	}
	void peakAddUnsafe(xbSTATINT cUnit,xbSTATINT cTi)
	{
		if (IsDisabled())
			return;
		m_cur.m_cCall++;
		m_cur.m_cUnit += cUnit;
		m_cur.m_cTi += cTi;
		if (cUnit < m_peakMin.m_cUnit)
			m_peakMin.m_cUnit = cUnit;
		if (cUnit > m_peakMax.m_cUnit)
			m_peakMax.m_cUnit = cUnit;
		if (cTi < m_peakMin.m_cTi)
			m_peakMin.m_cTi = cTi;
		if (cTi > m_peakMax.m_cTi)
			m_peakMax.m_cTi = cTi;
	}
protected:
	virtual bool onPropertyGet(xbStatPropType type,int dispId,int64 *pIntValue,double *pDblValue, xbString *pStringValue,int sampleCnt,int *pSampleCnt)
	{
		return onPropertyGet_Tput(type,dispId,pIntValue,pDblValue,pStringValue,sampleCnt,pSampleCnt);
	}
};

class xbEXPORT __declspec(uuid("{57E394EC-BC92-4728-9567-A00E94862057}"))
	xbStatPointItemMute:public xbStatPointItemDfltImpl
{
public:
	xbStatPointItemMute()
	{
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbStatPointItemMute);
		return xbStatPointItemDfltImpl::GetInterface(riid,ppInterf);
	}
	virtual const CLSID &GetClassID() const {return __uuidof(xbStatPointItemMute);} 

#ifdef XDCBASE_X64
	void add(int64 cUnit,int64 cUnit2,int64 cTi)
	{
		if (IsDisabled())
			return;
		::xbInterlockIncrement64((LONGLONG*)&m_cur.m_cCall);
		::xbInterlockExchangeAdd64((LONGLONG*)&m_cur.m_cUnit, (LONGLONG)cUnit);
		::xbInterlockExchangeAdd64((LONGLONG*)&m_cur.m_cUnit2, (LONGLONG)cUnit2);
		::xbInterlockExchangeAdd64((LONGLONG*)&m_cur.m_cTi, (LONGLONG)cTi);
	}
	void peakAdd(int64 cUnit,int64 cUnit2,int64 cTi)
	{
		if (IsDisabled())
			return;
		::xbInterlockIncrement64((LONGLONG*)&m_cur.m_cCall);
		::xbInterlockExchangeAdd64((LONGLONG*)&m_cur.m_cUnit, (LONGLONG)cUnit);
		::xbInterlockExchangeAdd64((LONGLONG*)&m_cur.m_cUnit2, (LONGLONG)cUnit2);
		::xbInterlockExchangeAdd64((LONGLONG*)&m_cur.m_cTi, (LONGLONG)cTi);
		if (cUnit < m_peakMin.m_cUnit)
			m_peakMin.m_cUnit = cUnit;
		if (cUnit > m_peakMax.m_cUnit)
			m_peakMax.m_cUnit = cUnit;
		if (cUnit2 < m_peakMin.m_cUnit2)
			m_peakMin.m_cUnit2 = cUnit2;
		if (cUnit2 > m_peakMax.m_cUnit2)
			m_peakMax.m_cUnit2 = cUnit2;
		if (cTi < m_peakMin.m_cTi)
			m_peakMin.m_cTi = cTi;
		if (cTi > m_peakMax.m_cTi)
			m_peakMax.m_cTi = cTi;
	}
#else
	void add(int32 cUnit,int32 cUnit2,int32 cTi)
	{
		if (IsDisabled())
			return;
		::xbInterlockIncrement32((LONG*)&m_cur.m_cCall);
		::xbInterlockExchangeAdd32((LONG*)&m_cur.m_cUnit, (LONG)cUnit);
		::xbInterlockExchangeAdd32((LONG*)&m_cur.m_cUnit2, (LONG)cUnit2);
		::xbInterlockExchangeAdd32((LONG*)&m_cur.m_cTi, (LONG)cTi);
	}
	void peakAdd(int32 cUnit,int32 cUnit2,int32 cTi)
	{
		if (IsDisabled())
			return;
		::xbInterlockIncrement32((LONG*)&m_cur.m_cCall);
		::xbInterlockExchangeAdd32((LONG*)&m_cur.m_cUnit, (LONG)cUnit);
		::xbInterlockExchangeAdd32((LONG*)&m_cur.m_cUnit2, (LONG)cUnit2);
		::xbInterlockExchangeAdd32((LONG*)&m_cur.m_cTi, (LONG)cTi);
		if (cUnit < m_peakMin.m_cUnit)
			m_peakMin.m_cUnit = cUnit;
		if (cUnit > m_peakMax.m_cUnit)
			m_peakMax.m_cUnit = cUnit;
		if (cUnit2 < m_peakMin.m_cUnit2)
			m_peakMin.m_cUnit2 = cUnit2;
		if (cUnit2 > m_peakMax.m_cUnit2)
			m_peakMax.m_cUnit2 = cUnit2;
		if (cTi < m_peakMin.m_cTi)
			m_peakMin.m_cTi = cTi;
		if (cTi > m_peakMax.m_cTi)
			m_peakMax.m_cTi = cTi;
	}
#endif
	void addUnsafe(xbSTATINT cUnit,xbSTATINT cUnit2,xbSTATINT cTi)
	{
		if (IsDisabled())
			return;
		m_cur.m_cCall++;
		m_cur.m_cUnit += cUnit;
		m_cur.m_cUnit2 += cUnit2;
		m_cur.m_cTi += cTi;
	}
	void peakAddUnsafe(xbSTATINT cUnit,xbSTATINT cUnit2,xbSTATINT cTi)
	{
		if (IsDisabled())
			return;
		m_cur.m_cCall++;
		m_cur.m_cUnit += cUnit;
		m_cur.m_cUnit2 += cUnit2;
		m_cur.m_cTi += cTi;
		if (cUnit < m_peakMin.m_cUnit)
			m_peakMin.m_cUnit = cUnit;
		if (cUnit > m_peakMax.m_cUnit)
			m_peakMax.m_cUnit = cUnit;
		if (cUnit2 < m_peakMin.m_cUnit2)
			m_peakMin.m_cUnit2 = cUnit2;
		if (cUnit2 > m_peakMax.m_cUnit2)
			m_peakMax.m_cUnit2 = cUnit2;
		if (cTi < m_peakMin.m_cTi)
			m_peakMin.m_cTi = cTi;
		if (cTi > m_peakMax.m_cTi)
			m_peakMax.m_cTi = cTi;
	}
protected:
	virtual bool onPropertyGet(xbStatPropType type,int dispId,int64 *pIntValue,double *pDblValue, xbString *pStringValue,int sampleCnt,int *pSampleCnt)
	{
		return onPropertyGet_Mute(type,dispId,pIntValue,pDblValue,pStringValue,sampleCnt,pSampleCnt);
	}
};
/*************************************************************************************
Stat point engines
**************************************************************************************/
class xbStatPointFolder:public xbTStatPoint<xbStatPointItemFolder>
{
public:
	xbStatPointFolder(LPCSTR pPath,LPCSTR pLabel,ulong startMode = 0)
		:xbTStatPoint<xbStatPointItemFolder>(pPath,NULL,pLabel,NULL,startMode)
	{
	}
	xbStatPointFolder(xbStatPointBase *pParent,LPCSTR pPath,LPCSTR pLabel,ulong startMode = 0)
		:xbTStatPoint<xbStatPointItemFolder>(pParent,pPath,NULL,pLabel,NULL,startMode)
	{
	}
};

class xbStatPointCounter:public xbTStatPoint<xbStatPointItemCounter>
{
public:
	xbStatPointCounter(LPCSTR pPath,const xbStatDesc *pDesc,LPCSTR pLabel,const xbStatReport *pReportList = NULL,ulong startMode = 0)
		:xbTStatPoint<xbStatPointItemCounter>(pPath,pDesc,pLabel,pReportList,startMode)
	{
	}
	xbStatPointCounter(xbStatPointBase *pParent,LPCSTR pPath,const xbStatDesc *pDesc,LPCSTR pLabel,const xbStatReport *pReportList = NULL,ulong startMode = 0)
		:xbTStatPoint<xbStatPointItemCounter>(pParent,pPath,pDesc,pLabel,pReportList,startMode)
	{
	}
};

class xbStatPointSum:public xbTStatPoint<xbStatPointItemSum>
{
public:
	xbStatPointSum(LPCSTR pPath,const xbStatDesc *pDesc,LPCSTR pLabel,const xbStatReport *pReportList = NULL,ulong startMode = 0)
		:xbTStatPoint<xbStatPointItemSum>(pPath,pDesc,pLabel,pReportList,startMode)
	{
	}
	xbStatPointSum(xbStatPointBase *pParent,LPCSTR pPath,const xbStatDesc *pDesc,LPCSTR pLabel,const xbStatReport *pReportList = NULL,ulong startMode = 0)
		:xbTStatPoint<xbStatPointItemSum>(pParent,pPath,pDesc,pLabel,pReportList,startMode)
	{
	}
};

class xbStatPointTput:public xbTStatPoint<xbStatPointItemTput>
{
public:
	xbStatPointTput(LPCSTR pPath,const xbStatDesc *pDesc,LPCSTR pLabel,const xbStatReport *pReportList = NULL,ulong startMode = 0)
		:xbTStatPoint<xbStatPointItemTput>(pPath,pDesc,pLabel,pReportList,startMode)
	{
	}
	xbStatPointTput(xbStatPointBase *pParent,LPCSTR pPath,const xbStatDesc *pDesc,LPCSTR pLabel,const xbStatReport *pReportList = NULL,ulong startMode = 0)
		:xbTStatPoint<xbStatPointItemTput>(pParent,pPath,pDesc,pLabel,pReportList,startMode)
	{
	}
};

class xbStatPointMute:public xbTStatPoint<xbStatPointItemMute>
{
public:
	xbStatPointMute(LPCSTR pPath,const xbStatDesc *pDesc,LPCSTR pLabel,const xbStatReport *pReportList = NULL,ulong startMode = 0)
		:xbTStatPoint<xbStatPointItemMute>(pPath,pDesc,pLabel,pReportList,startMode)
	{
	}
	xbStatPointMute(xbStatPointBase *pParent,LPCSTR pPath,const xbStatDesc *pDesc,LPCSTR pLabel,const xbStatReport *pReportList = NULL,ulong startMode = 0)
		:xbTStatPoint<xbStatPointItemMute>(pParent,pPath,pDesc,pLabel,pReportList,startMode)
	{
	}
};

/*************************************************************************************
Stack helpers
**************************************************************************************/
#define xbSTATTIMESUBOP(opType, statOp) \
	class xbStatTimeSum ## opType \
	{ \
	public: \
		xbStatTimeSum ## opType(xbStatPointSum *pSum) \
		{ \
			Start(pSum); \
		} \
		xbStatTimeSum ## opType() \
		{ \
			m_pSum=NULL; \
		} \
		~xbStatTimeSum ## opType() \
		{ \
			if (!m_pSum) \
				return; \
			eProtect(Stop();); \
		} \
		void Start(xbStatPointSum *pSum) \
		{ \
			if(!pSum || pSum->IsDisabled()) \
			{ \
				m_pSum = NULL; \
				return; \
			} \
			m_pSum=pSum; \
			m_ti = ::xbGetTimeInMicroSec(); \
		} \
		void Cancel() \
		{ \
			m_pSum=NULL; \
		} \
		void Stop() \
		{ \
			xbStatPointSum *pSum = m_pSum; \
			m_pSum=NULL; \
			if (!pSum) \
				return; \
			(*pSum)->statOp(xbSTATINT(::xbGetTimeInMicroSec() - m_ti)); \
		} \
		xbStatPointSum *m_pSum; \
		uint64			m_ti; \
	}
#define xbSTATTIMETPUTOP(opType, statOp) \
	class xbStatTimeTput ## opType \
	{ \
	public: \
		xbStatTimeTput ## opType(xbStatPointTput *pTput,xbSTATINT cUnit=0) \
		{ \
			Start(pTput,cUnit); \
		} \
		xbStatTimeTput ## opType() \
		{ \
			m_pTput=NULL; \
		} \
		~xbStatTimeTput ## opType() \
		{ \
			if (!m_pTput) \
				return; \
			eProtect(Stop();); \
		} \
		void Start(xbStatPointTput *pTput,xbSTATINT cUnit=0) \
		{ \
			if(!pTput || pTput->IsDisabled()) \
			{ \
				m_pTput = NULL; \
				return; \
			} \
			m_pTput=pTput; \
			m_ti = ::xbGetTimeInMicroSec(); \
			m_cUnit=cUnit; \
		} \
		void Cancel() \
		{ \
			m_pTput=NULL; \
		} \
		void Add(xbSTATINT cUnit) \
		{ \
			m_cUnit+=cUnit; \
		} \
		void Stop(xbSTATINT cUnit=0) \
		{ \
			xbStatPointTput *pTput = m_pTput; \
			m_pTput=NULL; \
			if (!pTput) \
				return; \
			if (cUnit) m_cUnit+=cUnit; \
			(*pTput)->statOp(m_cUnit,xbSTATINT(::xbGetTimeInMicroSec() - m_ti)); \
		} \
		xbStatPointTput *m_pTput; \
		uint64			m_ti; \
		xbSTATINT		m_cUnit; \
	}
#define xbSTATTIMEMUTEOP(opType, statOp) \
	class xbStatTimeMute ## opType \
	{ \
	public: \
		xbStatTimeMute ## opType(xbStatPointMute *pMute,xbSTATINT cUnit=0,xbSTATINT cUnit2=0) \
		{ \
			Start(pMute,cUnit,cUnit2); \
		} \
		xbStatTimeMute ## opType() \
		{ \
			m_pMute=NULL; \
		} \
		~xbStatTimeMute ## opType() \
		{ \
			if (!m_pMute) \
				return; \
			eProtect(Stop();); \
		} \
		void Start(xbStatPointMute *pMute,xbSTATINT cUnit=0,xbSTATINT cUnit2=0) \
		{ \
			if(!pMute || pMute->IsDisabled()) \
			{ \
				m_pMute = NULL; \
				return; \
			} \
			m_pMute=pMute; \
			m_ti = ::xbGetTimeInMicroSec(); \
			m_cUnit=cUnit; \
			m_cUnit2=cUnit2; \
		} \
		void Cancel() \
		{ \
			m_pMute=NULL; \
		} \
		void Add(xbSTATINT cUnit,xbSTATINT cUnit2) \
		{ \
			m_cUnit+=cUnit; \
			m_cUnit2+=cUnit2; \
		} \
		void Add1(xbSTATINT cUnit) \
		{ \
			m_cUnit+=cUnit; \
		} \
		void Add2(xbSTATINT cUnit) \
		{ \
			m_cUnit2+=cUnit; \
		} \
		void Stop(xbSTATINT cUnit=0,xbSTATINT cUnit2=0) \
		{ \
			xbStatPointMute *pMute = m_pMute; \
			m_pMute=NULL; \
			if (!pMute) \
				return; \
			if (cUnit) m_cUnit+=cUnit; \
			if (cUnit2) m_cUnit2+=cUnit2; \
			(*pMute)->statOp(m_cUnit,m_cUnit2,xbSTATINT(::xbGetTimeInMicroSec() - m_ti)); \
		} \
		xbStatPointMute *m_pMute; \
		uint64			m_ti; \
		xbSTATINT		m_cUnit; \
		xbSTATINT		m_cUnit2; \
	}
xbSTATTIMESUBOP(Op,add);						//xbStatTimeSumOp
xbSTATTIMESUBOP(OpUnsafe,addUnsafe);			//xbStatTimeSumOpUnsafe
xbSTATTIMESUBOP(OpPeak,peakAdd);				//xbStatTimeSumOpPeak
xbSTATTIMESUBOP(OpPeakUnsafe,peakAddUnsafe);	//xbStatTimeSumOpPeakUnsafe

xbSTATTIMETPUTOP(Op,add);						//xbStatTimeTputOp
xbSTATTIMETPUTOP(OpUnsafe,addUnsafe);			//xbStatTimeTputOpUnsafe
xbSTATTIMETPUTOP(OpPeak,peakAdd);				//xbStatTimeTputOpPeak
xbSTATTIMETPUTOP(OpPeakUnsafe,peakAddUnsafe);	//xbStatTimeTputOpPeakUnsafe

xbSTATTIMEMUTEOP(Op,add);						//xbStatTimeMuteOp
xbSTATTIMEMUTEOP(OpUnsafe,addUnsafe);			//xbStatTimeMuteOpUnsafe
xbSTATTIMEMUTEOP(OpPeak,peakAdd);				//xbStatTimeMuteOpPeak
xbSTATTIMEMUTEOP(OpPeakUnsafe,peakAddUnsafe);	//xbStatTimeMuteOpPeakUnsafe

#endif
