#ifndef _xbDNOBJECT_
#define _xbDNOBJECT_
/*<<<***************************************************************************
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: xbDnObject
#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 _xbDNITF_
#	include "xbDnItf.h"
#endif

template<class base> class xbTdnObject:public base,public IxbDnObject
{
public:
	xbTdnObject(const xbString &url,int64 urlParseType)
	{
		m_Url = url;
		m_Url.OwnData();
		m_UrlParseType = urlParseType;

		m_errCode = S_OK;
		m_bLoaded = false;
		m_bWrited = false;

		m_workingOp = m_waitingOp = xbDnNoop;
		m_bStopDnOp = false;

		m_bDnCenterCanDel = false;
		m_pDnCenter = NULL;
		m_dnCenterCacheId = 0;

		m_dnOpRetryCount = 0;
		m_dnOpRetryNowCount = 0;

	//default: m_pSectData is same than m_pSectPtr
		m_pSectData = m_pSectPtr;
	}

	xbImplObject();

	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(IxbDnObject);
		xbImplInterface(sIxbDnInfo);
		return base::GetInterface(riid,ppInterf);
	}

//sIxbDnInfo methods
	virtual bool		IsCacheable() const {return true;}//impl: return false if cache not supported
	virtual bool		IsLoadable() const {return true;}//impl: return false if load not implemented
	virtual bool		IsWritable() const {return false;}//impl: return false if write not implemented
	virtual xbString	GetURL() const
	{
		xbSectLock lck(m_pSectData);
		xbString url(m_Url);
		url.OwnData();
		return url;
	}
	virtual xbString	GetRequestURL(bool *pbHasReqUrl = NULL) const
	{
		xbSectLock lck(m_pSectData);
		xbString url(m_requestUrl.IsEmpty()?m_Url:m_requestUrl);
		if (pbHasReqUrl)
			*pbHasReqUrl = m_requestUrl.IsValid();
		url.OwnData();
		return url;
	}
	virtual void		SetRequestURL(const xbString &url)
	{
		xbSectLock lck(m_pSectData);
		m_requestUrl = url;
		m_requestUrl.OwnData();
	}
	virtual xbString	GetContentURL(bool *pbHasContUrl = NULL) const
	{
		xbSectLock lck(m_pSectData);
		xbString url;
		if (m_contentUrl.IsValid()) 
		{
			url = m_contentUrl;
			if (pbHasContUrl)
				*pbHasContUrl = true;
		}
		else 
		{
			if (pbHasContUrl)
				*pbHasContUrl = false;
			if (m_requestUrl.IsValid())
			{
				url = m_requestUrl;
			}
			else
			{
				url = m_Url;
			}
		}
		url.OwnData();
		return url;
	}
	virtual void		SetContentURL(const xbString &url)
	{
		xbSectLock lck(m_pSectData);
		m_contentUrl = url;
		m_contentUrl.OwnData();
	}

	virtual int64		GetURLparseType() const
	{
		xbSectLock lck(m_pSectData);
		return m_UrlParseType;
	}
/*	virtual void		SetHTTPcookies(const xbString &cookies)
	{
		xbSectLock lck(m_pSectData);
		m_cookies = cookies;
		m_cookies.OwnData();
	}
	virtual xbString	GetHTTPcookies() const
	{
		xbSectLock lck(m_pSectData);
		xbString cookies(m_cookies);
		cookies.OwnData();
		return cookies;
	}*/

	virtual bool		GetError(DWORD *pErrCode,xbString *pMsg,xbString *pCtx) const
	{
		xbSectLock lck(m_pSectData);
		if (pErrCode)
			*pErrCode = m_errCode;
		if (pMsg)
		{
			*pMsg = m_errMsg;
			pMsg->OwnData();
		}
		if (pCtx)
		{
			*pCtx = m_errCtx;
			pCtx->OwnData();
		}
		return m_errCode != S_OK;
	}
	virtual bool		IsLoaded() const
	{
		xbSectLock lck(m_pSectData);
		return m_bLoaded;
	}
	virtual bool		IsWrited() const
	{
		xbSectLock lck(m_pSectData);
		return m_bWrited;
	}
