/* This file is part of the YAZ toolkit.
 * Copyright (C) Index Data
 * See the file LICENSE for details.
 */

/**
 * \file marc_read_json.c
 * \brief Implements reading of MARC in JSON format
 */

#if HAVE_CONFIG_H
#include <config.h>
#endif

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

#include <yaz/marcdisp.h>
#include <yaz/json.h>
#include <yaz/yaz-util.h>

static void parse_subfields(yaz_marc_t mt, struct json_node *sf, WRBUF wtmp)
{
    assert(sf->type == json_node_list);
    for (; sf; sf = sf->u.link[1])
    {
        if (sf->u.link[0]->type == json_node_object &&
            sf->u.link[0]->u.link[0]->type == json_node_list)
        {
            struct json_node *se = sf->u.link[0]->u.link[0];
            for (; se; se = se->u.link[1])
            {
                if (se->u.link[0]->type == json_node_pair
                    && se->u.link[0]->u.link[0]->type == json_node_string
                    && se->u.link[0]->u.link[1]->type == json_node_string)
                {
                    wrbuf_rewind(wtmp);
                    wrbuf_puts(wtmp, se->u.link[0]->u.link[0]->u.string);
                    wrbuf_puts(wtmp, se->u.link[0]->u.link[1]->u.string);
                    yaz_marc_add_subfield(mt, wrbuf_buf(wtmp), wrbuf_len(wtmp));
                }
            }
        }
    }
}

static void parse_field(yaz_marc_t mt, struct json_node *p,
                        int indicator_length, WRBUF wtmp)
{
    if (p->type == json_node_pair && p->u.link[0]->type == json_node_string)
    {
        struct json_node *l = p->u.link[1];
        if (l->type == json_node_string)
        {
            yaz_marc_add_controlfield(mt, p->u.link[0]->u.string,
                                      l->u.string, strlen(l->u.string));
        }
        else if (l->type == json_node_object &&
                 l->u.link[0]->type == json_node_list)
        {
            struct json_node *m;
            int j;
            wrbuf_rewind(wtmp);
            for (j = 1; j <= indicator_length; j++)
            {
                for (m = l->u.link[0]; m; m = m->u.link[1])
                {
                    struct json_node *s = m->u.link[0];
                    if (s->type == json_node_pair)
                    {
                        if (s->u.link[0]->type == json_node_string
                            && !strncmp(s->u.link[0]->u.string, "ind", 3)
                            && s->u.link[0]->u.string[3] == '0' + j
                            && s->u.link[1]->type == json_node_string)
                        {
                            wrbuf_puts(wtmp, s->u.link[1]->u.string);
                        }
                    }
                }
            }
            yaz_marc_add_datafield(mt, p->u.link[0]->u.string,
                                   wrbuf_cstr(wtmp), wrbuf_len(wtmp));
            for (m = l->u.link[0]; m; m = m->u.link[1])
            {
                struct json_node *s = m->u.link[0];
                if (s->type == json_node_pair)
                {
                    if (s->u.link[0]->type == json_node_string
                        && !strcmp(s->u.link[0]->u.string, "subfields")
                        && s->u.link[1]->type == json_node_array)
                    {
                        parse_subfields(mt, s->u.link[1]->u.link[0], wtmp);
                    }
                }
            }
        }
    }
}

int yaz_marc_read_json_node(yaz_marc_t mt, struct json_node *n)
{
    if (n && n->type == json_node_object)
    {
        int indicator_length;
        int identifier_length;
        int base_address;
        int length_data_entry;
        int length_starting;
        int length_implementation;
        struct json_node *l;
        WRBUF wtmp = wrbuf_alloc();
        const char *leader = 0;
        for (l = n->u.link[0]; l; l = l->u.link[1])
        {
            if (l->u.link[0]->type == json_node_pair &&
                l->u.link[0]->u.link[0]->type == json_node_string)
            {
                struct json_node *p = l->u.link[0];
                if (!strcmp(p->u.link[0]->u.string, "leader") &&
                    p->u.link[1]->type == json_node_string &&
                    strlen(p->u.link[1]->u.string) == 24)
                {
                    leader = p->u.link[1]->u.string;
                }
            }
        }
        if (!leader)
        {
            yaz_marc_cprintf(mt, "Missing leader. Inserting fake leader");
            leader = "00000nam a22000000a 4500";
        }
        yaz_marc_set_leader(mt, leader,
                            &indicator_length,
                            &identifier_length,
                            &base_address,
                            &length_data_entry,
                            &length_starting,
                            &length_implementation);
        for (l = n->u.link[0]; l; l = l->u.link[1])
        {
            if (l->u.link[0]->type == json_node_pair &&
                l->u.link[0]->u.link[0]->type == json_node_string)
            {
                struct json_node *p = l->u.link[0];
                if (!strcmp(p->u.link[0]->u.string, "fields") &&
                    p->u.link[1]->type == json_node_array &&
                    p->u.link[1]->u.link[0] &&
                    p->u.link[1]->u.link[0]->type == json_node_list)
                {
                    struct json_node *l;
                    for (l = p->u.link[1]->u.link[0]; l; l = l->u.link[1])
                    {
                        if (l->u.link[0]->type == json_node_object)
                        {
                            if (l->u.link[0]->u.link[0] &&
                                l->u.link[0]->u.link[0]->type == json_node_list)
                            {
                                struct json_node *m = l->u.link[0]->u.link[0];
                                for (; m; m = m->u.link[1])
                                    parse_field(mt, m->u.link[0],
                                                indicator_length, wtmp);
                            }
                        }
                    }
                }
            }
        }
        wrbuf_destroy(wtmp);
        return 0;
    }
    return -1;
}

/*
 * Local variables:
 * c-basic-offset: 4
 * c-file-style: "Stroustrup"
 * indent-tabs-mode: nil
 * End:
 * vim: shiftwidth=4 tabstop=8 expandtab
 */

