#ifndef _xbDNITF_
#define _xbDNITF_
/*<<<***************************************************************************
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: xbDnItf
#Project: xdcBase
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<15/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 _xbEXCEPTION_
#	include "xbException.h"
#endif

#ifndef _xbSTREAM_
#	include "xbStream.h"
#endif

#ifndef _xbLOCK_
#	include "xbLock.h"
#endif

#ifndef _xbCTXPROGRESS_
#	include "xbCtxProgress.h"
#endif

#define xbDNWAIT_DFLTTIMEOUT	0
enum xbEXPORT xbDnPriority
{
	xbDnFast = 5,
	xbDnFastLocked = 4,
	xbDnHigh = 3,
	xbDnHighLocked = 2,
	xbDnLow = 1,
	xbDnLowLocked = 0,
	xbDnNotReady = -1,
	xbDnNotReadyLocked = -2
//	xbDnNoPriority = -3
};

inline bool xbDnIsLockedPriority(xbDnPriority priority)
{
	return !(int(priority) & 0x1);
}

interface xbEXPORT sIxbUrlRoots
{
	virtual xbString GetUrlRootForProtocol(const xbString &proto) = 0;
};

xbString	xbEXPORT xbAddPath(const xbString &url,const xbString &path,sIxbUrlRoots *piRoots);
xbString	xbEXPORT xbAddPath(const xbString &url,const xbString &path);
//CAUTION: xbMakeAbsUrl is bugged : not conform to http conventions, use xbAddPath instead.
xbString	xbEXPORT xbMakeAbsUrl(const xbString &url,LPCSTR pCurFile,sIxbUrlRoots *piRoots);
xbString	xbEXPORT xbSetProtocol(const xbString &_url,const xbString &_proto);

xbString	xbEXPORT xbUrlDecode(const xbString &url);
xbString	xbEXPORT xbUrlEncode(const xbString &url,LPCSTR pszChToEncode = NULL,LPCSTR pszChToExclude = NULL);

xbStringA	xbEXPORT xbBase64encodeA(const byte *pDta,int dtaLen);
xbStringA	xbEXPORT xbBase64decodeA(const char *pStr,int strLen);
xbStringW	xbEXPORT xbBase64encodeW(const byte *pDta,int dtaLen);
xbStringA	xbEXPORT xbBase64decodeW(const wchar *pStr,int strLen);
inline xbStringA	xbBase64encodeA(const xbStringA &str)
{
	return xbBase64encodeA((const byte*)str.Ptr(),str.Length);
}
inline xbStringA	xbBase64decodeA(const xbStringA &str)
{
	return xbBase64decodeA(str,str.Length);
}
inline xbStringW	xbBase64encodeW(const xbStringA &str)
{
	return xbBase64encodeW((const byte*)str.Ptr(),str.Length);
}
inline xbStringA	xbBase64decodeW(const xbStringW &str)
{
	return xbBase64decodeW(str,str.Length);
}

xbString	xbEXPORT xbGetProtocol(const xbString &url,xbString *pRet = NULL,bool *pbSlash = NULL,bool bDblSlashRemove = true);
xbString	xbEXPORT xbGetDrive(const xbString &url,xbString *pRet = NULL);

bool		xbEXPORT xbIsAbsUrl(const xbString &_url);
bool		xbEXPORT xbGetResUrl(const xbString &url,xbString *pDll = NULL,xbString *pRet = NULL,LPCSTR *ppResRet = NULL,xbString *pType = NULL,LPCSTR *ppTypeRet = NULL,xbString *ppUrlIfNot = NULL);
bool		xbEXPORT xbGetFileUrl(const xbString &url,xbString *pRet = NULL);
bool		xbEXPORT xbGetNetUrl(const xbString &url,xbString *pRet = NULL);
bool		xbEXPORT xbGetDataUrl(const xbString &url,xbString *pRet = NULL);
bool		xbEXPORT xbGetUncUrl(const xbString &url,xbString *pMachine = NULL,xbString *pRet = NULL);
bool		xbEXPORT xbGetUncPathPart(const xbString &path,xbString *pMachine = NULL,xbString *pRet = NULL);

xbString	xbEXPORT xbGetResNo(int ix,LPCSTR typePtr,HMODULE hMod);

xbString	xbEXPORT xbMakeResUrl(LPCSTR pRes,LPCSTR pType = NULL,HMODULE hMod = NULL);
inline xbString xbMakeResUrl(UINT ResId,LPCSTR pType = NULL,HMODULE hMod = NULL)
{
	return xbMakeResUrl((LPCSTR)MAKEINTRESOURCE(ResId),pType,hMod);
}

xbString	xbEXPORT xbUrlSlash(const xbString &url);
xbString	xbEXPORT _xbUrlAslash(const xbString &url); //use xbPathSlash instead of _xbUrlAslash

//Exception xbEdn: to use by upload/download system
xbEdclStart(xbEdn,xbEadv,{A7637234-F609-40ff-ADE3-AB7F58C40F29},xbEXPORT)
	virtual xbMBiconType GetMBoxIcon() const {return xbMBicon_Stop;}
	virtual const char *GetMBoxTitle() const {return "Download system error";} 
xbEdclEnd(xbEdn);

//Exception xbEdnUser: to use by upload/download system to signal user error
xbEdclStart(xbEdnUser,xbEdn,{1AE6CA24-3C28-435a-A341-8A18FC8354FE},xbEXPORT)
	virtual xbMBiconType GetMBoxIcon() const {return xbMBicon_Exclamation;}
	virtual const char *GetMBoxTitle() const {return "Download error";} 
	virtual bool IsToWriteOnLogFile() const 
	{
		return g_xbExceptionEngine.IsToLog(GetFullEname(),false);
	}
xbEdclEnd(xbEdnUser);

enum xbDnConnectMode
{
	xbDnConnectKeep = 0,
		xbDnConnectClose = 1
};

//Exception xbEdnHttp: to use by upload/download system to signal http error
class xbEXPORT __declspec(uuid("{AE53C1A7-F632-4652-875B-C3719B59BAC2}"))
	xbEdnHttp:public xbEdn
{
public:
	static xbEinfoSt s_info;
	virtual const xbEinfoSt *GetInfo() const {return &s_info;}

	virtual LPCSTR GetFullEname() const {return "xbEdnHttp";}
	virtual const char *GetMBoxTitle() const {return "Download error";} 

	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbEdnHttp);
		return xbEdn::GetInterface(riid,ppInterf);
	}

	xbEdnHttp(long status,const xbString &msg,xbDnConnectMode connectMode = xbDnConnectKeep,LPCSTR pConVar = NULL,xbEctorMode ctorMode = xbEctor_final)
		:xbEdn(msg,xbEctor_base)
	{
		m_status = status;
		m_connectMode = connectMode;
		if (pConVar) 
			m_conVar = pConVar;
		traceExcept(ctorMode);
	}
	xbEdnHttp(long status,const xbString &msg,const xbString &ctx,xbDnConnectMode connectMode = xbDnConnectKeep,LPCSTR pConVar = NULL,xbEctorMode ctorMode = xbEctor_final)
		:xbEdn(msg,ctx,xbEctor_base)
	{
		m_status = status;
		m_connectMode = connectMode;
		if (pConVar) 
			m_conVar = pConVar;
		traceExcept(ctorMode);
	}
	xbEdnHttp(long status,HRESULT hr,const xbString &msg,const xbString &ctx,xbDnConnectMode connectMode = xbDnConnectKeep,LPCSTR pConVar = NULL,xbEctorMode ctorMode = xbEctor_final)
		:xbEdn(hr,msg,ctx,xbEctor_base)
	{
		m_status = status;
		m_connectMode = connectMode;
		if (pConVar) 
			m_conVar = pConVar;
		traceExcept(ctorMode);
	}
	xbEdnHttp(long status,HRESULT hr,const xbString &msg,xbDnConnectMode connectMode = xbDnConnectKeep,LPCSTR pConVar = NULL,xbEctorMode ctorMode = xbEctor_final)
		:xbEdn(hr,msg,xbEctor_base)
	{
		m_status = status;
		m_connectMode = connectMode;
		if (pConVar) 
			m_conVar = pConVar;
		traceExcept(ctorMode);
	}
	virtual bool IsToWriteOnLogFile() const 
	{
		return g_xbExceptionEngine.IsToLog(GetFullEname(),m_status >= 500);
	}

	virtual xbMBiconType GetMBoxIcon() const
	{
		return m_status >= 500?xbMBicon_Stop:xbMBicon_Exclamation;
	}

	virtual long GetHttpStatus() const {return m_status;}
	virtual xbDnConnectMode GetConnectMode() const {return m_connectMode;}
	virtual xbString		GetConnectVar() const {return m_conVar;}
protected:
	long			m_status;
	xbDnConnectMode	m_connectMode;
	xbString		m_conVar;
private:
	xbDclNoCopyForObject(xbEdnHttp);
public:
	xbDefaultHeapDnewImpl(xbEdnHttp);
};


class xbEXPORT __declspec(uuid("{2750F9A8-D1A5-4f0e-B642-0FC49B5B6D08}"))
	xbEdnRetry:public xbEdn
{
public:
	static xbEinfoSt s_info;
	virtual const xbEinfoSt *GetInfo() const {return &s_info;}

	virtual LPCSTR GetFullEname() const {return "xbEdnRetry";}
	virtual xbMBiconType GetMBoxIcon() const {return xbMBicon_Exclamation;}
	virtual const char *GetMBoxTitle() const {return "Download error";} 
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbEdnRetry);
		return xbEdn::GetInterface(riid,ppInterf);
	}

	xbEdnRetry(HRESULT hr,const xbString &msg,int timeOut = -1,xbEctorMode ctorMode = xbEctor_final)
		:xbEdn(hr,msg,xbEctor_base),m_timeOut(timeOut)
	{
		traceExcept(ctorMode);
	}
	xbEdnRetry(const xbString &msg,int timeOut = -1,xbEctorMode ctorMode = xbEctor_final)
		:xbEdn(msg,xbEctor_base),m_timeOut(timeOut)
	{
		traceExcept(ctorMode);
	}
	xbEdnRetry(HRESULT hr,const xbString &msg,const xbString &ctx,int timeOut = -1,xbEctorMode ctorMode = xbEctor_final)
		:xbEdn(hr,msg,ctx,xbEctor_base),m_timeOut(timeOut)
	{
		traceExcept(ctorMode);
	}
	xbEdnRetry(const xbString &msg,const xbString &ctx,int timeOut = -1,xbEctorMode ctorMode = xbEctor_final)
		:xbEdn(msg,ctx,xbEctor_base),m_timeOut(timeOut)
	{
		traceExcept(ctorMode);
	}

	virtual bool IsToWriteOnLogFile() const 
	{
		return g_xbExceptionEngine.IsToLog(GetFullEname(),false);
	}

	virtual int GetTimeOut() const {return m_timeOut;}
protected:
	int m_timeOut;
private:
	xbDclNoCopyForObject(xbEdnRetry);
public:
	xbDefaultHeapDnewImpl(xbEdnRetry);
};

class xbEXPORT __declspec(uuid("{2253B5B2-07BD-4a96-86FF-D5E376C8DAA7}"))
	xbEdnRetryLater:public xbEdnRetry
{
public:
	static xbEinfoSt s_info;
	virtual const xbEinfoSt *GetInfo() const {return &s_info;}

	virtual LPCSTR GetFullEname() const {return "xbEdnRetryLater";}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbEdnRetryLater);
		return xbEdnRetry::GetInterface(riid,ppInterf);
	}

	xbEdnRetryLater(HRESULT hr,const xbString &msg,int timeOut = -1,xbEctorMode ctorMode = xbEctor_final)
		:xbEdnRetry(hr,msg,timeOut,xbEctor_base)
	{
		traceExcept(ctorMode);
	}
	xbEdnRetryLater(const xbString &msg,int timeOut = -1,xbEctorMode ctorMode = xbEctor_final)
		:xbEdnRetry(msg,timeOut,xbEctor_base)
	{
		traceExcept(ctorMode);
	}
	xbEdnRetryLater(HRESULT hr,const xbString &msg,const xbString &ctx,int timeOut = -1,xbEctorMode ctorMode = xbEctor_final)
		:xbEdnRetry(hr,msg,ctx,timeOut,xbEctor_base)
	{
		traceExcept(ctorMode);
	}
	xbEdnRetryLater(const xbString &msg,const xbString &ctx,int timeOut = -1,xbEctorMode ctorMode = xbEctor_final)
		:xbEdnRetry(msg,ctx,timeOut,xbEctor_base)
	{
		traceExcept(ctorMode);
	}
private:
	xbDclNoCopyForObject(xbEdnRetryLater);
public:
	xbDefaultHeapDnewImpl(xbEdnRetryLater);
};

class xbEXPORT __declspec(uuid("{92976EEB-C75F-4578-965C-0397AAFF15F0}"))
	xbEdnRetrySession:public xbEdnRetry
{
public:
	static xbEinfoSt s_info;
	virtual const xbEinfoSt *GetInfo() const {return &s_info;}

	virtual LPCSTR GetFullEname() const {return "xbEdnRetrySession";}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbEdnRetrySession);
		return xbEdnRetry::GetInterface(riid,ppInterf);
	}

	xbEdnRetrySession(HRESULT hr,const xbString &msg,int timeOut = -1,xbEctorMode ctorMode = xbEctor_final)
		:xbEdnRetry(hr,msg,timeOut,xbEctor_base)
	{
		traceExcept(ctorMode);
	}
	xbEdnRetrySession(const xbString &msg,int timeOut = -1,xbEctorMode ctorMode = xbEctor_final)
		:xbEdnRetry(msg,timeOut,xbEctor_base)
	{
		traceExcept(ctorMode);
	}
	xbEdnRetrySession(HRESULT hr,const xbString &msg,const xbString &ctx,int timeOut = -1,xbEctorMode ctorMode = xbEctor_final)
		:xbEdnRetry(hr,msg,ctx,timeOut,xbEctor_base)
	{
		traceExcept(ctorMode);
	}
	xbEdnRetrySession(const xbString &msg,const xbString &ctx,int timeOut = -1,xbEctorMode ctorMode = xbEctor_final)
		:xbEdnRetry(msg,ctx,timeOut,xbEctor_base)
	{
		traceExcept(ctorMode);
	}
private:
	xbDclNoCopyForObject(xbEdnRetrySession);
public:
	xbDefaultHeapDnewImpl(xbEdnRetrySession);
};


class xbEXPORT __declspec(uuid("{A4BCE3D4-E0E3-4169-A0E5-67FB69F42662}"))
	xbEdnRetryNow:public xbEdnRetry
{
public:
	static xbEinfoSt s_info;
	virtual const xbEinfoSt *GetInfo() const {return &s_info;}

	virtual LPCSTR GetFullEname() const {return "xbEdnRetryNow";}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbEdnRetryNow);
		return xbEdnRetry::GetInterface(riid,ppInterf);
	}

	xbEdnRetryNow(HRESULT hr,const xbString &msg,xbEctorMode ctorMode = xbEctor_final)
		:xbEdnRetry(hr,msg,xbEctor_base)
	{
		traceExcept(ctorMode);
	}
	xbEdnRetryNow(const xbString &msg,xbEctorMode ctorMode = xbEctor_final)
		:xbEdnRetry(msg,xbEctor_base)
	{
		traceExcept(ctorMode);
	}
	xbEdnRetryNow(HRESULT hr,const xbString &msg,const xbString &ctx,xbEctorMode ctorMode = xbEctor_final)
		:xbEdnRetry(hr,msg,ctx,xbEctor_base)
	{
		traceExcept(ctorMode);
	}
	xbEdnRetryNow(const xbString &msg,const xbString &ctx,xbEctorMode ctorMode = xbEctor_final)
		:xbEdnRetry(msg,ctx,xbEctor_base)
	{
		traceExcept(ctorMode);
	}
private:
	xbDclNoCopyForObject(xbEdnRetryNow);
public:
	xbDefaultHeapDnewImpl(xbEdnRetryNow);
};

interface  __declspec(uuid("{5A122C24-40A9-404e-89F8-CD5C8A856269}")) 
	xbEXPORT sIxbDnCenter:public sIxbBase
{
	virtual void LongTaskLock() = 0;
	virtual void LongTaskUnlock() = 0;
};

interface __declspec(uuid("{A64F102D-7D40-43e2-A48D-2ABBF8544F3A}")) 
	xbEXPORT sIxbDnInfo
{
	virtual bool		IsCacheable() const = 0;//impl: return false if cache not supported
	virtual bool		IsLoadable() const = 0;//impl: return false if loadd not implemented
	virtual bool		IsWritable() const = 0;//impl: return false if write not implemented
	virtual const CLSID	&GetClsId() const = 0;
	virtual xbString	GetURL() const = 0;
	virtual int64		GetURLparseType() const = 0;
	virtual bool		GetError(DWORD *pErrCode,xbString *pMsg,xbString *pCtx = NULL) const = 0;
	virtual bool		IsLoaded() const = 0;
	virtual bool		IsWrited() const = 0;
};

enum xbDnOp
{
	xbDnNoop = 0,
	xbDnLoad = 1,
	xbDnWrite = 2
};

interface __declspec(uuid("{D89139A9-E23F-43d3-BD6C-B30434C6BC74}")) 
	xbEXPORT IxbDnObject;
interface  __declspec(uuid("{DF99DB2C-4FC3-471d-ACD1-4B95D11C6EE7}")) 
	xbEXPORT IxbDnProto:public IxbObject
{
	virtual bool	askStopDnOp(IxbDnObject *pObj) = 0;
};

interface sIxbDnSession;
class xbDnData;
interface xbEXPORT IxbDnObject:public IxbObject,public sIxbDnInfo
{
//General methods
	virtual void		CancelDnOp(LPCSTR pReason) = 0;
	virtual void		ClearDnOpStatus() = 0;

	virtual bool		ShouldStopDnOp() const = 0;
//	virtual void		CheckStopDnOp(const xbString &url) const = 0;
	virtual bool		HasError() const = 0;
	virtual void		SetError(xbEbase *pE) = 0;
	virtual void		SetError(DWORD errCode,const xbString &msg,LPCSTR pCtx) = 0;
	virtual void		ClearError() = 0;

	virtual bool		IsWaitingDnOp() const = 0;
	virtual xbDnOp		GetWaitingDnOp() const = 0;

	virtual bool		IsInDnOp() const = 0;
	virtual xbDnOp		GetWorkingDnOp() const = 0;

	virtual int			GetMemSizeForCache() const = 0;

	virtual bool		CanDnOpShowDlg() const = 0;
	virtual bool		CanDnOpLimitSessionCount() const = 0;

	virtual bool		DoDnOp(xbDnData *pDnData) = 0;
	virtual void		onDoDnOpStart(sIxbDnSession *pDnSession,xbThreadEventObject *pEvent) = 0;
	virtual void		onDoDnOpEnd(sIxbDnSession *pDnSession) = 0;

	virtual xbString	GetRequestURL(bool *pbHasReqUrl = NULL) const = 0;
	virtual void		SetRequestURL(const xbString &url) = 0;

	virtual xbString	GetContentURL(bool *pbHasContUrl = NULL) const = 0;
	virtual void		SetContentURL(const xbString &url) = 0;

//Load methods
	virtual void		Load(LPCSTR pszUrl = NULL,xbDnPriority priority = xbDnLow) = 0;
	virtual void		CancelLoad(LPCSTR pReason) = 0;
	virtual bool		IsWaitingLoad() const = 0;

	virtual void		ClearLoadStatus() = 0;
	virtual void		SetLoaded(bool bLoaded,bool bSig = true) = 0;

	virtual bool		LoadFromRes(xbDnData *pDnData,LPCSTR pRes,LPCSTR pType,HMODULE hMod) = 0; //impl: return false if not supported
	virtual LPCSTR		GetDefaultResType() const = 0;
	virtual bool		LoadFromFile(xbDnData *pDnData,const xbString &file) = 0; //impl: return false if not supported

	virtual void		LoadingStart(xbDnData *pDnData,int64 sz) = 0; // sz = downloaded file size, could be -1 if not known
	virtual bool		LoadingAddBuffer(xbDnData *pDnData,const BYTE *pBuf,DWORD cByteBuf) = 0; // impl: return false to stop downloading if enougth data
	virtual void		LoadingEnd(xbDnData *pDnData,bool bOpComplete) = 0; //called when download is finished


//Write methods
	virtual void		Write(LPCSTR pszUrl = NULL,xbDnPriority priority = xbDnFast) = 0;
	virtual void		CancelWrite(LPCSTR pReason) = 0;
	virtual bool		IsWaitingWrite() const = 0;

	virtual void		ClearWriteStatus() = 0;
	virtual void		SetWrited(bool bLoaded,bool bSig = true) = 0;
	virtual void		WriteToStream(xbDnData *pDnData,IxbOutputStream *pStm) = 0;
	virtual void		WritingEnd(xbDnData *pDnData,bool bOpComplete) = 0; //called when upload is finished

//Never use, call only by downloader 
	virtual void		changeUrl(const xbString &url) = 0;
	virtual void		setWaitingDnOp(xbDnOp op) = 0;

	virtual void		setLoaded() = 0;
	virtual void		setWrited() = 0;
	virtual void		setInDnOp(bool bInDnOp) = 0;
	virtual bool		setDnOpRetry(bool bInDlg,xbEadv *pE) = 0;
	virtual bool		setDnOpRetryNow(xbEadv *pE) = 0;
	virtual int			getDnOpRetryTimeOut(bool bInDlg) = 0;
	virtual void		clearDnOpRetryNow() = 0;
	virtual void		setDnOpProto(IxbDnProto *pProto) = 0;
	virtual void		stopDnOp(LPCSTR pReason) = 0;
	virtual xbString	getStopReason() const = 0;
	virtual void		clearDnOpRetry() = 0;

	virtual void		dnCenter_cache(sIxbDnCenter *pDnCenter,int cacheId) = 0;
	virtual bool		dnCenter_tryDel(sIxbDnCenter *pDnCenter,int cacheId) = 0;
	virtual int			dnCenter_getCacheId(sIxbDnCenter *pDnCenter) = 0;

	virtual void		setProtoInfo(const xbString &label,ulong protoMode) = 0;

	virtual xbString	closeReasonLabel(bool bLfAfter = true) const
	{
		xbString ret(getStopReason());
		if (ret.IsEmpty())
			return ret;
		return "(stop reason: "+ret+(bLfAfter?")\n":")");
	}
};

enum xbDnProtoMode
{
	xbDnProtoNetwork = 1,
	xbDnProtoCrypted = 2,
	xbDnProtoUserLogged = 4
};

interface  __declspec(uuid("{9756AA91-848C-499d-BC16-043DD8DCA8DD}")) 
	xbEXPORT sIxbDnPtr:public sIxbPtr,public sIxbDnInfo
{
	virtual IxbDnObject	*CreateObject() = 0;
	virtual IxbDnObject	*GetObject() = 0;
	virtual const IxbDnObject	*GetObject() const = 0;

//Never use, call only by downloader 
	virtual sIxbDnPtr *_getNextWaiting() = 0;
	virtual void _setNextWaiting(sIxbDnPtr *ptr) = 0;
};

interface  __declspec(uuid("{3007C69E-B545-4a83-A10A-DD00DCB253D2}")) 
	xbEXPORT sIxbDnSession:public sIxbBase
{
	virtual bool	ReadUrl(xbDnData *pDnData,IxbDnObject *pObj,
		xbRefPtr<IxbInputStream> *ppStm) = 0; //return true, if op completed -> no need to read bytes (*ppStm in this case is empty)
	virtual bool	WriteUrl(xbDnData *pDnData,IxbDnObject *pObj,
		xbRefPtr<IxbOutputStream> *ppStm) = 0; //return true, if op completed -> no need to read bytes (*ppStm in this case is empty)

	virtual bool	DoDnOp(xbDnData *pCallerData,xbDnOp op,const xbString &url,IxbDnObject *pObj) = 0;

	virtual xbString getCloseReason() const = 0;
	virtual xbString closeReasonLabel(bool bLfAfter = true) const = 0;
	virtual bool isHotPlugCloseEvent() const = 0;

//	virtual bool	ShouldStopDnOp() const = 0;

//	virtual void	CheckStopDnOp(const xbString &url) const = 0;
};

interface  __declspec(uuid("{0708EE2B-2207-42e0-BCE2-724AEFBA12C0}")) 
	xbEXPORT IxbDnProtoStream:public IxbDnProto
{
	virtual void		SetDnData(xbDnData *pDnData) = 0;
	virtual void		askClose(LPCSTR pReason) = 0;
	virtual xbString	getCloseReason() const = 0;
	virtual xbString	closeReasonLabel(bool bLfAfter = true) const
	{
		xbString ret(getCloseReason());
		if (ret.IsEmpty())
			return ret;
		return "(reason: "+ret+(bLfAfter?")\n":")");
	}
	virtual int64	GetReadContentLength() const = 0;
};

interface  __declspec(uuid("{4D094621-B86A-4b22-822C-9E9B59D98B6D}")) 
	xbEXPORT IxbDnProtoRead:public IxbDnProtoStream
{
	virtual bool	GetSerializeRecursiveRead(xbDnData *pDnData,IxbDnObject *pObj) = 0;
};

interface  __declspec(uuid("{25BF84DE-F3FA-40f8-B328-CEDC3C2195A1}")) 
	xbEXPORT IxbDnProtoWrite:public IxbDnProtoStream
{
	virtual void	onWritingStreamEnd(xbDnData *pDnData,bool bCompleted) = 0;
	virtual void	WriteSetContentLocation(const xbString &url) = 0;
	virtual void	WriteSetContentType(const xbString &type) = 0;
	virtual void	WriteSetContentLength(ulong length) = 0;
	virtual void	WriteSetContentRange(ulong start,ulong end,ulong totalLength,LPCSTR pUnit) = 0;
	virtual void	WriteSetBufferLength(long length) = 0;
};

enum xbDnHttpStatusType
{
	xbDnHttpStatusError = -1,
	xbDnHttpStatusWriting = -2,
	xbDnHttpStatusContinue = -3,
	xbDnHttpStatusResponse = 0
};

enum xbDnEncodeType
{
	xbDnEncodeNone = 0,
		xbDnEncodeChunked = 1
};

struct xbEXPORT xbDnTransferStat
{
	uint64 reqStartTi;
	uint64 connectStartTi,connectEndTi;
	uint64 reqSendEndTi;
	uint64 reqReadStartTi;
	uint64 reqEndTi;

	uint64 writeTimeWait,writeByte;
	uint64 readTimeWait,readByte;

	void Reset()
	{
		reqStartTi = 0;
		connectStartTi = connectEndTi = 0;
		reqSendEndTi = 0;
		reqReadStartTi = 0;
		reqEndTi = 0;
		writeTimeWait = writeByte = 0;
		readTimeWait = readByte = 0;
	}
};

enum xbDnProtoCryptMode
{
	xbDnProtoCrypt_None,
	xbDnProtoCrypt_SSL,
	xbDnProtoCrypt_XD
};
interface __declspec(uuid("{2103AB83-827B-478f-9150-0C94B6B4A1B7}")) 
	IxbDnObjectHttpInfo:public IxbObject
{
	virtual void onHttpStatus(xbDnData *pDnData,const xbString &httpVer,int code,const xbString &msg,bool bCacheable,bool *pbErr,xbString *pRedirLocation,bool *pbRedir) = 0;
	virtual void onHttpStatusDataStart(xbDnData *pDnData,xbDnHttpStatusType type) = 0;
	virtual void onHttpStatusData(xbDnData *pDnData,xbDnHttpStatusType type,const void *pDta,ulong DataLg) = 0;
	virtual void onHttpStatusDataEnd(xbDnData *pDnData,xbDnHttpStatusType type) = 0;
	virtual void onHttpContentType(const xbString &msg) = 0;
	virtual void onHttpContentLength(int64 cByteData) = 0;
	virtual bool onHttpContentLocation(const xbString &location) = 0;
	virtual void onHttpContentRangeUnit(const xbString &unit) = 0;
	virtual void onHttpContentRange(ulong start,ulong end,ulong totalLength) = 0;
	virtual void onHttpField(const xbString &name,const xbString &value) = 0;

	virtual void onHttpRequestInfo(IxbObject *pSession,xbString *pHttpOrder,xbString *pUsrAgent,ulong *pRespTimeOut,bool bWriteHdr) = 0;
	virtual bool onHttpGetCookies(xbDnProtoCryptMode protoCrypt,const xbString &server,const xbString &port,const xbString &path,xbString *pCookies) = 0;
	virtual bool onHttpSetCookies(xbDnProtoCryptMode protoCrypt,const xbString &server,const xbString &port,const xbString &path,const xbString &cookies) = 0;
	virtual void onHttpRequestGetContent(xbString *pContentType,int64 *pContentLength,xbString *pContentLocation,xbData *pContentDta,bool *pbKeepAlive,xbDnEncodeType *pEncodeMode,bool bWriteHdr,xbArray<xbString> *pSendEncoding,xbArray<xbString> *pWantedEncoding) = 0;
	virtual bool onHttpRequestSend(IxbObject *pSession,xbString *pRequest,bool bWriteHdr) = 0; //return false if not implemented or to add '\n' to request string end

	virtual bool onHttpLogOnRequired(xbDnData *pDnData,bool bProxyAuth,
		const xbString &srv,const xbString &port,const xbString &path,LPCSTR pUserDom,
		LPCSTR pAuthMeth,const xbString &realm,xbString *pUserName,xbString *pUserPwd,
		bool *pbUserSavePwd,bool *pbStop,bool *pbUserFeedBack) = 0;
	virtual bool onHttpLogOnFeedBack(bool bProxyAuth,const xbString &srv,
		const xbString &port,const xbString &path,LPCSTR pUserDom,LPCSTR pAuthMeth,
		const xbString &userName,const xbString &userPwd,bool bUserSavePwd) = 0;
	virtual bool onHttpLogOnRetrieve(bool bProxyAuth,const xbString &srv,
		const xbString &port,const xbString &path,LPCSTR pUserDom,LPCSTR pAuthMeth,
		xbString *pUserName,xbString *pUserPwd,bool *pbUserSavePwd) = 0;
	virtual int onHttpGetCancelTimeOut(bool bProxyAuth,const xbString &srv,
		const xbString &port,const xbString &path,LPCSTR pUserDom,LPCSTR pAuthMeth) = 0;
	virtual void onHttpConnectInfo(IxbObject *pSession,xbString *pPath,ulong *pConnectTimeOut,bool *pbWantStat) = 0;
	virtual void onHttpTransferStat(const xbDnTransferStat &stat) = 0;
	virtual void onHttpRequestReadPost(IxbObject *pSession,IxbOutputStream *pStm) = 0;
};

class xbEXPORT __declspec(uuid("{553C2779-1E11-489e-8CB1-CE92A6D7C7F4}")) 
	xbDnData:public xbCtxBase
{
public:
	xbDnData(xbDnData *pPrev,xbDnOp op,const xbString &url,IxbDnObject *pObj)
		:m_pCenter(pPrev->m_pCenter),m_pSession(pPrev->m_pSession),
		m_pPrev(pPrev),m_Url(url),m_pObj(pObj),m_op(op)
	{
		m_pData = NULL;
		m_bPlugOpen = m_bPlugErr = false;
		AddToThreadCtx();
		xbRdbgAssert(m_pThEv != NULL);
	}

	xbDnData(xbDnOp op,const xbString &url,IxbDnObject *pObj)
		:m_pCenter(NULL),m_pSession(NULL),
		m_pPrev(NULL),m_Url(url),m_pObj(pObj),m_op(op)
	{
		m_pData = NULL;
		m_bPlugOpen = m_bPlugErr = false;
		AddToThreadCtx();
		if (!m_pThCtxObjOld || !xbCastIn(m_pThCtxObjOld,(xbDnData**)&m_pPrev))
			xbThrow xbElib("Unexpected call to xbDnData");
		m_pCenter = m_pPrev->m_pCenter;
		m_pSession = m_pPrev->m_pSession;
		xbRdbgAssert(m_pThEv != NULL);
	}

	xbDnData(sIxbDnCenter *pCenter,sIxbDnSession *pSession)
		:m_pCenter(pCenter),m_pSession(pSession),m_pObj(NULL),m_pPrev(NULL),m_op(xbDnNoop)
	{
		m_pData = NULL;
		m_bPlugOpen = m_bPlugErr = false;
	}
	~xbDnData()
	{
		eProtectTrace(UrlClose("dnData destruction"));
		xbRdbgAssert(m_pData == NULL);
		eProtectTrace(RemoveFromThreadCtx());
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbDnData);
		return xbBase::GetInterface(riid,ppInterf);
	}

	bool	IsAlreadyInDnOp() const
	{
		if (!m_pPrev) return false;
		return m_pPrev->IsInDnOp(m_op,m_Url);
	}
	bool	IsInDnOp(xbDnOp op,const xbString &url) const
	{
		if (url == m_Url && op == m_op) return true;
		if (!m_pPrev) return false;
		return m_pPrev->IsInDnOp(op,url);
	}
	void	CheckDnOp() const
	{
		if (!IsAlreadyInDnOp()) 
		{
			CheckStop();
			return;
		}
		xbThrow xbEdnUser("Recursive work on url = '"+m_Url+"' cause infinite loop ...","xbDnData::checkDnOp()");
	}
	void CheckStop() const;
	bool SubDnOp(xbDnOp op,const xbString &url,IxbDnObject *pObj);
	void AddDnTask(xbDnOp op,const xbString &url,IxbDnObject *pObj);
	bool GetDnTask(xbDnOp *pop,xbString *pUrl,xbRefPtr<IxbDnObject> *ppObj);
	bool HasDnTask();

	bool UrlOpen(); //return true, if op completed -> no need to read bytes
	void UrlClose(LPCSTR pReason);
	ulong UrlRead(void *_pDta,ulong DataLg,bool bDataLgRequired = false);
	ulong UrlWrite(void *pDta,ulong DataLg,bool bDataLgRequired = true);
	int64 UrlGetSize() const;
	bool UrlSetSize(int64 sz);
	void UrlGetReadStm(xbRefPtr<IxbInputStream> *ppStm);
	void UrlGetWriteStm(xbRefPtr<IxbOutputStream> *ppStm);
	void UrlWritingEnd(bool bCompleted);

	virtual xbString getCloseReason() const;

	virtual xbString	closeReasonLabel(bool bLfAfter = true) const
	{
		xbString ret(getCloseReason());
		if (ret.IsEmpty())
			return ret;
		return "(reason: "+ret+(bLfAfter?")\n":")");
	}
public:
	const xbString					m_Url;
	const xbDnOp					m_op;
	void*							m_pData;
	IxbDnObject* const				m_pObj;
	xbDnData* const					m_pPrev;
	sIxbDnCenter*					m_pCenter;
	sIxbDnSession*					m_pSession;
protected:
	void plugStartRead();

	xbString						m_closeReason;
	xbRefPtr<IxbInputStream>		m_piStm;
	xbRefPtr<IxbOutputStream>		m_poStm;
	xbMemoryStream					m_PlugStm;
	bool							m_bPlugOpen,m_bPlugErr;

	struct DnTask
	{
		xbDnOp						m_op;
		xbString					m_url;
		xbRefPtr<IxbDnObject>		m_obj;
		DnTask(xbDnOp op,const xbString &url,IxbDnObject *pObj)
			:m_op(op),m_url(url),m_obj(pObj)
		{
		}
		DnTask()
		{
		}
	};

	xbArray<DnTask>					m_arrDnTask;
private:
	xbDclNoNewForObject(xbDnData);
	xbDclNoCopyForObject(xbDnData);
};

xbEXPORT bool xbDnAsk(sIxbDnPtr *pPtr,xbDnOp op,xbDnPriority priority = xbDnLow,bool bWaitProcessMsg = true,bool bCacheableOnly = true);
xbEXPORT bool xbDnAsk(IxbDnObject *pObj,xbDnOp op,LPCSTR pszUrl,xbDnPriority priority = xbDnLow,bool bWaitProcessMsg = true);
xbEXPORT bool xbDnCancel(IxbDnObject *pObj,LPCSTR pReason,xbDnOp op,bool bWaitProcessMsg = true);
xbEXPORT bool xbDnWait(IxbDnObject *pObj,xbDnOp op,int timeOut = xbDNWAIT_DFLTTIMEOUT,bool bWaitProcessMsg = true);
xbEXPORT bool xbDnCacheUpdate(IxbDnObject *pObj,bool bAddIfNotInCache);
xbEXPORT bool xbDnCacheRemove(IxbDnObject *pObj);

xbEXPORT bool xbDnCacheRetrieve(const CLSID &clsid,const xbString &url,int64 urlParseType,xbRefPtr<IxbDnObject> *ppObj,bool bCacheableOnly = true);

xbEXPORT int xbDnCacheRetrieve(const CLSID &clsid,LPCSTR pszUrl,
		int64 urlParseType,xbArray< xbRefPtr<IxbDnObject> > *pArrObj,
		bool bCacheableOnly = true);
xbEXPORT int xbDnCacheRemove(const CLSID &clsid,LPCSTR pszUrl = NULL,
		int64 urlParseType = -1,bool bCacheableOnly = false);


class xbDnLongTaskLock
{
public:
	xbDnLongTaskLock()
	{
		m_pObj = NULL;
	}
	xbDnLongTaskLock(sIxbDnCenter *pObj)
	{
		m_pObj = NULL;
		if (pObj) Lock(pObj);
	}
	xbDnLongTaskLock(xbDnData *pObj)
	{
		m_pObj = NULL;
		if (pObj) 
			Lock(pObj->m_pCenter);
	}
	~xbDnLongTaskLock()
	{
		eProtect(Unlock());
	}
	void Lock(sIxbDnCenter *pObj)
	{
		if (m_pObj) Unlock();
		pObj->LongTaskLock();
		m_pObj = pObj;
	}
	void Lock(xbDnData *pObj)
	{
		if (m_pObj) Unlock();
		pObj->m_pCenter->LongTaskLock();
		m_pObj = pObj->m_pCenter;
	}
	void Unlock()
	{
		if (!m_pObj) return;
		sIxbDnCenter	*pObj = m_pObj;
		m_pObj = NULL;
		pObj->LongTaskUnlock();
	}
	bool IsLocked() const {return m_pObj != NULL;}
protected:
	sIxbDnCenter	*m_pObj;
	xbDclNoCopyForObject(xbDnLongTaskLock);
};


#include "xbStat.h"

xbEXPORT extern xbStatPointFolder g_xbStatDnCenter;
xbEXPORT extern xbStatPointFolder g_xbStatDnTraffic;

interface  __declspec(uuid("{06EB6F7B-5877-4462-A1D9-528FD8E7FF80}")) 
	xbEXPORT IxbDnDlgBoxLogin:public IxbObject
{
	virtual void Init(const xbString &loginType,const xbString &loginMethod,const xbString &srv,const xbString &realm,
		const xbString &srvMsg,
		const xbString &lastUserName,
		const xbString &lastUserPwd,
		LPCSTR lastUserDom,
		bool bSavePwd) = 0;

	virtual xbMBretType ShowModal() = 0;

	virtual void GetLoginInfo(xbString &userName,xbString &userPwd,xbString *pUserDom,bool &bSavePwd) = 0;
};


#endif