//sIxbDnInfo methods to overload
	virtual const CLSID	&GetClsId() const = 0;


//IxbDnObject methods
//General methods
	virtual void		ClearDnOpStatus()
	{
		xbSectLock lck(m_pSectData);
		m_errCode = S_OK;
		m_errMsg.Empty();
		m_errCtx.Empty();
		m_bLoaded = false;
		m_bWrited = false;
	}
	virtual bool		ShouldStopDnOp() const
	{
//		xbSectLock lck(m_pSectData);
		if (m_bStopDnOp || m_bDestruction)
			return true;
		if (m_dnEventPtr.IsEmpty())
			return false;
		xbSectLock lck(m_pSectData);
		return m_dnEventPtr.ProcessOrTaskToStop();
	}
/*	virtual void		CheckStopDnOp(const xbString &url) const
	{
		xbSectLock lck(m_pSectData);
		if (m_bDestruction)
		{
			lck.Unlock();
			xbThrow xbEdnUser(E_ABORT,"Task cancelled...",closeReasonLabel()+"Url:"+url+xbEdebug("xbTdnObject::CheckStopDnOp(m_bDestruction = true)"));
		}
		if (m_bStopDnOp)
		{
			lck.Unlock();
			xbThrow xbEdnUser(E_ABORT,"Task cancelled...",closeReasonLabel()+"Url:"+url+xbEdebug("\nxbTdnObject::CheckStopDnOp(m_bStopDnOp = true)"));
		}
	}*/
	virtual bool		HasError() const
	{
		xbSectLock lck(m_pSectData);
		return m_errCode != S_OK;
	}
	virtual void		ClearError()
	{
		xbSectLock lck(m_pSectData);
		m_errCode = S_OK;
		m_errMsg.Empty();
		m_errCtx.Empty();
	}
	virtual void		SetError(xbEbase *pE)
	{
		xbString msg(xbGetMsg("raw",pE));
		xbString ctx(xbGetCtx("raw",pE));
		int		code = xbGetHR(pE);
		SetError(code,msg,ctx);
	}
	virtual void		SetError(DWORD errCode,const xbString &msg,LPCSTR pCtx)
	{
		xbSectLock lck(m_pSectData);
		m_errCode = errCode;
		m_errMsg = msg;
		m_errMsg.OwnData();
		if (pCtx)
			m_errCtx = pCtx;
		else
			m_errCtx.Empty();
	}
	virtual void		CancelDnOp(LPCSTR pReason)
	{
		xbDnCancel(this,pReason,xbDnNoop);
	}
	virtual bool		IsWaitingDnOp() const
	{
		xbSectLock lck(m_pSectData);
		return m_waitingOp != xbDnNoop;
	}
	virtual xbDnOp		GetWaitingDnOp() const
	{
		xbSectLock lck(m_pSectData);
		return m_waitingOp;
	}
	virtual bool		IsInDnOp() const
	{
		xbSectLock lck(m_pSectData);
		return m_workingOp != xbDnNoop;
	}
	virtual xbDnOp		GetWorkingDnOp() const
	{
		xbSectLock lck(m_pSectData);
		return m_workingOp;
	}
	virtual bool		CanDnOpShowDlg() const
	{
		return true;
	}
	virtual bool		CanDnOpLimitSessionCount() const
	{
		return true;
	}

//General methods to override
	virtual int			GetMemSizeForCache() const = 0;

	virtual bool		DoDnOp(xbDnData *pData)
	{
		return false;
	}
	virtual void		onDoDnOpStart(sIxbDnSession *pDnSession,xbThreadEventObject *pEvent)
	{
		xbSectLock lck(m_pSectData);
		m_dnEventPtr = pEvent;
	}
	virtual void		onDoDnOpEnd(sIxbDnSession *pDnSession)
	{
		xbSectLock lck(m_pSectData);
		m_dnEventPtr.Empty();
	}

