/*
 * XML Parser implementation
 *
 * Copyright 2011 Alistair Leslie-Hughes
 *
 * 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
 */
#define COBJMACROS

#include "config.h"

#include <stdarg.h>
#ifdef HAVE_LIBXML2
# include <libxml/parser.h>
# include <libxml/xmlerror.h>
# include <libxml/HTMLtree.h>
#endif

#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "ole2.h"
#include "msxml6.h"

#include "msxml_private.h"

#include "initguid.h"
#include "xmlparser.h"

#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(msxml);

typedef struct _xmlparser
{
    IXMLParser IXMLParser_iface;
    IXMLNodeFactory *nodefactory;
    IUnknown *input;
    LONG ref;

    int flags;
    XML_PARSER_STATE state;
} xmlparser;

static inline xmlparser *impl_from_IXMLParser( IXMLParser *iface )
{
    return CONTAINING_RECORD(iface, xmlparser, IXMLParser_iface);
}

/*** IUnknown methods ***/
static HRESULT WINAPI xmlparser_QueryInterface(IXMLParser* iface, REFIID riid, void **ppvObject)
{
    xmlparser *This = impl_from_IXMLParser( iface );
    TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);

    if ( IsEqualGUID( riid, &IID_IXMLParser ) ||
         IsEqualGUID( riid, &IID_IXMLNodeSource ) ||
         IsEqualGUID( riid, &IID_IUnknown ) )
    {
        *ppvObject = iface;
    }
    else
    {
        TRACE("Unsupported interface %s\n", debugstr_guid(riid));
        *ppvObject = NULL;
        return E_NOINTERFACE;
    }

    IXMLParser_AddRef(iface);
    return S_OK;
}

static ULONG WINAPI xmlparser_AddRef(IXMLParser* iface)
{
    xmlparser *This = impl_from_IXMLParser( iface );
    ULONG ref = InterlockedIncrement( &This->ref );
    TRACE("(%p)->(%d)\n", This, ref);
    return ref;
}

static ULONG WINAPI xmlparser_Release(IXMLParser* iface)
{
    xmlparser *This = impl_from_IXMLParser( iface );
    ULONG ref = InterlockedDecrement( &This->ref );

    TRACE("(%p)->(%d)\n", This, ref);
    if ( ref == 0 )
    {
        if(This->input)
            IUnknown_Release(This->input);

        if(This->nodefactory)
            IXMLNodeFactory_Release(This->nodefactory);

        heap_free( This );
    }

    return ref;
}

/*** IXMLNodeSource methods ***/
static HRESULT WINAPI xmlparser_SetFactory(IXMLParser *iface, IXMLNodeFactory *pNodeFactory)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    TRACE("(%p %p)\n", This, pNodeFactory);

    if(This->nodefactory)
        IXMLNodeFactory_Release(This->nodefactory);

    This->nodefactory = pNodeFactory;
    if(This->nodefactory)
        IXMLNodeFactory_AddRef(This->nodefactory);

    return S_OK;
}

static HRESULT WINAPI xmlparser_GetFactory(IXMLParser *iface, IXMLNodeFactory **ppNodeFactory)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    TRACE("(%p, %p)\n", This, ppNodeFactory);

    if(!ppNodeFactory)
        return E_INVALIDARG;

    *ppNodeFactory = This->nodefactory;

    if(*ppNodeFactory)
        IXMLNodeFactory_AddRef(*ppNodeFactory);

    return S_OK;
}

static HRESULT WINAPI xmlparser_Abort(IXMLParser *iface, BSTR bstrErrorInfo)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p, %s)\n", This, debugstr_w(bstrErrorInfo));

    return E_NOTIMPL;
}

static ULONG WINAPI xmlparser_GetLineNumber(IXMLParser *iface)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p)\n", This);

    return 0;
}

static ULONG WINAPI xmlparser_GetLinePosition(IXMLParser *iface)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p)\n", This);

    return 0;
}

static ULONG WINAPI xmlparser_GetAbsolutePosition(IXMLParser *iface)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p)\n", This);

    return 0;
}

static HRESULT WINAPI xmlparser_GetLineBuffer(IXMLParser *iface, const WCHAR **ppBuf,
                ULONG *len, ULONG *startPos)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p %p %p %p)\n", This, ppBuf, len, startPos);

    return 0;
}

static HRESULT WINAPI xmlparser_GetLastError(IXMLParser *iface)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p)\n", This);

    return E_NOTIMPL;
}

static HRESULT WINAPI xmlparser_GetErrorInfo(IXMLParser *iface, BSTR *pErrorInfo)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p %p)\n", This, pErrorInfo);

    return E_NOTIMPL;
}

static ULONG WINAPI xmlparser_GetFlags(IXMLParser *iface)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    TRACE("(%p)\n", This);

    return This->flags;
}

static HRESULT WINAPI xmlparser_GetURL(IXMLParser *iface, const WCHAR **ppBuf)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p %p)\n", This, ppBuf);

    return E_NOTIMPL;
}

/*** IXMLParser methods ***/
static HRESULT WINAPI xmlparser_SetURL(IXMLParser *iface,const WCHAR *pszBaseUrl,
                const WCHAR *relativeUrl, BOOL async)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p %s %s %d)\n", This, debugstr_w(pszBaseUrl), debugstr_w(relativeUrl), async);

    return E_NOTIMPL;
}

