#include "stdafx.h"
#include "resource.h"

#include "urlmonikerdlg.h"
#include "bindcallback.h"

#define	BUFSIZE	500000 

void CALLBACK TimerFunc(HWND hWnd, UINT msg,  UINT idEvent, DWORD dwTime) 
{
	MessageBeep (0) ;
	CBindStatusCallback	*pThis =  (CBindStatusCallback*) idEvent ;

/*
Didn't begin download in time, abort the operation.This should
generate a call to OnStopBinding( ) ;
*/
	if (pThis->m_BeganDownload == FALSE)
	{
		pThis->m_pBinding->Abort( ) ;
	}

	KillTimer (hWnd, idEvent) ;
	MessageBeep (0) ;
}

/*
Constructor 
*/

CBindStatusCallback::CBindStatusCallback (CUrlmonikerDlg *pDlg)
{
    m_RefCount = 1;
	m_pDlg = pDlg ;
	m_LastSize = 0 ;
	m_pBinding = NULL ;
	m_BeganDownload = FALSE ;
}

/*
Destructor
*/

CBindStatusCallback::~CBindStatusCallback()
{
	GlobalFree (m_pBuf) ;
	m_pBinding->Release( ) ;
} 


STDMETHODIMP CBindStatusCallback::OnStartBinding(DWORD grfBSCOption, IBinding* pbinding)
{

/*
Addref the binding for later use.
*/
	m_pBinding = pbinding ;
		
	m_pBinding->AddRef ( )  ;

/*
Show status to user.
*/

	m_pDlg->SetDlgItemText (IDC_STATUS, "Starting to bind ...") ;
/*
Allocate a large buffer for incoming text.
*/
    m_pBuf = (char *) GlobalAlloc (GMEM_FIXED | GMEM_ZEROINIT, BUFSIZE) ;

/*
Start the timeout interval for beginning the download.
*/
	UINT TimeoutSec = m_pDlg->GetDlgItemInt (IDC_TIMEOUTSEC) ;
	SetTimer (m_pDlg->m_hWnd, (UINT)this, TimeoutSec * 1000, TimerFunc) ;
	
	return S_OK;
}  

STDMETHODIMP CBindStatusCallback::OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
{
/*
Find character string that corresponds to status flag.  Place in
edit control for user to look at.
*/
	char *cp ;
	switch (ulStatusCode)
	{
		case BINDSTATUS_FINDINGRESOURCE: cp = "Finding resource..."; break ;
		case BINDSTATUS_CONNECTING: cp = "Connecting"; break ;
		case BINDSTATUS_REDIRECTING: cp = "Redirecting"; break ;
		case BINDSTATUS_BEGINDOWNLOADDATA: cp = "Beginning download"; break ;
		case BINDSTATUS_DOWNLOADINGDATA: cp = "Downloading"; break ;
		case BINDSTATUS_ENDDOWNLOADDATA: cp = "Download completed"; break ;
		case BINDSTATUS_BEGINDOWNLOADCOMPONENTS: cp	= "beginning component download" ; break ;
		case BINDSTATUS_INSTALLINGCOMPONENTS: cp = "Installing components"; break ;
		case BINDSTATUS_ENDDOWNLOADCOMPONENTS: cp = "End download components" ; break ;
		case BINDSTATUS_USINGCACHEDCOPY: cp = "using cached copy" ; break ;
		case BINDSTATUS_SENDINGREQUEST: cp = "Sending request" ; break ;
		case BINDSTATUS_CLASSIDAVAILABLE: cp = "Class ID Available" ; break ;
		case BINDSTATUS_MIMETYPEAVAILABLE: cp = "Mime type available" ; break ;
		case BINDSTATUS_CACHEFILENAMEAVAILABLE: cp = "Cache file name available" ; break ;
		default: cp = "Unknown progress flag" ;
	}
 	m_pDlg->SetDlgItemText (IDC_STATUS, cp) ;


/*
Put status string in status edit control
*/ 
	USES_CONVERSION ;
	m_pDlg->SetDlgItemText (IDC_PROGSTRING, W2A(szStatusText)) ;

/*
Set state of progress indicator bar
*/
	m_pDlg->m_Progress.SetRange (0, ulProgressMax/1000) ;
	m_pDlg->m_Progress.SetPos (ulProgress/1000) ;

    return(NOERROR);
}  