//Load methods
	virtual void		Load(LPCSTR pszUrl = NULL,xbDnPriority priority = xbDnLow)
	{
		xbDnAsk(this,xbDnLoad,pszUrl,priority);
	}
	virtual void		CancelLoad(LPCSTR pReason)
	{
		xbDnCancel(this,pReason,xbDnLoad);
	}
	virtual bool		IsWaitingLoad() const
	{
		xbSectLock lck(m_pSectData);
		return m_waitingOp == xbDnLoad;
	}

	virtual void		ClearLoadStatus()
	{
		xbSectLock lck(m_pSectData);
		m_errCode = S_OK;
		m_errMsg.Empty();
		m_errCtx.Empty();
		m_bLoaded = false;
	}
	virtual void		SetLoaded(bool bLoaded,bool bSig = true)
	{
		if (bLoaded) setLoaded();
		else ClearLoadStatus();
		if (bSig) 
			SignalPtr(HasError()?xbPTRSIG_LOADEDERROR:xbPTRSIG_LOADEDOK);
	}

//Load methods to override
	virtual bool		LoadFromRes(xbDnData *pData,LPCSTR pRes,LPCSTR pType,HMODULE hMod) = 0; //impl: return false if not supported
	virtual LPCSTR		GetDefaultResType() const {return (LPCSTR)RT_RCDATA;}
	virtual bool		LoadFromFile(xbDnData *pData,const xbString &file) = 0; //impl: return false if not supported

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

//Write methods
	virtual void		Write(LPCSTR pszUrl = NULL,xbDnPriority priority = xbDnFast)
	{
		xbDnAsk(this,xbDnWrite,pszUrl,priority);
	}
	virtual void		CancelWrite(LPCSTR pReason)
	{
		xbDnCancel(this,pReason,xbDnWrite);
	}
	virtual bool		IsWaitingWrite() const
	{
		xbSectLock lck(m_pSectData);
		return m_waitingOp == xbDnWrite;
	}

	virtual void		ClearWriteStatus()
	{
		xbSectLock lck(m_pSectData);
		m_errCode = S_OK;
		m_errMsg.Empty();
		m_errCtx.Empty();
		m_bWrited = false;
	}
	virtual void		SetWrited(bool bLoaded,bool bSig = true)
	{
		if (bLoaded) setWrited();
		else ClearWriteStatus();
		if (bSig) 
			SignalPtr(HasError()?xbPTRSIG_WRITEDERROR:xbPTRSIG_WRITEDOK);
	}

//Write methods to override
	virtual void		WriteToStream(xbDnData *pData,IxbOutputStream *pStm)
	{
		xbSectLock lck(m_pSectData);
		xbThrow xbEsys(E_NOTIMPL,"xbTdnObject("+m_Url+")::WriteToStream() not implemented");
	}
	virtual void		WritingEnd(xbDnData *pData,bool bOpComplete)
	{
	}

