/*
 * © 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 <stdio.h>
#include "mars.h"

#define SIZE ((int)4097)

typedef struct hashrec {
    struct hashrec* next;
    char* name;
    int cnt;
} hashrec;

static hashrec* table[SIZE] = {
    NULL,
};


static int hash(const char* name) {
    int n = 0;

    while (*name)
        n += (*name++ - 'A') + (n << 5);

#ifdef CRAY
    if (n < 0)
        n = -n;
#else
    if (n < 0) {
        int m = -n / SIZE;
        n += (m + 1) * SIZE;
    }
#endif
    return n % SIZE;
}

void hash_stat() {
    int i;
    int a = 0, b = 0, c = 0;
    hashrec* h;

    printf("Table size is %d. ", SIZE);

    for (i = 0; i < SIZE; i++)
        if ((h = table[i])) {
            a++;
            while (h) {
                b++;
                c += h->cnt;
                h = h->next;
            };
        }

    printf("Used: %d, Total: %d, Strings: %d\n", a, b, c);
}

char* strcache(const char* name) {
    hashrec* h;
    int n;

    if (name == NULL)
        return NULL;

    n = hash(name);
    h = table[n];

    while (h) {
        if (EQ(h->name, name)) {
            h->cnt++;
            return h->name;
        }
        h = h->next;
    }

    h        = NEW(hashrec);
    h->name  = NEW_STRING(name);
    h->next  = table[n];
    h->cnt   = 1;
    table[n] = h;

    return h->name;
}

void strfree(char* name) {

    hashrec* h;
    hashrec* p = NULL;
    int n;

    if (name == NULL)
        return;

    n = hash(name);
    h = table[n];

    while (h) {
        if (h->name == name) {
            h->cnt--;
            break;
        }
        p = h;
        h = h->next;
    }

    if (h == NULL) {
        marslog(LOG_WARN, "%s was not in hash table", name);
        abort();
        printf("n=%d\n", n);
        h = table[n];
        while (h) {
            printf("%s %d\n", h->name, h->cnt);
            h = h->next;
        }
        return;
    }

    if (h->cnt == 0) {
        if (p)
            p->next = h->next;
        else
            table[n] = h->next;
        FREE(h->name);
        FREE(h);
    }
}
