//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
//
// oleobj.cpp 
//
//   IOleObject Implementation.  IOleObject is required for for downloading
//   cdf files from within the browser.
//
//   History:
//
//       6/18/97  edwardp   Created.
//
////////////////////////////////////////////////////////////////////////////////

//
// Includes
//

#include "stdinc.h"
#include "cdfidl.h"
#include "xmlutil.h"
#include "chanapi.h"
#include "chanenum.h"
#include "persist.h"
#include "resource.h"
#include <shguidp.h>
#include <htiface.h>   // IID_ITargetEmbedding
#define _SHDOCVW_
#include <shdocvw.h>

#include <mluisupp.h>

STDMETHODIMP CPersist::SetClientSite(IOleClientSite *pIOleClientSite)
{
#ifdef IMP_CLIENTSITE

    if (NULL != m_pOleClientSite)
        m_pOleClientSite->Release();

    m_pOleClientSite = pIOleClientSite;

    if (m_pOleClientSite)
        m_pOleClientSite->AddRef();

#endif

    if (pIOleClientSite && NULL == m_pIWebBrowser2)
    {
        IOleWindow *pIOleWindow;

        HRESULT hr = pIOleClientSite->QueryInterface(IID_IOleWindow,
                                                     (void**)&pIOleWindow);
        if (SUCCEEDED(hr))
        {
            ASSERT(NULL != pIOleWindow);
            pIOleWindow->GetWindow(&m_hwnd);
            pIOleWindow->Release();
        }

        IServiceProvider* pIServiceProvider;

        hr = pIOleClientSite->QueryInterface(IID_IServiceProvider,
                                             (void**)&pIServiceProvider);

        if (SUCCEEDED(hr))
        {
            ASSERT(pIServiceProvider);

            IServiceProvider* pIServiceProvider2;

            hr = pIServiceProvider->QueryService(SID_STopLevelBrowser,
                                                 IID_IServiceProvider,
                                                 (void**)&pIServiceProvider2);

            if (SUCCEEDED(hr))
            {
                ASSERT(pIServiceProvider2);

                hr = pIServiceProvider2->QueryService(SID_SWebBrowserApp,
                                                      IID_IWebBrowser2,
                                                      (void**)&m_pIWebBrowser2);

                //
                // REVIEW: Determine if the current browser is IE
                //
                // New check if the browser is IE.  IE will fail on a QI of
                // IWebBrowserApp for ITargetEmbedding.  Anyone else hosting
                // the browser OC must support this interface.
                //

                IWebBrowserApp* pIWebBrowserApp;

                hr = m_pIWebBrowser2->QueryInterface(IID_IWebBrowserApp,
                                                     (void**)&pIWebBrowserApp);

                if (SUCCEEDED(hr))
                {
                    ASSERT(pIWebBrowserApp);

                    ITargetEmbedding* pITargetEmbedding;

                    hr = pIWebBrowserApp->QueryInterface(IID_ITargetEmbedding,
                                                    (void**)&pITargetEmbedding); 

                    if (SUCCEEDED(hr))
                    {
                        ASSERT(pITargetEmbedding);

                        //
                        // This isn't IE.  So release m_IWebBrowser2.  IE
                        // will be CoCreated later if m_IWebBrowser2 == NULL.
                        //

                        m_pIWebBrowser2->Release();
                        m_pIWebBrowser2 = NULL;

                        pITargetEmbedding->Release();
                    }

                    pIWebBrowserApp->Release();
                }

                pIServiceProvider2->Release();
            }

            pIServiceProvider->Release();
        }


    }

    return S_OK;
}

STDMETHODIMP CPersist::GetClientSite(IOleClientSite **ppClientSite)
{
#ifdef IMP_CLIENTSITE

    ASSERT(ppClientSite);

    if (NULL != m_pOleClientSite)
    {
        *ppClientSite = m_pOleClientSite;
        return S_OK;
    }
    else
        return E_UNEXPECTED;
#else

    return E_NOTIMPL;

#endif
}

STDMETHODIMP CPersist::SetHostNames(LPCOLESTR szContainerApp,
                          LPCOLESTR szContainerObj)
{
    return E_NOTIMPL;
}

STDMETHODIMP CPersist::Close(DWORD dwSaveOption)
{
    return E_NOTIMPL;
}