protected:
//IxbDnObject protected methods
	virtual void changeUrl(const xbString &url)
	{
		xbSectLock lck(m_pSectData);
		m_Url = url;
		m_Url.OwnData();
		m_requestUrl.Empty();
		m_contentUrl.Empty();
	}
	virtual void setInDnOp(bool bInDnOp)
	{
		xbRefPtr<IxbDnProto> prProto;
		xbSectLock lck(m_pSectData);
		xbAssert((bInDnOp && m_workingOp == xbDnNoop)
			|| (!bInDnOp /*&& m_workingOp != xbDnNoop*/));
		m_bStopDnOp = false;
		if (bInDnOp)
		{
			m_workingOp = m_waitingOp;
			m_waitingOp = xbDnNoop;
			if (!xbMustBe(m_prDnOpProto.IsEmpty()))
				prProto = m_prDnOpProto;
			m_prDnOpProto.Empty();
		}
		else
		{
			m_dnOpRetryCount = 0;
			m_dnOpRetryNowCount = 0;

			m_workingOp = xbDnNoop;
			prProto = m_prDnOpProto;
			m_prDnOpProto.Empty();
		}
//		xbAssert(m_waitingOp == xbDnNoop);
	}
	virtual bool setDnOpRetry(bool bInDlg,xbEadv *pE)
	{
		xbSectLock lck(m_pSectData);
		xbAssert(m_workingOp != xbDnNoop);
		xbAssert(m_waitingOp == xbDnNoop);
		if (m_workingOp == xbDnNoop || m_waitingOp != xbDnNoop
			|| m_bStopDnOp
			|| (!bInDlg && m_dnOpRetryCount > 308))
		{
//			m_bStopDnOp = false;
			m_workingOp = xbDnNoop;
			m_dnOpRetryCount = 0;
			return false;
		}
		if (bInDlg)
			m_dnOpRetryCount = 1;
		else
			m_dnOpRetryCount++;
		m_dnOpRetryNowCount = 0;
		m_waitingOp = m_workingOp;
		m_workingOp = xbDnNoop;
		return true;
	}
	virtual bool setDnOpRetryNow(xbEadv *pE)
	{
		xbSectLock lck(m_pSectData);
		xbAssert(m_workingOp != xbDnNoop);
		xbAssert(m_waitingOp == xbDnNoop);
		if (m_workingOp == xbDnNoop || m_waitingOp != xbDnNoop
			|| m_bStopDnOp
			|| m_dnOpRetryNowCount > 4)
		{
			m_dnOpRetryCount = 0;
			return false;
		}

		m_dnOpRetryNowCount++;
		m_dnOpRetryCount = 0;
		return true;
	}
	virtual void clearDnOpRetryNow()
	{
		xbSectLock lck(m_pSectData);
		xbAssert(m_workingOp != xbDnNoop);
		xbAssert(m_waitingOp == xbDnNoop);
		m_dnOpRetryNowCount = 0;
	}
	virtual void clearDnOpRetry()
	{
		xbSectLock lck(m_pSectData);
		xbAssert(m_workingOp != xbDnNoop);
		xbAssert(m_waitingOp == xbDnNoop);
		m_dnOpRetryCount = 0;
	}
	virtual int	getDnOpRetryTimeOut(bool bInDlg)
	{
		if (bInDlg)
			return 1000;
		xbSectLock lck(m_pSectData);
		if (m_dnOpRetryCount <= 2)
			return 10; //10ms
		if (m_dnOpRetryCount <= 10)
			return 200; //200ms
		if (m_dnOpRetryCount <= 20) //20
			return 500; //10s
		if (m_dnOpRetryCount <= 140) //120
			return 1000; //2min
		if (m_dnOpRetryCount <= 260)
			return 2000; //4min
//		if (m_dnOpRetryCount <= 308)
			return 5000; //3min 20s
//		return -1; //temps maxi, approx 4min 

	}
	virtual void setDnOpProto(IxbDnProto *pProto)
	{
		xbRefPtr<IxbDnProto> prProto;
		xbSectLock lck(m_pSectData);
		prProto = m_prDnOpProto;
		if (pProto) 
			m_prDnOpProto = pProto;
		else
			m_prDnOpProto.Empty();
	}
	virtual void stopDnOp(LPCSTR pReason)
	{
		xbRefPtr<IxbDnProto> prProto;
		{
			xbSectLock lck(m_pSectData);
			if (pReason && (m_bStopDnOp || m_stopReason.IsEmpty()))
				m_stopReason = pReason;
			m_bStopDnOp = true;
			prProto = m_prDnOpProto;
			if (m_dnEventPtr.IsValid())
				m_dnEventPtr.StopTaskProcess();
		}
		if (prProto.IsValid())
			prProto->askStopDnOp(this);
	}
	virtual xbString	getStopReason() const
	{
		xbSectLock lck(m_pSectData);
		xbString ret(m_stopReason);
		ret.OwnData();
		return ret;
	}
	virtual void setLoaded()
	{
		xbSectLock lck(m_pSectData);
		m_bLoaded = true;
	}
	virtual void setWrited()
	{
		xbSectLock lck(m_pSectData);
		m_bWrited = true;
	}

	virtual void		setWaitingDnOp(xbDnOp op)
	{
		xbSectLock lck(m_pSectData);
		m_waitingOp = op;
	}
	virtual bool		IsInDnOpRetry() const
	{
		xbSectLock lck(m_pSectData);
		if (m_workingOp == xbDnNoop) return false;
		return m_dnOpRetryCount > 0 || m_dnOpRetryNowCount > 0;
	}
