#ifndef _MSPCOLL_H_
#define _MSPCOLL_H_

template <class T> class CTapiIfCollection : public IDispatchImpl<ITCollection,&IID_ITCollection,&LIBID_TAPI3Lib>,public CComObjectRootEx<CComMultiThreadModelNoCS>
{
public:
  typedef CTapiIfCollection<T> _CTapiCollectionBase;
  BEGIN_COM_MAP(_CTapiCollectionBase)
    COM_INTERFACE_ENTRY(IDispatch)
    COM_INTERFACE_ENTRY(ITCollection)
  END_COM_MAP()
private:
  int m_nSize;
  CComVariant *m_Var;

public:
  CTapiIfCollection(void) : m_nSize(0),m_Var(NULL) { }
  HRESULT WINAPI Initialize(DWORD dwSize,T *pBegin,T *pEnd) {
    int i;
    HRESULT hr;
    T *iter;
    LOG((MSP_TRACE,"CTapiCollection::Initialize - enter"));
    m_nSize = dwSize;
    m_Var = new CComVariant[m_nSize];
    if(!m_Var) return E_OUTOFMEMORY;
    i = 0;
    for(iter = pBegin;iter!=pEnd;iter++) {
      IDispatch *pDisp = NULL;
      hr = (*iter)->QueryInterface(IID_IDispatch,(void**)&pDisp);
      if(hr!=S_OK) return hr;
      CComVariant& var = m_Var[i];
      VariantInit(&var);
      var.vt = VT_DISPATCH;
      var.pdispVal = pDisp;
      i++;
    }
    LOG((MSP_TRACE,"CTapiCollection::Initialize - exit"));
    return S_OK;
  }
  void FinalRelease() {
    LOG((MSP_TRACE,"CTapiCollection::FinalRelease - enter"));
    delete [] m_Var;
    LOG((MSP_TRACE,"CTapiCollection::FinalRelease - exit"));
  }
  STDMETHOD(get_Count)(long *retval) {
    HRESULT hr = S_OK;
    LOG((MSP_TRACE,"CTapiCollection::get_Count - enter"));
    try {
      *retval = m_nSize;
    } catch(...) {
      hr = E_INVALIDARG;
    }
    LOG((MSP_TRACE,"CTapiCollection::get_Count - exit"));
    return hr;
  }
  STDMETHOD(get_Item)(long Index,VARIANT *retval) {
    HRESULT hr = S_OK;
    LOG((MSP_TRACE,"CTapiCollection::get_Item - enter"));
    if(!retval) return E_POINTER;
    try {
      VariantInit(retval);
    } catch(...) {
      hr = E_INVALIDARG;
    }
    if(hr!=S_OK) return hr;
    retval->vt = VT_UNKNOWN;
    retval->punkVal = NULL;
    if((Index < 1) || (Index > m_nSize)) return E_INVALIDARG;
    hr = VariantCopy(retval,&m_Var[Index-1]);
    if(FAILED(hr)) {
      LOG((MSP_ERROR,"CTapiCollection::get_Item - VariantCopy failed. hr = %lx",hr));
      return hr;
    }
    LOG((MSP_TRACE,"CTapiCollection::get_Item - exit"));
    return S_OK;
  }
  HRESULT WINAPI get__NewEnum(IUnknown **retval) {
    HRESULT hr;
    LOG((MSP_TRACE,"CTapiCollection::new__Enum - enter"));
    if(!retval) return E_POINTER;
    *retval = NULL;
    typedef CComObject<CSafeComEnum<IEnumVARIANT,&IID_IEnumVARIANT,VARIANT,_Copy<VARIANT> > > enumvar;
    enumvar *p;
    hr = enumvar::CreateInstance(&p);
    if(FAILED(hr)) return hr;
    hr = p->Init(&m_Var[0],&m_Var[m_nSize],NULL,AtlFlagCopy);
    if(SUCCEEDED(hr)) hr = p->QueryInterface(IID_IEnumVARIANT,(void**)retval);
    if(FAILED(hr)) delete p;
    LOG((MSP_TRACE,"CTapiCollection::new__Enum - exit"));
    return hr;
  }
};

