/*
 * Implementation of class factory for IE Web Browser
 *
 * 2001 John R. Sheets (for CodeWeavers)
 *
 * Copyright (c) 2003 TransGaming Technologies
 * david@transgaming.com
 */

#include <string.h>
#include <stdio.h>

#include "winreg.h"
#include "winbase.h"
#include "winuser.h"
#include "wine/debug.h"
#include "shdocvw.h"

#include "wine/unicode.h"

#include "initguid.h"

WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);

#define USE_MOZILLA_CONTROL 1

/* mozilla control stuff */

#ifdef USE_MOZILLA_CONTROL

DEFINE_GUID(CLSID_MozillaBrowser, 0x1339B54C,0x3453,0x11D2,0x93, 0xB9, 0x00, 0x00,0x00, 0x00, 0x00, 0x00);

typedef HRESULT (WINAPI *fnGetClassObject)(REFCLSID rclsid, REFIID iid, LPVOID *ppv);

HMODULE hMozCtl = (HMODULE)-1;

/* convert a guid to a wide character string */
static void SHDOCVW_guid2wstr(const GUID *guid, LPWSTR wstr)
{
    char str[40];

    sprintf(str, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
            guid->Data1, guid->Data2, guid->Data3,
            guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
            guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
    MultiByteToWideChar(CP_ACP, 0, str, -1, wstr, 40);
}

static BOOL SHDOCVW_GetMozctlPath(LPWSTR szPath, DWORD sz)
{
    DWORD r, type;
    BOOL ret = FALSE;
    HKEY hkey;
    const WCHAR szPre[] = {
        'S','o','f','t','w','a','r','e','\\',
        'C','l','a','s','s','e','s','\\',
        'C','L','S','I','D','\\',0};
    const WCHAR szPost[] = {
        '\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
    WCHAR szRegPath[(sizeof(szPre)+sizeof(szPost))/sizeof(WCHAR)+40];

    strcpyW(szRegPath, szPre);
    SHDOCVW_guid2wstr(&CLSID_MozillaBrowser, &szRegPath[strlenW(szRegPath)]);
    strcatW(szRegPath, szPost);

    TRACE("key = %s\n", debugstr_w(szRegPath));

    r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szRegPath, &hkey);
    if (r != ERROR_SUCCESS)
        return FALSE;

    r = RegQueryValueExW(hkey, NULL, NULL, &type, (LPBYTE)szPath, &sz);
    ret = (r == ERROR_SUCCESS) && (type == REG_SZ);
    RegCloseKey(hkey);

    return ret;
}

static BOOL SHDOCVW_TryLoadMozillaControl()
{
    WCHAR szPath[MAX_PATH];

    if (hMozCtl != (HMODULE)-1)
        return hMozCtl ? TRUE : FALSE;

    if (!SHDOCVW_GetMozctlPath(szPath, sizeof(szPath)))
    {
        MESSAGE("You need to install the Mozilla ActiveX control to\n"
                "be able to view webpages in this application\n");
        return FALSE;
    }

    TRACE("trying to load dll '%s'\n", debugstr_w(szPath));
    hMozCtl = LoadLibraryExW(szPath, (HANDLE)NULL, LOAD_WITH_ALTERED_SEARCH_PATH);

    if (!hMozCtl)
    {
        ERR("Can't load the Mozilla ActiveX control\n");
        return FALSE;
    }

    return TRUE;
}

#endif /* USE_MOZILLA_CONTROL */


/**********************************************************************
 * Implement the IWebBrowser class factory
 */

typedef struct
{
    /* IUnknown fields */
    ICOM_VFIELD(IClassFactory);
    DWORD ref;
    /* IClassFactory fields */
    HRESULT (*pfnCreateInstance)(IUnknown *pOuter, REFIID riid,
                                 LPVOID *ppobj);
} IClassFactoryImpl;


/**********************************************************************
 * WBCF_QueryInterface (IUnknown)
 */
static HRESULT WINAPI WBCF_QueryInterface(LPCLASSFACTORY iface,
                                          REFIID riid, LPVOID *ppobj)
{
    ICOM_THIS(IClassFactoryImpl, iface);

    FIXME("(%p)->(%s, %p): stub\n", iface, debugstr_guid(riid), ppobj);

    /*
     * Perform a sanity check on the parameters.
     */
    if ((This == NULL) || (ppobj == NULL) )
        return E_INVALIDARG;

    return E_NOINTERFACE;
}

/************************************************************************
 * WBCF_AddRef (IUnknown)
 */
static ULONG WINAPI WBCF_AddRef(LPCLASSFACTORY iface)
{
    ICOM_THIS(IClassFactoryImpl, iface);

    TRACE("(%p)->()\n", iface);

    return ++(This->ref);
}

/************************************************************************
 * WBCF_Release (IUnknown)
 */
static ULONG WINAPI WBCF_Release(LPCLASSFACTORY iface)
{
    ICOM_THIS(IClassFactoryImpl, iface);

    TRACE("(%p)->()\n", iface);

    /* static class, won't be freed */
    return --(This->ref);
}

/************************************************************************
 * WBCF_CreateInstance (IClassFactory)
 */
static HRESULT WINAPI WBCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter,
                                          REFIID riid, LPVOID *ppobj)
{
    ICOM_THIS(IClassFactoryImpl, iface);

    TRACE("(%p)->(%p,%s,%p)\n", iface, pOuter, debugstr_guid(riid), ppobj);

    /* Don't support aggregation (yet?) */
    if (pOuter)
    {
        TRACE ("Failed attempt to aggregate IWebBrowser\n");
        return CLASS_E_NOAGGREGATION;
    }

    return This->pfnCreateInstance(pOuter, riid, ppobj);
}

