/*
 * © Copyright 1996-2012 ECMWF.
 *
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 * In applying this licence, ECMWF does not waive the privileges and immunities
 * granted to it by virtue of its status as an intergovernmental organisation nor
 * does it submit to any jurisdiction.
 */

#include "mars.h"

void mars_field_index_add(mars_field_index* idx, const char* name, boolean s_ok, const char* s, boolean l_ok, long l, boolean d_ok, double d) {
    mars_grib_map* m = NEW_CLEAR(mars_grib_map);
    m->name          = strcache(name);
    m->s_ok          = s_ok;
    m->s_value       = strcache(s);
    m->l_ok          = l_ok;
    m->l_value       = l;
    m->d_ok          = d_ok;
    m->d_value       = d;

    if (idx->head == NULL)
        idx->head = m;
    else
        idx->tail->next = m;

    idx->tail = m;
}

mars_field_index* mars_field_index_new(off_t offset, long length) {
    mars_field_index* idx = NEW_CLEAR(mars_field_index);
    idx->offset           = offset;
    idx->length           = length;
    return idx;
}

static void send_map(mstream* s, mars_grib_map* m) {

    while (m) {
        stream_write_int(s, 1);
        stream_write_string(s, m->name);

        stream_write_int(s, m->s_ok);
        if (m->s_ok) {
            stream_write_string(s, m->s_value);
            if (mars.debug) {
                marslog(LOG_DBUG, "metadata %s %s (string)", m->name, m->s_value);
            }
        }

        stream_write_int(s, m->l_ok);
        if (m->l_ok) {
            stream_write_long(s, m->l_value);
            if (mars.debug) {
                marslog(LOG_DBUG, "metadata %s %ld (long)", m->name, m->l_value);
            }
        }
        stream_write_int(s, m->d_ok);
        if (m->d_ok) {
            stream_write_double(s, m->d_value);
            if (mars.debug) {
                marslog(LOG_DBUG, "metadata %s %g (double)", m->name, m->d_value);
            }
        }

        m = m->next;
    }
    stream_write_int(s, 0);
}

err mars_field_index_send(mars_field_index* idx, mstream* s) {
    unsigned long count = 0;
    mars_field_index* p = idx;
    while (p) {
        count++;
        p = p->next;
    }
    stream_write_ulong(s, count);

    p = idx;
    while (p) {
        stream_write_ulonglong(s, p->offset);
        stream_write_ulonglong(s, p->length);

        send_map(s, p->head);

        p = p->next;
    }

    if (s->error) {
        marslog(LOG_EROR, "Error occurred when sending GRIB index to server");
    }

    return s->error;
}

static void free_map(mars_grib_map* m) {
    while (m) {
        mars_grib_map* next = m->next;
        strfree(m->name);
        strfree(m->s_value);
        FREE(m);
        m = next;
    }
}

void mars_field_index_free(mars_field_index* idx) {
    while (idx) {
        mars_field_index* next = idx->next;
        free_map(idx->head);
        FREE(idx);
        idx = next;
    }
}

static void print_map(mars_grib_map* m) {
    while (m) {
        mars_grib_map* next = m->next;
        printf(" %s", m->name);
        if (m->s_ok)
            printf(" s: %s", m->s_value);
        if (m->l_ok)
            printf(" l: %ld", m->l_value);
        if (m->d_ok)
            printf(" d: %g", m->d_value);
        m = next;
    }
}

void mars_field_index_print(mars_field_index* idx) {
    while (idx) {
        mars_field_index* next = idx->next;

        printf("offset = %lld length = %ld", idx->offset, idx->length);
        print_map(idx->head);
        printf("\n");

        idx = next;
    }
}