class CTapiBstrCollection : public CComObjectRootEx<CComMultiThreadModelNoCS>,public IDispatchImpl<ITCollection,&IID_ITCollection,&LIBID_TAPI3Lib>,public CMSPObjectSafetyImpl
{
public:
  BEGIN_COM_MAP(CTapiBstrCollection)
    COM_INTERFACE_ENTRY(IDispatch)
    COM_INTERFACE_ENTRY(ITCollection)
    COM_INTERFACE_ENTRY(IObjectSafety)
  END_COM_MAP()
private:
  DWORD m_dwSize;
  CComVariant *m_Var;
public:
  CTapiBstrCollection(void) : m_dwSize(0),m_Var(NULL) { }
  HRESULT WINAPI Initialize(DWORD dwSize,BSTR *pBegin,BSTR *pEnd) {
    BSTR *i;
    DWORD dw = 0;
    LOG((MSP_TRACE,"CTapiBstrCollection::Initialize - enter"));
    m_dwSize = dwSize;
    m_Var = new CComVariant[m_dwSize];
    if(!m_Var) return E_OUTOFMEMORY;
    for(i = pBegin;i!=pEnd;i++) {
      CComVariant& var = m_Var[dw];
      var.vt = VT_BSTR;
      var.bstrVal = *i;
      dw++;
    }
    LOG((MSP_TRACE,"CTapiBstrCollection::Initialize - exit"));
    return S_OK;
  }
  STDMETHOD(get_Count)(long *retval) {
    HRESULT hr = S_OK;
    LOG((MSP_TRACE,"CTapiBstrCollection::get_Count - enter"));
    try {
      *retval = m_dwSize;
    } catch(...) {
      hr = E_INVALIDARG;
    }
    LOG((MSP_TRACE,"CTapiBstrCollection::get_Count - exit"));
    return hr;
  }
  STDMETHOD(get_Item)(long Index,VARIANT *retval) {
    HRESULT hr = S_OK;
    LOG((MSP_TRACE,"CTapiBstrCollection::get_Item - enter"));
    if(!retval) return E_POINTER;
    try {
      VariantInit(retval);
    } catch(...) {
      hr = E_INVALIDARG;
    }
    if(hr!=S_OK) return hr;
    retval->vt = VT_BSTR;
    retval->bstrVal = NULL;
    if((Index < 1) || ((DWORD) Index > m_dwSize)) return E_INVALIDARG;
    hr = VariantCopy(retval,&m_Var[Index-1]);
    if(FAILED(hr)) {
      LOG((MSP_ERROR,"CTapiBstrCollection::get_Item - VariantCopy failed. hr = %lx",hr));
      return hr;
    }
    LOG((MSP_TRACE,"CTapiBstrCollection::get_Item - exit"));
    return S_OK;
  }
  HRESULT WINAPI get__NewEnum(IUnknown **retval) {
    HRESULT hr;
    LOG((MSP_TRACE,"CTapiBstrCollection::get__NumEnum - enter"));
    if(!retval) return E_POINTER;
    *retval = NULL;
    typedef CComObject<CSafeComEnum<IEnumVARIANT,&IID_IEnumVARIANT,VARIANT,_Copy<VARIANT> > > enumvar;
    enumvar *p = new enumvar;
    if(!p) return E_OUTOFMEMORY;
    hr = p->Init(&m_Var[0],&m_Var[m_dwSize],NULL,AtlFlagCopy);
    if(SUCCEEDED(hr)) {
      hr = p->QueryInterface(IID_IEnumVARIANT,(void**)retval);
    }
    if(FAILED(hr)) delete p;
    LOG((MSP_TRACE,"CTapiBstrCollection::get__NewEnum - exit"));
    return hr;
  }
  void FinalRelease() {
    LOG((MSP_TRACE,"CTapiBstrCollection::FinalRelease() - enter"));
    delete [] m_Var;
    LOG((MSP_TRACE,"CTapiBstrCollection::FinalRelease() - exit"));
  }
};
#endif