STDMETHODIMP CPersist::SetMoniker(DWORD dwWhichMoniker, IMoniker *pmk)
{
    return E_NOTIMPL;
}

STDMETHODIMP CPersist::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker,
                        IMoniker **ppmk)
{
    return E_NOTIMPL;
}

STDMETHODIMP CPersist::InitFromData(IDataObject *pDataObject, BOOL fCreation,
                          DWORD dwReserved)
{
    return E_NOTIMPL;
}

STDMETHODIMP CPersist::GetClipboardData(DWORD dwReserved,IDataObject **ppDataObject)
{
    return E_NOTIMPL;
}

STDMETHODIMP CPersist::DoVerb(LONG iVerb, LPMSG lpmsg, IOleClientSite *pActiveSite,
                              LONG lindex, HWND hwndParent, LPCRECT lprcPosRect)
{
    HRESULT hr;

    if (OLEIVERB_PRIMARY == iVerb)
    {
        ASSERT(m_pIXMLDocument);

        XMLDOCTYPE xdt = XML_GetDocType(m_pIXMLDocument);

        switch(xdt)
        {
        case DOC_CHANNEL:
        case DOC_SOFTWAREUPDATE:
            // Admins can disallow adding channels and limit
            // the number of installed channels.
            if (1 /*(dwFlags & STC_CHANNEL)*/ &&
                !SHRestricted2W(REST_NoAddingChannels, m_polestrURL, 0) &&
                (!SHRestricted2W(REST_MaxChannelCount, NULL, 0) ||
                (CountChannels() < SHRestricted2W(REST_MaxChannelCount, NULL, 0))))
            {
                XML_DownloadLogo(m_pIXMLDocument);

                //
                // In case the SELF tag is different than the URL get the
                // subscribed URL from SubscriptionHelper.
                //

                BSTR bstrSubscribedURL = NULL;

                if (SubscriptionHelper(m_pIXMLDocument, m_hwnd,
                                       SUBSTYPE_CHANNEL,
                                       SUBSACTION_ADDADDITIONALCOMPONENTS,
                                       m_polestrURL, xdt, &bstrSubscribedURL))
                {
                    TCHAR szSubscribedURL[INTERNET_MAX_URL_LENGTH];

                    if (bstrSubscribedURL &&
                        SHUnicodeToTChar(bstrSubscribedURL, szSubscribedURL,
                                       ARRAYSIZE(szSubscribedURL)))
                    {
                        FILETIME ftLastMod;
                        URLGetLastModTime(szSubscribedURL, &ftLastMod);

                        Cache_AddItem(szSubscribedURL, m_pIXMLDocument,
                                      PARSE_NET, ftLastMod, g_dwCacheCount);
                    }

                    OpenChannel(bstrSubscribedURL);

                    hr = S_OK;
                }
                else
                {
                    hr = S_FALSE;
                }

                if (bstrSubscribedURL)
                    SysFreeString(bstrSubscribedURL);
            }
            else
            {
                hr = E_ACCESSDENIED;
            }
            break;

        case DOC_DESKTOPCOMPONENT:
#ifndef UNIX
            if (m_hwnd && WhichPlatform() != PLATFORM_INTEGRATED)
#else
            if (0)
#endif /* UNIX */
            {
                TCHAR szText[MAX_PATH];
                TCHAR szTitle[MAX_PATH];

                MLLoadString(IDS_BROWSERONLY_DLG_TEXT,  szText,
                           ARRAYSIZE(szText)); 
                MLLoadString(IDS_BROWSERONLY_DLG_TITLE, szTitle,
                            ARRAYSIZE(szTitle));

                MessageBox(m_hwnd, szText, szTitle, MB_OK); 
            }
            else if (1 /*dwFlags & STC_DESKTOPCOMPONENT*/)
            {
                COMPONENT Info;
                hr = XML_GetDesktopComponentInfo(m_pIXMLDocument, &Info);
                if(SUCCEEDED(hr))
                {
                    if(!Info.wszSubscribedURL[0])
                    {
                        if(m_polestrURL)
                        {
                            StrCpyNW(Info.wszSubscribedURL, m_polestrURL, ARRAYSIZE(Info.wszSubscribedURL));
                        }
                        else
                        {
                            TraceMsg(TF_GENERAL, "CPersist::DoVerb : COMPONENT::wszSubscribedURL is not set.");
                            hr = S_FALSE;
                        }
                    }
#ifndef UNIX
                    /* No Active Desktop on Unix */
                    if (SUCCEEDED(hr))
                    {
                    
                        IActiveDesktop* pIActiveDesktop;
                        hr = CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER,
                                  IID_IActiveDesktop, (void**)&pIActiveDesktop);
                        if (SUCCEEDED(hr))
                        {
                            ASSERT(pIActiveDesktop);

                            hr = pIActiveDesktop->AddDesktopItemWithUI(m_hwnd, &Info, DTI_ADDUI_DISPSUBWIZARD);

                            // Note: Do not call pIActiveDesktop->ApplyChanges() here. AddDesktopItemWithUI() itself creates
                            // one instance of ActiveDesktop object, adds the component and calls ApplyChanges() for us. 
                            // Calling ApplyChanges() again here causes the second instance US to overwrite with stale data.
                            // Bug #404153. Fixed by Sankar. 29th May 2001.

                            pIActiveDesktop->Release();
                        }
                        else
                        {
                            TraceMsg(TF_GENERAL, "CPersist::DoVerb : CoCreateInstance for CLSID_ActiveDesktop failed.");
                        }
                    }
#endif /* !UNIX */
                }
                if(SUCCEEDED(hr))
                {
                    hr = S_OK;
                }
                else
                {
                    hr = S_FALSE;
                }
            }
            else
            {
                hr = E_ACCESSDENIED;
            }
            break;

        case DOC_UNKNOWN:
        default:
            hr = E_FAIL;
            break;
        }
    }
    else
    {
        hr = E_NOTIMPL;
    }

    return hr;
}

