/*
 * libkarma/fdb.h
 * 
 * Copyright (c) Frank Zschockelt <libkarma@freakysoft.de> 2005
 * 
 * You may distribute and modify this program under the terms of 
 * the GNU GPL, version 2 or later.
 * 
 */
#include <stdlib.h>
#include <string.h>
#include <zlib.h>

#include "lkarma.h"
#include "properties.h"
#include "util.h"
#include "rio_rw.h"
#include "fdb.h"

static int rio = 0;

static int fdb_read_header(gzFile fdb_file)
{
    char *p, buf[64];
    int ver;

    gzread(fdb_file, buf, 64);
    buf[63] = '\0';
    if (memcmp(buf, "LkFdB ", 6) != 0) {
        lk_errors_set(E_BADFDB);
        return -1;
    }
    for (p=buf; *p != '\0'; p++)
        if (*p == ' ')
            break;
    *p = '\0';
    ver = atoi(buf);
    if (ver > 1) {
        lk_errors_set(E_BADFDB);
        return -1;
    }
    p++;
    for (; *p != '\0'; p++)
        if (*p == '\n')
            break;
    p++;
    gzseek(fdb_file, p-buf, SEEK_SET);
    return 0;
}

/*
 * fid:fid_generation path
 */

int lk_fdb_load(int download)
{
    gzFile fdb_file;
    char * fname;
    char * buf=NULL,*p,*n_tok;
    int read,upd,size=0;
    uint32_t fid;
    uint32_t *db;
    char * fid_gen;
    HASH * tmp;
    
    /*
     * Datenbank vom Karma laden
    */
    fname=lk_path_string(FDB_FILENAME);
    if (fname == NULL)
        return -1;

    if (download) {
        db=lk_properties_andOrSearch(EXACT|ORS, NULL, "title", FDB_FILENAME);
        if (db) {
            db=lk_properties_andOrSearch(EXACT|ORS, db, "type", "taxi");
            if (db) {
                unlink(fname);
                lk_rio_read(rio, *db, fname);
                free(db);
            }
        }
    }

    fdb_file=gzopen(fname, "r");
    free(fname);
    if (fdb_file == NULL)
        return -1;

    if (fdb_read_header(fdb_file) != 0)
        return -1;

    do{
        buf=realloc(buf, size+8192);
        read=gzread(fdb_file, &buf[size], 8192);
        size+=read;
    }while(read > 0);    
    gzclose(fdb_file);
    
    if((read == -1) || (size == 0)){
        free(buf);
        return read;
    }
    buf[size]='\0';
    p=strtok_r(buf, ":", &n_tok);
    upd = properties_updated;
    while(p!=NULL){
        fid=strtoul(p, (char **)NULL, 10);
        fid_gen=strtok_r(NULL, " ", &n_tok);
        p=strtok_r(NULL, "\n", &n_tok);
        if((tmp=lk_properties_idsearch(fid)))
            if(strcmp(fid_gen, lk_properties_get_property_hash(tmp,
                      "fid_generation")) == 0)
                lk_properties_set_property_hash(tmp, "path", p);
        p=strtok_r(NULL, ":", &n_tok);
    }
    free(buf);
    properties_updated = upd;
    fdb_updated = 0;

    return 0;
}

char **lk_fdb_getlist(char *fdb)
{
    gzFile fdb_file;
    char **list, **entry;
    char * buf=NULL,*p,*n_tok;
    int read,size=0;
    uint32_t fid;
    char * fid_gen;
    HASH * tmp;
    int nlist, len;
    
    fdb_file=gzopen(fdb, "r");
    if (fdb_file == NULL)
        return NULL;

    if (fdb_read_header(fdb_file) != 0)
        return NULL;

    do{
        buf=realloc(buf, size+8192);
        read=gzread(fdb_file, &buf[size], 8192);
        size+=read;
    }while(read > 0);    
    gzclose(fdb_file);
    
    if((read == -1) || (size == 0)){
        free(buf);
        return NULL;
    }
    buf[size]='\0';
    nlist = 0;
    for(p=buf; *p != '\0'; p++)
        if (*p == '\n') nlist++;
    if (nlist == 0)
        return NULL;
    nlist++;
    entry = list = calloc(nlist*sizeof(char *), 1);
    p=strtok_r(buf, ":", &n_tok);
    while(p!=NULL){
        fid=strtoul(p, (char **)NULL, 10);
        fid_gen=strtok_r(NULL, " ", &n_tok);
        p=strtok_r(NULL, "\n", &n_tok);
        len=strlen(p)+1;
        *entry = malloc(len);
        memcpy(*entry, p, len);
        entry++;
        p=strtok_r(NULL, ":", &n_tok);
    }
    free(buf);

    return list;
}

int lk_fdb_save(void)
{
    gzFile fdb_file;
    char * fname;
    char * id, * path, * tm;
    uint32_t * fdb;
    HASH * tmp;
    int i=0, first=1, ret=0;

    fname=lk_path_string(FDB_FILENAME);
    fdb_file=gzopen(fname, "w");
    if (fdb_file == NULL)
        return -1;

    gzwrite(fdb_file, "LkFdB 1 ", 8);
    if (serial) {
        id = simple_itoa(serial);
        gzwrite(fdb_file, id, strlen(id));
    } else
        gzwrite(fdb_file, "0", 1);
    gzwrite(fdb_file, "\n", 1);

    fdb=lk_properties_andOrSearch(EXACT|ORS, NULL, "path", "");
    if(fdb){
        for(i=0; fdb[i]; i++){
            tmp=lk_properties_idsearch(fdb[i]);
            if (!tmp)
                continue;
            path=lk_properties_get_property_hash(tmp, "path");
            tm=lk_properties_get_property_hash(tmp, "fid_generation");

            if (!path || !tm) {
                if (first) {
                    tm=lk_properties_get_property_hash(tmp, "type");

                    /* playlist files always have a missing path */
                    if (tm && memcmp(tm, "playlist", 8) == 0)
                        continue;
                    else if (tm && strncmp(tm, "taxi", 5) == 0) {
                        /* fdb file always has a missing path */
                        tm=lk_properties_get_property_hash(tmp, "title");
                        if (tm && strncmp(tm, FDB_FILENAME,
                                          strlen(FDB_FILENAME)+1) == 0)
                            continue;
                    }

                    lk_errors_set(E_NOPATHPR);
                    first = 0;
                }
                continue;
            }
            id=simple_itoa(fdb[i]);
            gzwrite(fdb_file, id, strlen(id));
            gzwrite(fdb_file, ":", 1); 
            gzwrite(fdb_file, tm, strlen(tm));
            gzwrite(fdb_file, " ", 1);
            gzwrite(fdb_file, path, strlen(path));
            gzwrite(fdb_file, "\n", 1);
        }
        free(fdb);
        gzclose(fdb_file);
    }
    ret = lk_rio_write_fdb(rio, fname);
    /*
     * Datenbank auf Karma als Taxifile kopieren...
     */
    free(fname);
    fdb_updated = 0;

    return ret;
}

void lk_fdb_set_device(int karma)
{
    rio = karma;
}
