//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
#ifndef __DEVICE_DESC_IMPL_H__
#define __DEVICE_DESC_IMPL_H__

#include "upnp.h"

#define DLLSVC 1
#include <combook.h>

#include "string.hxx"
#include "sax.h"
#include "list.hxx"
#include "DispatchImpl.hxx"
#include "sync.hxx"
#include "gencf.h"

class Device;

class DeviceDescription : public ce::DispatchImpl<IUPnPDescriptionDocument, &IID_IUPnPDescriptionDocument>, 
                          ce::SAXContentHandler
{
public:
    DeviceDescription(UINT nLifeTime = 0);
    ~DeviceDescription();

    friend class Device;

    DEFAULT_CLASS_REGISTRY_TABLE(DeviceDescription,
                                 TEXT("{1d8a9b47-3a28-4ce2-8a4b-bd34e45bceeb}"),    // CLSID
                                 TEXT("UPnP DescriptionDocument Class"),            // friendly name
                                 TEXT("UPnP.DescriptionDocument.1"),                // ProgID
                                 TEXT("UPnP.DescriptionDocument"),                  // version independent ProgID
                                 TEXT("Both"));                                     // threading model

    BEGIN_INTERFACE_TABLE(DeviceDescription)
        IMPLEMENTS_INTERFACE(IUPnPDescriptionDocument)
        IMPLEMENTS_INTERFACE(IDispatch)
    END_INTERFACE_TABLE()

    IMPLEMENT_UNKNOWN(DeviceDescription);

    IMPLEMENT_CREATE_INSTANCE(DeviceDescription);

    IMPLEMENT_GENERIC_CLASS_FACTORY(DeviceDescription);

// IUPnPDescriptionDocument
public:
    STDMETHOD(get_ReadyState)   (/* [retval][out] */ LONG *plReadyState);
    STDMETHOD(Load)             (/* [in] */ BSTR bstrUrl);
    STDMETHOD(LoadAsync)        (/* [in] */ BSTR bstrUrl, /* [in] */ IUnknown *punkCallback);
    STDMETHOD(get_LoadResult)   (/* [retval][out] */ long *phrError);
    STDMETHOD(Abort)            (void);
    STDMETHOD(RootDevice)       (/* [retval][out] */ IUPnPDevice **ppudRootDevice);
    STDMETHOD(DeviceByUDN)      (/* [in] */ BSTR bstrUDN, /* [retval][out] */ IUPnPDevice **ppudDevice);

private:
    void                DeviceAddedCallback(Device* pDevice);
    void                LoadImpl();
    HRESULT             Parse(LPCSTR pszDescriptionURL);
    static DWORD WINAPI LoadAsyncThread(LPVOID lpParameter);

    typedef enum tagREADYSTATE
    {
        READYSTATE_UNINITIALIZED = 0,
        READYSTATE_LOADING       = 1,
        READYSTATE_LOADED        = 2,
        READYSTATE_INTERACTIVE   = 3,
        READYSTATE_COMPLETE      = 4         // _hrLoadResult is valid
    } READYSTATE;

// ISAXContentHandler
private:
    virtual HRESULT STDMETHODCALLTYPE startElement(
        /* [in] */ const wchar_t __RPC_FAR *pwchNamespaceUri,
        /* [in] */ int cchNamespaceUri,
        /* [in] */ const wchar_t __RPC_FAR *pwchLocalName,
        /* [in] */ int cchLocalName,
        /* [in] */ const wchar_t __RPC_FAR *pwchQName,
        /* [in] */ int cchQName,
        /* [in] */ ISAXAttributes __RPC_FAR *pAttributes);
    
    virtual HRESULT STDMETHODCALLTYPE endElement( 
        /* [in] */ const wchar_t __RPC_FAR *pwchNamespaceUri,
        /* [in] */ int cchNamespaceUri,
        /* [in] */ const wchar_t __RPC_FAR *pwchLocalName,
        /* [in] */ int cchLocalName,
        /* [in] */ const wchar_t __RPC_FAR *pwchQName,
        /* [in] */ int cchQName);
    
    virtual HRESULT STDMETHODCALLTYPE characters( 
        /* [in] */ const wchar_t __RPC_FAR *pwchChars,
        /* [in] */ int cchChars);

private:
    ce::string             m_strBaseURL;
    ce::wstring            m_strBaseURLTag;
    ce::wstring            m_strSpecVersionMajor;
    ce::wstring            m_strSpecVersionMinor;
    ce::wstring            m_strUrl;
    Device*                m_pRootDevice;
    Device*                m_pTempDevice;
    int                    m_nPass;
    bool                   m_bAbort;
    bool                   m_bParsedRootElement;
    ce::list<Device*>      m_listDevices;
    READYSTATE             m_ReadyState;
    HRESULT                m_hrLoadResult;
    ce::critical_section   m_cs;
    IUnknown*              m_punkCallback;
    UINT                   m_nLifeTime;
};

#endif // __DEVICE_DESC_IMPL_H__
