/* This file is part of the YAZ toolkit.
 * Copyright (C) Index Data
 * See the file LICENSE for details.
 */
#if HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdlib.h>
#include <stdio.h>

#include <yaz/options.h>
#include <yaz/querytowrbuf.h>
#include <yaz/xmlquery.h>
#include <yaz/pquery.h>
#include <yaz/backtrace.h>

#if YAZ_HAVE_XML2
#include <libxml/parser.h>
#endif

static char *prog = "yaz-xmlquery";

#if YAZ_HAVE_XML2
void pqftoxmlquery(const char *pqf)
{
    YAZ_PQF_Parser parser = yaz_pqf_create();
    ODR odr = odr_createmem(ODR_ENCODE);
    Z_RPNQuery *rpn;

    if (!parser)
    {
        fprintf(stderr, "%s: cannot create parser\n", prog);
        exit(1);
    }

    if (!odr)
    {
        fprintf(stderr, "%s: cannot create parser\n", prog);
        exit(1);
    }

    rpn = yaz_pqf_parse(parser, odr, pqf);

    yaz_pqf_destroy(parser);

    if (!rpn)
    {
        fprintf(stderr, "%s: pqf parse error for query %s\n", prog, pqf);
        exit(2);
    }
    else
    {
        xmlDocPtr doc = 0;

        yaz_rpnquery2xml(rpn, &doc);

        if (!doc)
        {
            fprintf(stderr, "%s: yaz_rpnquery2xml failed for query %s\n",
                    prog, pqf);
            exit(3);
        }
        else
        {
            xmlChar *buf_out = 0;
            int len_out = 0;

            xmlDocDumpMemory(doc, &buf_out, &len_out);

            if (!len_out || !buf_out)
            {
                fprintf(stderr, "%s: xmlDocDumpMemory failed for query %s\n",
                        prog, pqf);
                exit(4);
            }
            else
            {
                if (fwrite(buf_out, len_out, 1, stdout) != 1)
                {
                    fprintf(stderr, "%s: write failed\n", prog);
                    exit(5);
                }
            }
            xmlFreeDoc(doc);
        }
    }
    odr_destroy(odr);
}


void xmlquerytopqf(const char *xmlstr)
{
    xmlDocPtr doc;

    doc = xmlParseMemory(xmlstr, strlen(xmlstr));
    if (!doc)
    {
        fprintf(stderr, "%s: xml parse error for XML:\n%s\n", prog, xmlstr);
        exit(1);
    }
    else
    {
        int error_code = 0;
        const char *addinfo = 0;
        Z_Query *query = 0;
        ODR odr = odr_createmem(ODR_ENCODE);

        const xmlNode *root_element = xmlDocGetRootElement(doc);
        yaz_xml2query(root_element, &query, odr, &error_code, &addinfo);
        if (error_code)
        {
            fprintf(stderr, "%s: yaz_xml2query failed code=%d addinfo=%s\n",
                    prog, error_code, addinfo);
            exit(1);
        }
        else if (!query)
        {
            fprintf(stderr, "%s: yaz_xml2query no query result\n",
                    prog);
            exit(1);
        }
        else
        {
            WRBUF w = wrbuf_alloc();
            yaz_query_to_wrbuf(w, query);
            printf("%s\n", wrbuf_cstr(w));
            wrbuf_destroy(w);
        }
        odr_destroy(odr);
        xmlFreeDoc(doc);
    }
}

void xmlfiletopqf(const char *xmlfile)
{
    long sz;
    char *xmlstr;
    FILE *f = fopen(xmlfile, "rb");
    if (!f)
    {
        fprintf(stderr, "%s: cannot open %s\n", prog, xmlfile);
        exit(1);
    }
    fseek(f, 0, SEEK_END);
    sz = ftell(f);
    if (sz <= 0 || sz >= 1<<18)
    {
        fprintf(stderr, "%s: bad size for file %s\n", prog, xmlfile);
        exit(1);
    }
    rewind(f);
    xmlstr = (char *) xmalloc(sz+1);
    xmlstr[sz] = '\0';
    if (fread(xmlstr, sz, 1, f) != 1)
    {
        fprintf(stderr, "%s: read failed for file %s\n", prog, xmlfile);
        exit(1);
    }
    if (fclose(f))
    {
        fprintf(stderr, "%s: close failed for file %s\n", prog, xmlfile);
        exit(1);
    }

    xmlquerytopqf(xmlstr);
    xfree(xmlstr);
}
#endif

void usage(void)
{
    fprintf(stderr, "%s [-p pqf] [-x xmlfile]\n", prog);
    fprintf(stderr, " -p pqf      reads pqf. write xml to stdout\n");
    fprintf(stderr, " -x xmlfile  reads XML from file. write pqf to stdout\n");
    exit(1);
}

int main (int argc, char **argv)
{
#if YAZ_HAVE_XML2
    char *arg;
    int r;
    int active = 0;

    yaz_enable_panic_backtrace(*argv);
    while ((r = options("-p:x:", argv, argc, &arg)) != -2)
    {
        switch(r)
        {
        case 'p':
            pqftoxmlquery(arg);
            active = 1;
            break;
        case 'x':
            xmlfiletopqf(arg);
            active = 1;
            break;
        case 0:
            break;
        }
    }
    if (!active)
    {
        fprintf(stderr, "%s: nothing to do\n", prog);
        usage();
    }
#else
    fprintf(stderr, "%s: XML support not enabled.\n", prog);
    exit(1);
#endif
    return 0;
}