//others protected methods
	virtual ~xbTdnObject()
	{
		xbAssert(m_waitingOp == xbDnNoop);
		xbAssert(!m_pDnCenter);
	}
	virtual void	removeAllPtr(xbSectLock *pLck)
	{
		//pLck->Unlock();
		{
			xbSectLock	lck(m_pSectData);
			m_waitingOp = xbDnNoop;
		}
		base::removeAllPtr(pLck);
	}
	virtual ULONG	release()
	{
		long l = ::xbInterlockDecrement32(&m_nRefCnt);
		if (l == 0)
		{
			m_bDestruction = true;

			//release in two pass
			//In case of addref during removeAllPtr operation (...)
			// -> if xbObsPtr have a pointer on this object
			// & GetPtr is called on it.
			::xbInterlockIncrement32(&m_nRefCnt); 
			
			eProtect(onBeforeDestruction(false));

			xbSectLock	lck(m_pSectPtr);
			eProtectBegin();
			{
				m_bAddPtrAllowed = false;
				removeAllPtr(&lck);
				lck.Unlock();
			}
			eProtectEnd();
			eProtect(onDestruction(false));
			
			lck.Lock(m_pSectPtr);

			l = ::xbInterlockDecrement32(&m_nRefCnt);
			if (l == 0)
			{
				if (m_pDnCenter)
				{
					m_bDnCenterCanDel = true;
					return l;
				}
				
				xbAssert(m_pFirstPtr == NULL);

				lck.Unlock();

				m_nRefCnt = 1;
				delete this;
			}
		}
		return l;
	}

	virtual void		dnCenter_cache(sIxbDnCenter *pDnCenter,int cacheId)
	{
		xbSectLock	lck(m_pSectPtr);
		if (m_pDnCenter != NULL && pDnCenter != NULL && m_pDnCenter != pDnCenter)
			xbThrow xbEsys("dnCenter_cache(): object set to another download center");
		xbAssert((m_pDnCenter == NULL && m_dnCenterCacheId == 0)
			||(pDnCenter == NULL && cacheId == 0)
			||(pDnCenter != NULL && m_pDnCenter != NULL && m_dnCenterCacheId == cacheId));
		if (m_pDnCenter != NULL && pDnCenter != NULL && m_pDnCenter == pDnCenter
			&& m_dnCenterCacheId != cacheId)
			xbThrow xbEsys("dnCenter_cache(): bad cache id (expected="+xbString(cacheId)+",obj="+xbString(m_dnCenterCacheId)+")");
		m_bDnCenterCanDel = false;
		m_pDnCenter = pDnCenter;
		m_dnCenterCacheId = cacheId;
		if (m_pDnCenter)
		{
			m_bDestruction = false;
			m_bAddPtrAllowed = true;
		}
	}
	virtual bool	dnCenter_tryDel(sIxbDnCenter *pDnCenter,int cacheId)
	{
		xbSectLock	lck(m_pSectPtr);
		if (m_pDnCenter != pDnCenter)
			xbThrow xbEsys("dnCenter_tryDel(): object set to another download center");
		if (m_dnCenterCacheId != cacheId)
			xbThrow xbEsys("dnCenter_tryDel(): bad cache id (expected="+xbString(cacheId)+",obj="+xbString(m_dnCenterCacheId)+")");
		if (!m_bDnCenterCanDel) return false;
		eProtectBegin();
		m_bDnCenterCanDel = false;
		m_pDnCenter = NULL;
		m_dnCenterCacheId = 0;
		addRef();
		lck.Unlock();
		xbMustBe(release() == 0);
		eProtectEndTrace();
		return true;
	}
	virtual int			dnCenter_getCacheId(sIxbDnCenter *pDnCenter)
	{
		xbSectLock	lck(m_pSectPtr);
		if (m_pDnCenter && m_pDnCenter != pDnCenter)
			xbThrow xbEsys("dnCenter_getCacheId(): object set to another download center");
		return m_dnCenterCacheId;
	}
	virtual void		setProtoInfo(const xbString &label,ulong protoMode)
	{
	}