STDMETHODIMP CPersist::EnumVerbs(IEnumOLEVERB **ppEnumOleVerb)
{
    return E_NOTIMPL;
}

STDMETHODIMP CPersist::Update(void)
{
    return E_NOTIMPL;
}

STDMETHODIMP CPersist::IsUpToDate(void)
{
    return E_NOTIMPL;
}

STDMETHODIMP CPersist::GetUserClassID(CLSID *pClsid)
{
    return E_FAIL;
}

STDMETHODIMP CPersist::GetUserType(DWORD dwFormOfType, LPOLESTR *pszUserType)
{
    return E_NOTIMPL;
}

STDMETHODIMP CPersist::SetExtent(DWORD dwDrawAspect, SIZEL *psizel)
{
    return E_NOTIMPL;
}

STDMETHODIMP CPersist::GetExtent(DWORD dwDrawAspect, SIZEL *psizel)
{
    return E_NOTIMPL;
}

STDMETHODIMP CPersist::Advise(IAdviseSink *pAdvSink, DWORD *pdwConnection)
{
    return E_NOTIMPL;
}

STDMETHODIMP CPersist::Unadvise(DWORD dwConnection)
{
    return E_NOTIMPL;
}

STDMETHODIMP CPersist::EnumAdvise(IEnumSTATDATA **ppenumAdvise)
{
    return E_NOTIMPL;
}

STDMETHODIMP CPersist::GetMiscStatus(DWORD dwAspect, DWORD *pdwStatus)
{
    return E_NOTIMPL;
}

STDMETHODIMP CPersist::SetColorScheme(LOGPALETTE *pLogpal)
{
    return E_NOTIMPL;
}

//
// Helper functions.
//