static HRESULT WINAPI xmlparser_Load(IXMLParser *iface, BOOL bFullyAvailable,
                IMoniker *pMon, LPBC pBC, DWORD dwMode)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p %d %p %p %d)\n", This, bFullyAvailable, pMon, pBC, dwMode);

    return E_NOTIMPL;
}

static HRESULT WINAPI xmlparser_SetInput(IXMLParser *iface, IUnknown *pStm)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    TRACE("(%p %p)\n", This, pStm);

    if(!pStm)
        return E_INVALIDARG;

    if(This->input)
        IUnknown_Release(This->input);

    This->input = pStm;
    IUnknown_AddRef(This->input);

    return S_OK;
}

static HRESULT WINAPI xmlparser_PushData(IXMLParser *iface, const char *pData,
                ULONG nChars, BOOL fLastBuffer)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p %s %d %d)\n", This, debugstr_a(pData), nChars, fLastBuffer);

    return E_NOTIMPL;
}

static HRESULT WINAPI xmlparser_LoadDTD(IXMLParser *iface, const WCHAR *baseUrl,
                const WCHAR *relativeUrl)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p %s %s)\n", This, debugstr_w(baseUrl), debugstr_w(relativeUrl));

    return E_NOTIMPL;
}

static HRESULT WINAPI xmlparser_LoadEntity(IXMLParser *iface, const WCHAR *baseUrl,
                const WCHAR *relativeUrl, BOOL fpe)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p %s %s %d)\n", This, debugstr_w(baseUrl), debugstr_w(relativeUrl), fpe);

    return E_NOTIMPL;
}

static HRESULT WINAPI xmlparser_ParseEntity(IXMLParser *iface, const WCHAR *text,
                ULONG len, BOOL fpe)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p %s %d %d)\n", This, debugstr_w(text), len, fpe);

    return E_NOTIMPL;
}

static HRESULT WINAPI xmlparser_ExpandEntity(IXMLParser *iface, const WCHAR *text,
                ULONG len)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p %s %d)\n", This, debugstr_w(text), len);

    return E_NOTIMPL;
}

static HRESULT WINAPI xmlparser_SetRoot(IXMLParser *iface, PVOID pRoot)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p %p)\n", This, pRoot);

    return E_NOTIMPL;
}

static HRESULT WINAPI xmlparser_GetRoot( IXMLParser *iface, PVOID *ppRoot)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p %p)\n", This, ppRoot);

    return E_NOTIMPL;
}

static HRESULT WINAPI xmlparser_Run(IXMLParser *iface, LONG chars)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p %d)\n", This, chars);

    return E_NOTIMPL;
}

static HRESULT WINAPI xmlparser_GetParserState(IXMLParser *iface)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    TRACE("(%p)\n", This);

    return This->state;
}

static HRESULT WINAPI xmlparser_Suspend(IXMLParser *iface)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p)\n", This);

    return E_NOTIMPL;
}

static HRESULT WINAPI xmlparser_Reset(IXMLParser *iface)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p)\n", This);

    return E_NOTIMPL;
}

static HRESULT WINAPI xmlparser_SetFlags(IXMLParser *iface, ULONG flags)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    TRACE("(%p %d)\n", This, flags);

    This->flags = flags;

    return S_OK;
}

static HRESULT WINAPI xmlparser_SetSecureBaseURL(IXMLParser *iface, const WCHAR *baseUrl)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p %s)\n", This, debugstr_w(baseUrl));

    return E_NOTIMPL;
}

static HRESULT WINAPI xmlparser_GetSecureBaseURL( IXMLParser *iface, const WCHAR **ppBuf)
{
    xmlparser *This = impl_from_IXMLParser( iface );

    FIXME("(%p %p)\n", This, ppBuf);

    return E_NOTIMPL;
}


static const struct IXMLParserVtbl xmlparser_vtbl =
{
    xmlparser_QueryInterface,
    xmlparser_AddRef,
    xmlparser_Release,
    xmlparser_SetFactory,
    xmlparser_GetFactory,
    xmlparser_Abort,
    xmlparser_GetLineNumber,
    xmlparser_GetLinePosition,
    xmlparser_GetAbsolutePosition,
    xmlparser_GetLineBuffer,
    xmlparser_GetLastError,
    xmlparser_GetErrorInfo,
    xmlparser_GetFlags,
    xmlparser_GetURL,
    xmlparser_SetURL,
    xmlparser_Load,
    xmlparser_SetInput,
    xmlparser_PushData,
    xmlparser_LoadDTD,
    xmlparser_LoadEntity,
    xmlparser_ParseEntity,
    xmlparser_ExpandEntity,
    xmlparser_SetRoot,
    xmlparser_GetRoot,
    xmlparser_Run,
    xmlparser_GetParserState,
    xmlparser_Suspend,
    xmlparser_Reset,
    xmlparser_SetFlags,
    xmlparser_SetSecureBaseURL,
    xmlparser_GetSecureBaseURL
};

HRESULT XMLParser_create(void **ppObj)
{
    xmlparser *This;

    TRACE("(%p)\n", ppObj);

    This = heap_alloc( sizeof(xmlparser) );
    if(!This)
        return E_OUTOFMEMORY;

    This->IXMLParser_iface.lpVtbl = &xmlparser_vtbl;
    This->nodefactory = NULL;
    This->input = NULL;
    This->flags = 0;
    This->state = XMLPARSER_IDLE;
    This->ref = 1;

    *ppObj = &This->IXMLParser_iface;

    TRACE("returning iface %p\n", *ppObj);

    return S_OK;
}