STDMETHODIMP CBindStatusCallback::OnStopBinding(HRESULT hrStatus, LPCWSTR pszError) 
{
    if (pszError)
	{
		USES_CONVERSION ;
		m_pDlg->SetDlgItemText (IDC_STATUS, W2A(pszError)) ;
	}
	else
	{
		if (hrStatus == S_OK) 
		{
			m_pDlg->SetDlgItemText (IDC_STATUS, "Successful Completion") ;
		}
		else
		{
			char out [256] ;
			wsprintf (out, "OnStopBinding Error: 0x%x", hrStatus) ;
			m_pDlg->SetDlgItemText (IDC_STATUS, out) ;
		}
	}

	m_pDlg->BindFinished( ) ;

    return S_OK;
}  


/*
Moniker is asking us to fill in a BINDINFO structure decribing the binding
operation that is about to occur.
*/

STDMETHODIMP CBindStatusCallback::GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindInfo)
{

/*
Fill out flags 
*/

    *pgrfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;

/*
Fill out structure
*/
    pbindInfo->cbSize = sizeof(BINDINFO);		// size
    pbindInfo->szExtraInfo = NULL;

    memset(&pbindInfo->stgmedData, 0, sizeof(STGMEDIUM));
    pbindInfo->grfBindInfoF = 0;
    pbindInfo->dwBindVerb = BINDVERB_GET;
    pbindInfo->szCustomVerb = NULL;

    return S_OK;
} 

/*
Data Available
*/

STDMETHODIMP CBindStatusCallback::OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC* pfmtetc, STGMEDIUM* pstgmed) 
{
/*
If more data has arrived, read it into the edit control buffer. Invalidate to force
a repaint.
*/
	DWORD nBytesToRead = dwSize - m_LastSize ;
	DWORD nActual ;

	if (dwSize > m_LastSize)
    {
		pstgmed->pstm->Read (m_pBuf + m_LastSize, nBytesToRead, &nActual) ;
  		m_pDlg->SetDlgItemText (IDC_DATAEDIT, m_pBuf) ;
		m_LastSize = dwSize ;
		m_BeganDownload = TRUE ;
	}
/*
Do another read to keep the flow of data coming.
*/
	HRESULT hr = pstgmed->pstm->Read (m_pBuf + m_LastSize, 1, NULL) ;

    return S_OK;
}  

/*
Stubbed-out methods
*/
 
STDMETHODIMP CBindStatusCallback::OnObjectAvailable(REFIID riid, IUnknown* punk) 
{
	AfxMessageBox ("OnObjectAvailable") ;
    return E_NOTIMPL;
}  

STDMETHODIMP CBindStatusCallback::GetPriority(LONG* pnPriority) 
{
	AfxMessageBox ("GetPriority") ;
	return E_NOTIMPL;
}  

STDMETHODIMP CBindStatusCallback::OnLowResource(DWORD dwReserved)
{
	AfxMessageBox ("OnLowResource") ;
    return E_NOTIMPL;
}  



/*
IUnknown methods
*/

STDMETHODIMP CBindStatusCallback::QueryInterface(REFIID riid, void** ppv)
{ 
	if (riid==IID_IUnknown || riid==IID_IBindStatusCallback)
	{
        *ppv = this;
        AddRef();
        return S_OK;
    }
	else
	{
		*ppv = NULL ;
		return E_NOINTERFACE;
	}
}

STDMETHODIMP_(ULONG) CBindStatusCallback::AddRef()    
{ 
	return m_RefCount ++; 
}

STDMETHODIMP_(ULONG)  CBindStatusCallback::Release()
{ 
	if (--m_RefCount == 0) 
	{ 
		delete this ; 
		return 0; 
	} 
	else
	{
		return m_RefCount ; 
	}
}