HRESULT
CPersist::OpenChannel(
    LPCWSTR pszSubscribedURL                   
)
{
    ASSERT(m_pIXMLDocument);

    HRESULT hr;

    if (NULL == m_pIWebBrowser2)
    {
        hr = CoCreateInstance(CLSID_InternetExplorer, NULL, 
                                                  CLSCTX_LOCAL_SERVER,
                                                  IID_IWebBrowser2, 
                                                  (void**)&m_pIWebBrowser2);
        if (FAILED(hr))
        {
            return hr;
        }
    }

    
    //m_pIWebBrowser2->put_TheaterMode(-1); Moved to worker window
    //m_pIWebBrowser2->put_Visible(-1);

    //ShowChannelPane(m_pIWebBrowser2);


    IXMLElement*    pIXMLElement;
    LONG            nIndex;

    hr = XML_GetFirstChannelElement(m_pIXMLDocument,
                                    &pIXMLElement, &nIndex);

    if (SUCCEEDED(hr))
    {
        ASSERT(pIXMLElement);

        BSTR bstrURL = XML_GetAttribute(pIXMLElement, XML_HREF);

        if (bstrURL)
        {
            VARIANT vNull = {0};
            VARIANT vFlags = {0};

            //
            // check for null string
            //
            if (*bstrURL != 0)
            {
                HWND hwnd = CreateNavigationWorkerWindow(m_hwnd,
                                                         m_pIWebBrowser2);

                if (hwnd)
                {
                    LPOLESTR pszPath = Channel_GetChannelPanePath(
                                                              pszSubscribedURL);

                    if (pszPath)
                        PostMessage(hwnd, WM_NAVIGATE_PANE, 0, (LPARAM)pszPath);

                    PostMessage(hwnd, WM_NAVIGATE, 0, (LPARAM)bstrURL);                    
                    PostMessage(hwnd, WM_CLOSE, 0, 0);
                }
                else
                {
                    SysFreeString(bstrURL);
                }

            }
            else
            {
                 SysFreeString(bstrURL);
            }

        }

        pIXMLElement->Release();
    }

    return hr;
}

HWND
CPersist::CreateNavigationWorkerWindow(
    HWND hwndParent,
    IWebBrowser2* pIWebBrowser2
)
{
    ASSERT(pIWebBrowser2);

    HWND        hwnd;
    static BOOL fRegistered = FALSE;

    if (!fRegistered) {

        WNDCLASS wc = {0};

        wc.lpfnWndProc      = NavigateWndProc;
        wc.cbWndExtra       = SIZEOF(IWebBrowser2*);
        wc.hInstance        = g_hinst;
        wc.hCursor          = LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground    = (HBRUSH) (COLOR_BTNFACE + 1);
        wc.lpszClassName    = TEXT("NavigationWorker");

        fRegistered = (BOOL)RegisterClass(&wc);
    }

    hwnd = CreateWindow(TEXT("NavigationWorker"), NULL, WS_CHILD, 0, 0, 0, 0,
                        hwndParent, (HMENU)0xED, g_hinst, NULL);

    if (hwnd) {

        ASSERT(sizeof(IWebBrowser2*) == sizeof(LONG));
        
        pIWebBrowser2->AddRef();
        SetWindowLongPtr(hwnd, 0, (LRESULT)pIWebBrowser2);
    }

    return hwnd;
}

LRESULT
CALLBACK
NavigateWndProc(
    HWND hwnd,
    UINT msg,
    WPARAM wParam,
    LPARAM lParam
)
{
    LRESULT         lRet = 0;
    IWebBrowser2*   pIWebBrowser2;

    switch (msg)
    {
    case WM_NAVIGATE:
        ASSERT(lParam);

        pIWebBrowser2 = (IWebBrowser2*)GetWindowLongPtr(hwnd, 0);
        
        if (pIWebBrowser2)
        {
            //pIWebBrowser2->put_TheaterMode(-1);
            pIWebBrowser2->put_Visible(-1);

            VARIANT varNull = {0};
            VARIANT varURL;

            varURL.vt      = VT_BSTR;
            varURL.bstrVal = (BSTR)lParam;

            pIWebBrowser2->Navigate2(&varURL, &varNull, &varNull, &varNull,
                                     &varNull);
        }

        SysFreeString((BSTR)lParam);
        break;

    case WM_NAVIGATE_PANE:
        ASSERT(lParam);

        pIWebBrowser2 = (IWebBrowser2*)GetWindowLongPtr(hwnd, 0);
        
        if (pIWebBrowser2)
        {
            if (SUCCEEDED(ShowChannelPane(pIWebBrowser2)))
                NavigateChannelPane(pIWebBrowser2, (LPWSTR)lParam);
        }

        CoTaskMemFree((LPOLESTR)lParam);
        break;

    case WM_CLOSE:
        DestroyWindow(hwnd);
        break;

    case WM_DESTROY:
        pIWebBrowser2 = (IWebBrowser2*)GetWindowLongPtr(hwnd, 0);
        
        if (pIWebBrowser2)
        {
            SetWindowLongPtr(hwnd, 0, 0);
            pIWebBrowser2->Release();
        }
        // Fall through

    default:
        lRet = DefWindowProc(hwnd, msg, wParam, lParam);
        break;
    }

    return lRet;
}