protected:
	//default: m_pSectData is same than m_pSectPtr
	//protected by m_pSectData
	mutable xbSectShare	*m_pSectData;
	xbString					m_Url;
	__int64						m_UrlParseType;

	xbString					m_requestUrl,m_contentUrl; //,m_cookies;
	
	DWORD						m_errCode;
	xbString					m_errMsg,m_errCtx;
	bool						m_bLoaded,m_bWrited;
	
	xbDnOp						m_waitingOp,m_workingOp;
	bool						m_bStopDnOp;
	xbString					m_stopReason;

	int							m_dnOpRetryCount;
	int							m_dnOpRetryNowCount;

	xbRefPtr<IxbDnProto>		m_prDnOpProto;
	xbThreadEventPtr			m_dnEventPtr;

	//protected by m_pSectPtr
	bool						m_bDnCenterCanDel;
	sIxbDnCenter				*m_pDnCenter;
	int							m_dnCenterCacheId;
};

//typedef xbTdnObject<xbObject> xbEXPORT xbDnObject;
//typedef xbTdnObject<xbObjectBase> xbEXPORT xbDnObjectBase;

class xbEXPORT xbDnObject:public xbTdnObject<xbObject>
{
public:
	xbDnObject(const xbString &url,int64 urlParseType)
		:xbTdnObject<xbObject>(url,urlParseType)
	{
	}
};

class xbEXPORT xbDnObjectBase:public xbTdnObject<xbObjectBase>
{
public:
	xbDnObjectBase(const xbString &url,int64 urlParseType)
		:xbTdnObject<xbObjectBase>(url,urlParseType)
	{
	}
};

template <class object,class iobject = object> class xbDnPtr
	:public xbPtr<iobject>,public sIxbDnPtr
{
public:
	xbDnPtr()
	{
		m_UrlParseType = 0;
		m_pNextWaiting = NULL;
	}
	xbDnPtr(const xbString &url,__int64 urlParseType = 0)
	{
		m_UrlParseType = urlParseType;
		m_Url = url;
		m_pNextWaiting = NULL;
	}
	xbDnPtr(const xbDnPtr<object,iobject> &ptr)
		:xbPtr<iobject>(ptr)
	{
		m_UrlParseType = ptr.m_UrlParseType;
		m_Url = ptr.m_Url;
//		m_cookies = ptr.m_cookies;
		m_pNextWaiting = NULL;
	}
	void operator=(const xbDnPtr<object,iobject> &ptr)
	{
		xbPtr<iobject>::operator=(ptr);
		m_UrlParseType = ptr.m_UrlParseType;
		m_Url = ptr.m_Url;
//		m_cookies = ptr.m_cookies;
	}
	bool SetURL(const xbString &url,__int64 urlParseType = 0)
	{
		if (url == m_Url && urlParseType == m_UrlParseType) return false;
		Empty();
		m_UrlParseType = urlParseType;
		m_Url = url;
		return true;
	}
/*	virtual bool		SetHTTPcookies(const xbString &cookies)
	{
		if (cookies == m_cookies) return false;
		Empty();
		m_cookies = cookies;
		return true;
	}
	virtual xbString	GetHTTPcookies() const
	{
		return m_cookies;
	}*/
	bool AskLoad(xbDnPriority priority = xbDnLow)
	{
		if (m_pObj) return false;
		if (m_Url.IsEmpty()) return false; //xbThrow TExcept("xbDnPtr()::AskLoad() : nothing to load");
		return xbDnAsk(this,xbDnLoad,priority);
	}
	bool WaitLoaded(int timeout = xbDNWAIT_DFLTTIMEOUT)
	{
		if (!m_pObj) return false;
		return xbDnWait(m_pObj,xbDnLoad,timeout);
	}
	bool WaitLoad(int timeout = xbDNWAIT_DFLTTIMEOUT,xbDnPriority priority = xbDnFast)
	{
		if (!m_pObj) return false;
		if (m_Url.IsEmpty()) return false; //xbThrow TExcept("xbDnPtr()::AskLoad() : nothing to load");
//		xbDnAsk(this,xbDnLoad,priority); done in xbDnWait
		return xbDnWait(m_pObj,xbDnLoad,timeout);
	}
//methods of sIxbPtr
	xbImplPtr(xbPtr<iobject>);

	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(sIxbDnPtr);
		xbImplInterface(sIxbDnInfo);
		
		return xbPtr<iobject>::GetInterface(riid,ppInterf);
	}

