// SrvcCall.cpp
// Code to implement the INmCallNotify interface for the remote control service

#include "precomp.h"
#include "srvcutil.h"
#include "srvccall.h"

CSrvcCall::CSrvcCall(INmCall * pNmCall) :
	m_pCall  (pNmCall),
	m_pszName  (NULL),
	m_pszAddr  (NULL),
	m_addrType (NM_ADDR_UNKNOWN),
	m_fSelectedConference (FALSE),
	m_pos      (NULL),
	m_cRef     (1),
	m_dwCookie (0)
{
	HRESULT hr;

	TRACE_OUT(("CSrvcCall: Created %08X (INmCall=%08X)", this, pNmCall));

	ASSERT(NULL != m_pCall);
	m_pCall->AddRef();

	// Get the display name
	BSTR  bstr;
	hr = m_pCall->GetName(&bstr);
	if (SUCCEEDED(hr))
	{
		hr = BSTR_to_LPTSTR(&m_pszName, bstr);
		SysFreeString(bstr);
	}
	if (FEmptySz(m_pszName))
	{
		// Default to "another person" if no name available in the call data
		m_pszName = TEXT("Somebody");
	}

	hr = m_pCall->GetAddr(&bstr, &m_addrType);
	if (SUCCEEDED(hr))
	{
		hr = BSTR_to_LPTSTR(&m_pszAddr, bstr);
		SysFreeString(bstr);
	}

	// These should never change
	m_fIncoming = (m_pCall->IsIncoming() == S_OK);
	m_dwTick = ::GetTickCount();

	Update();

	NmAdvise(m_pCall, this, IID_INmCallNotify, &m_dwCookie);
}

VOID CSrvcCall::RemoveCall(void)
{
	NmUnadvise(m_pCall, IID_INmCallNotify, m_dwCookie);
}

CSrvcCall::~CSrvcCall()
{
	delete m_pszName;
	delete m_pszAddr;

	ASSERT(NULL != m_pCall);
	m_pCall->Release();
}

// IUnknown methods
STDMETHODIMP_(ULONG) CSrvcCall::AddRef(void)
{
	return ++m_cRef;
}

STDMETHODIMP_(ULONG) CSrvcCall::Release(void)
{
	ASSERT(m_cRef > 0);
	if (m_cRef > 0)
	{
		m_cRef--;
	}

	ULONG cRef = m_cRef;

	if (0 == cRef)
	{
		delete this;
	}

	return cRef;
}

STDMETHODIMP CSrvcCall::QueryInterface(REFIID riid, PVOID *ppv)
{
	HRESULT hr = S_OK;

	if ((riid == IID_INmCallNotify) || (riid == IID_IUnknown))
	{
		*ppv = (INmCallNotify *)this;
//		ApiDebugMsg(("CCall::QueryInterface()"));
	}
	else
	{
		hr = E_NOINTERFACE;
		*ppv = NULL;
//		ApiDebugMsg(("CCall::QueryInterface(): Called on unknown interface."));
	}

	if (S_OK == hr)
	{
		AddRef();
	}

	return hr;
}

// INmCallNotify methods
STDMETHODIMP CSrvcCall::NmUI(CONFN uNotify)
{
	return S_OK;
}

STDMETHODIMP CSrvcCall::StateChanged(NM_CALL_STATE uState)
{
	// REVIEW: This check should be done outside of this routine
	if (uState == m_State)
	{
		// Don't bother the UI when nothing changes!
		return S_OK;
	}

	Update();

	return S_OK;
}

STDMETHODIMP CSrvcCall::Failed(ULONG uError)
{
	return S_OK;
}

STDMETHODIMP CSrvcCall::Accepted(INmConference *pConference)
{
	return S_OK;
}

// INmCallNotify3 methods
STDMETHODIMP CSrvcCall::CallError(UINT cns)
{
	return S_OK;
}

STDMETHODIMP CSrvcCall::VersionConflict(HRESULT Status, BOOL *pfContinue)
{
	return S_OK;
}

STDMETHODIMP CSrvcCall::RemoteConference(BOOL fMCU, BSTR *pwszConfNames, BSTR *pbstrConfToJoin)
{
	return S_OK;
}

STDMETHODIMP CSrvcCall::RemotePassword(BSTR bstrConference, BSTR *pbstrPassword, BYTE *pb, DWORD cb, BOOL fIsService)
{
	return S_OK;
}

/*  U P D A T E  */
/*-------------------------------------------------------------------------
    %%Function: Update

    Update the cached information about the call
-------------------------------------------------------------------------*/
VOID CSrvcCall::Update(void)
{
	m_pCall->GetState(&m_State);
	// TRACE_OUT(("CCall: New State=%0d for call=%08X", m_State, this));

	switch (m_State)
	{
	case NM_CALL_ACCEPTED:
	case NM_CALL_REJECTED:
	case NM_CALL_CANCELED:

		RemoveCall();
		Release();
		break;

	case NM_CALL_RING:
		m_pCall->Accept();
		break;

	default:
		ERROR_OUT(("CCall::Update: Unknown state %08X", m_State));

	case NM_CALL_INVALID:
	case NM_CALL_INIT:
	case NM_CALL_SEARCH:
	case NM_CALL_WAIT:
		break;
	}

}