/************************************************************************
 * WBCF_LockServer (IClassFactory)
 */
static HRESULT WINAPI WBCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
{
    /*ICOM_THIS(IClassFactoryImpl, iface);*/
    FIXME("(%p)->(%d),stub!\n", iface, dolock);
    return S_OK;
}

static ICOM_VTABLE(IClassFactory) WBCF_Vtbl =
{
    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
    WBCF_QueryInterface,
    WBCF_AddRef,
    WBCF_Release,
    WBCF_CreateInstance,
    WBCF_LockServer
};

static IClassFactoryImpl SHDOCVW_CF_WebBrowser = { &WBCF_Vtbl, 1, SHDOCVW_CreateWebBrowser };


/*************************************************************************
 *              DllGetClassObject (SHDOCVW.@)
 */
HRESULT WINAPI SHDOCVW_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
    TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);

#ifdef USE_MOZILLA_CONTROL
    if (IsEqualGUID(&CLSID_WebBrowser, rclsid) &&
            SHDOCVW_TryLoadMozillaControl())
    {
        HRESULT r;
        fnGetClassObject pGetClassObject;

        TRACE("using Mozilla control\n");
        TRACE("WebBrowser class %s, riid %s\n", debugstr_guid(rclsid),
                debugstr_guid(riid));

        pGetClassObject = (fnGetClassObject)
            GetProcAddress(hMozCtl, "DllGetClassObject");

        if (!pGetClassObject)
            return CLASS_E_CLASSNOTAVAILABLE;
        *ppv = NULL;
        r = pGetClassObject(&CLSID_MozillaBrowser, riid, ppv);

        TRACE("r = %08lx, *ppv = %p\n", r, *ppv);

        return r;
    }
#endif /* USE_MOZILLA_CONTROL */

    if (!IsEqualGUID(riid, &IID_IClassFactory) &&
        !IsEqualGUID(riid, &IID_IUnknown))
    {
        ERR("(%s, %s, %p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
        return CLASS_E_CLASSNOTAVAILABLE;
    }

    if (IsEqualGUID(rclsid, &CLSID_WebBrowser))
    {
        *ppv = &SHDOCVW_CF_WebBrowser;
        WBCF_AddRef((IClassFactory*)*ppv);
        return S_OK;
    }

    ERR("(%s, %s, %p): no class found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
    return CLASS_E_CLASSNOTAVAILABLE;
}

