/*
 * IMetaDataDispenserEx - dynamic creation/editing of assemblies
 *
 * Copyright 2010 Vincent Povirk for CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdio.h>
#include <stdarg.h>
#include <assert.h>

#define COBJMACROS

#include "wine/library.h"
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "ole2.h"
#include "cor.h"
#include "mscoree.h"
#include "corhdr.h"
#include "cordebug.h"
#include "metahost.h"
#include "wine/list.h"
#include "mscoree_private.h"

#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL( mscoree );

typedef struct MetaDataDispenser
{
    IMetaDataDispenserEx IMetaDataDispenserEx_iface;
    LONG ref;
} MetaDataDispenser;

static inline MetaDataDispenser *impl_from_IMetaDataDispenserEx(IMetaDataDispenserEx *iface)
{
    return CONTAINING_RECORD(iface, MetaDataDispenser, IMetaDataDispenserEx_iface);
}

static HRESULT WINAPI MetaDataDispenser_QueryInterface(IMetaDataDispenserEx* iface,
    REFIID riid, void **ppvObject)
{
    TRACE("%p %s %p\n", iface, debugstr_guid(riid), ppvObject);

    if (IsEqualGUID(riid, &IID_IMetaDataDispenserEx) ||
        IsEqualGUID(riid, &IID_IMetaDataDispenser) ||
        IsEqualGUID(riid, &IID_IUnknown))
    {
        *ppvObject = iface;
    }
    else
    {
        FIXME("Unsupported interface %s\n", debugstr_guid(riid));
        return E_NOINTERFACE;
    }

    IMetaDataDispenserEx_AddRef( iface );

    return S_OK;
}

static ULONG WINAPI MetaDataDispenser_AddRef(IMetaDataDispenserEx* iface)
{
    MetaDataDispenser *This = impl_from_IMetaDataDispenserEx(iface);
    ULONG ref = InterlockedIncrement(&This->ref);

    TRACE("%p ref=%u\n", This, ref);

    return ref;
}

static ULONG WINAPI MetaDataDispenser_Release(IMetaDataDispenserEx* iface)
{
    MetaDataDispenser *This = impl_from_IMetaDataDispenserEx(iface);
    ULONG ref = InterlockedDecrement(&This->ref);

    TRACE("%p ref=%u\n", This, ref);

    if (ref == 0)
    {
        HeapFree(GetProcessHeap(), 0, This);
    }

    return ref;
}

static HRESULT WINAPI MetaDataDispenser_DefineScope(IMetaDataDispenserEx* iface,
    REFCLSID rclsid, DWORD dwCreateFlags, REFIID riid, IUnknown **ppIUnk)
{
    FIXME("%p %s %x %s %p\n", iface, debugstr_guid(rclsid), dwCreateFlags,
        debugstr_guid(riid), ppIUnk);
    return E_NOTIMPL;
}

static HRESULT WINAPI MetaDataDispenser_OpenScope(IMetaDataDispenserEx* iface,
    LPCWSTR szScope, DWORD dwOpenFlags, REFIID riid, IUnknown **ppIUnk)
{
    FIXME("%p %s %x %s %p\n", iface, debugstr_w(szScope), dwOpenFlags,
        debugstr_guid(riid), ppIUnk);
    return E_NOTIMPL;
}

static HRESULT WINAPI MetaDataDispenser_OpenScopeOnMemory(IMetaDataDispenserEx* iface,
    const void *pData, ULONG cbData, DWORD dwOpenFlags, REFIID riid, IUnknown **ppIUnk)
{
    FIXME("%p %p %u %x %s %p\n", iface, pData, cbData, dwOpenFlags,
        debugstr_guid(riid), ppIUnk);
    return E_NOTIMPL;
}

static HRESULT WINAPI MetaDataDispenser_SetOption(IMetaDataDispenserEx* iface,
    REFGUID optionid, const VARIANT *value)
{
    FIXME("%p %s\n", iface, debugstr_guid(optionid));
    return E_NOTIMPL;
}

static HRESULT WINAPI MetaDataDispenser_GetOption(IMetaDataDispenserEx* iface,
    REFGUID optionid, VARIANT *pvalue)
{
    FIXME("%p %s\n", iface, debugstr_guid(optionid));
    return E_NOTIMPL;
}

static HRESULT WINAPI MetaDataDispenser_OpenScopeOnITypeInfo(IMetaDataDispenserEx* iface,
    ITypeInfo *pITI, DWORD dwOpenFlags, REFIID riid, IUnknown **ppIUnk)
{
    FIXME("%p %p %u %s %p\n", iface, pITI, dwOpenFlags, debugstr_guid(riid), ppIUnk);
    return E_NOTIMPL;
}

static HRESULT WINAPI MetaDataDispenser_GetCORSystemDirectory(IMetaDataDispenserEx* iface,
    LPWSTR szBuffer, DWORD cchBuffer, DWORD *pchBuffer)
{
    FIXME("%p %p %u %p\n", iface, szBuffer, cchBuffer, pchBuffer);
    return E_NOTIMPL;
}

static HRESULT WINAPI MetaDataDispenser_FindAssembly(IMetaDataDispenserEx* iface,
    LPCWSTR szAppBase, LPCWSTR szPrivateBin, LPCWSTR szGlobalBin, LPCWSTR szAssemblyName,
    LPWSTR szName, ULONG cchName, ULONG *pcName)
{
    FIXME("%p %s %s %s %s %p %u %p\n", iface, debugstr_w(szAppBase),
        debugstr_w(szPrivateBin), debugstr_w(szGlobalBin),
        debugstr_w(szAssemblyName), szName, cchName, pcName);
    return E_NOTIMPL;
}

static HRESULT WINAPI MetaDataDispenser_FindAssemblyModule(IMetaDataDispenserEx* iface,
    LPCWSTR szAppBase, LPCWSTR szPrivateBin, LPCWSTR szGlobalBin, LPCWSTR szAssemblyName,
    LPCWSTR szModuleName, LPWSTR szName, ULONG cchName, ULONG *pcName)
{
    FIXME("%p %s %s %s %s %s %p %u %p\n", iface, debugstr_w(szAppBase),
        debugstr_w(szPrivateBin), debugstr_w(szGlobalBin), debugstr_w(szAssemblyName),
        debugstr_w(szModuleName), szName, cchName, pcName);
    return E_NOTIMPL;
}

static const struct IMetaDataDispenserExVtbl MetaDataDispenserVtbl =
{
    MetaDataDispenser_QueryInterface,
    MetaDataDispenser_AddRef,
    MetaDataDispenser_Release,
    MetaDataDispenser_DefineScope,
    MetaDataDispenser_OpenScope,
    MetaDataDispenser_OpenScopeOnMemory,
    MetaDataDispenser_SetOption,
    MetaDataDispenser_GetOption,
    MetaDataDispenser_OpenScopeOnITypeInfo,
    MetaDataDispenser_GetCORSystemDirectory,
    MetaDataDispenser_FindAssembly,
    MetaDataDispenser_FindAssemblyModule
};

HRESULT MetaDataDispenser_CreateInstance(IUnknown **ppUnk)
{
    MetaDataDispenser *This;

    This = HeapAlloc(GetProcessHeap(), 0, sizeof(MetaDataDispenser));

    if (!This)
        return E_OUTOFMEMORY;

    This->IMetaDataDispenserEx_iface.lpVtbl = &MetaDataDispenserVtbl;
    This->ref = 1;

    *ppUnk = (IUnknown*)&This->IMetaDataDispenserEx_iface;

    return S_OK;
}