//methods of sIxbDnPtr
public:
	virtual IxbDnObject *CreateObject()
	{
		object *ptr = xbDnew object(m_Url,m_UrlParseType);
		try
		{
			ptr->Create();
//			if (m_cookies.IsValid())
//				ptr->SetHTTPcookies(m_cookies);
			IxbDnObject *pObj;
			if (!ptr->GetInterface(__uuidof(IxbDnObject),(void**)&pObj))
				xbThrow xbEsys(E_NOINTERFACE,"xbDnPtr::CreateObject() : object doesn't have interface IxbDnObject");
			pObj->AddPtr((sIxbDnPtr*)this,xbOp_Required);
		}
		catch(...)
		{
			ptr->Release();
			throw;
		}
		ptr->Release();
		return m_pObj;
	}
	virtual IxbDnObject *GetObject()
	{
		return m_pObj;
	}
	virtual const IxbDnObject	*GetObject() const
	{
		return m_pObj;
	}
//methods of sIxbDnInfo
public:
	virtual bool		IsCacheable() const
	{
		return true;
	}
	virtual bool		IsLoadable() const
	{
		return true;
	}
	virtual bool		IsWritable() const
	{
		return false;
	}
	virtual const CLSID	&GetClsId() const
	{
		return __uuidof(object);
	}
	virtual xbString	GetURL() const
	{
		return m_Url;
	}
	virtual __int64			GetURLparseType() const
	{
		return m_UrlParseType;
	}
	virtual bool		GetError(DWORD *pErrCode,xbString *pMsg,xbString *pCtx) const
	{
		if (!m_pObj)
		{
			if (pErrCode)
				*pErrCode = S_OK;
			if (pMsg)
				pMsg->Empty();
			if (pCtx)
				pCtx->Empty();
			return false;
		}
		return m_pObj->GetError(pErrCode,pMsg,pCtx);
	}
	virtual bool		IsLoaded() const
	{
		return m_pObj && m_pObj->IsLoaded();
	}
	virtual bool		IsWrited() const
	{
		return m_pObj && m_pObj->IsWrited();
	}
	bool	operator==(const xbDnPtr<object,iobject> &ptr) const
	{
		return m_Url == ptr.m_Url
			&& m_UrlParseType == ptr.m_UrlParseType;
	}
	bool	operator!=(const xbDnPtr<object,iobject> &ptr) const
	{
		return m_Url != ptr.m_Url
			|| m_UrlParseType != ptr.m_UrlParseType;
	}
	inline void Empty(bool bAddAfter = false)
	{
		m_Url.Empty();
		m_UrlParseType = 0;
		xbPtr<iobject>::Empty(bAddAfter);
	}
	inline bool PtrEmpty(bool bAddAfter = false)
	{
		return xbPtr<iobject>::PtrEmpty(bAddAfter);
	}
protected:
	xbString				m_Url; //,m_cookies;
	__int64					m_UrlParseType;
	sIxbDnPtr			*m_pNextWaiting;

	virtual sIxbDnPtr *_getNextWaiting()
	{
		if (!m_pNextWaiting) return NULL;
		sIxbDnPtr *pRet = m_pNextWaiting;
		m_pNextWaiting = NULL;
		return pRet;
	}
	virtual void _setNextWaiting(sIxbDnPtr *ptr)
	{
		m_pNextWaiting = ptr;
	}
};

#endif
