#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "soundpipe.h"
#include "ini.h"

int nano_dict_add(nano_dict *dict, const char *name)
{
    nano_entry *entry = malloc(sizeof(nano_entry));
    entry->size = 0;
    entry->speed = 1;
    entry->pos = 0;
    strcpy(entry->name, name);
    dict->last->next = entry;
    dict->last = entry;
    dict->nval++;
    return SP_OK;
}

int nano_ini_handler(void *user, const char *section, const char *name,
        const char *value)
{
    nanosamp *ss = user;
    nano_dict *dict = &ss->dict;
    const char *entry_name = dict->last->name;

    if(dict->init) {
        nano_dict_add(dict, section);
        dict->init = 0;
    } else if(strncmp(entry_name, section, 50) != 0) {
        nano_dict_add(dict, section);
    }

    dict->last->speed = 1.0;

    if(strcmp(name, "pos") == 0) {
        dict->last->pos = (uint32_t)(atof(value) * ss->sr);
    } else if(strcmp(name, "size") == 0) {
        dict->last->size = (uint32_t)(atof(value) * ss->sr);
    } else if(strcmp(name, "speed") == 0) {
        dict->last->speed = atof(value);
    }

    return SP_OK;
}

int nano_create(nanosamp **smp, const char *ini, int sr)
{
    *smp = malloc(sizeof(nanosamp));
    nanosamp *psmp = *smp;
    strcpy(psmp->ini, ini);
    psmp->dict.last = &psmp->dict.root;
    psmp->dict.nval = 0;
    psmp->dict.init = 1;
    psmp->selected = 0;
    psmp->curpos = 0;
    psmp->sr = sr;
    if(ini_parse(psmp->ini, nano_ini_handler, psmp) < 0) {
        printf("Can't load file %s\n", psmp->ini);
        return SP_NOT_OK;
    }

    return SP_OK;
}

int nano_select_from_index(nanosamp *smp, uint32_t pos)
{
    pos %= smp->dict.nval;
    smp->selected = 1;
    smp->sample = smp->index[pos];
    smp->curpos = 0;
    return SP_OK;
}

uint32_t nano_keyword_to_index(nanosamp *smp, const char *keyword)
{
    uint32_t i;
    for (i = 0; i < smp->dict.nval; i++) {
        if(strcmp(keyword, smp->index[i]->name)) {
            return i;
        }
    }
    return 0;
}

int nano_select(nanosamp *smp, const char *keyword)
{
    uint32_t i;
    nano_dict *dict = &smp->dict;
    nano_entry *entry = dict->root.next;
    smp->curpos = 0;
    smp->selected = 0;
    for(i = 0; i < dict->nval; i++) {
        if(strncmp(keyword, entry->name, 50) == 0) {
            smp->selected = 1;
            smp->sample = entry;
            smp->curpos = 0;
            break;
        } else {
            entry = entry->next;
        }
    }

    if(smp->selected == 1) return SP_OK;
    else return SP_NOT_OK;
}


int nano_compute(sp_data *sp, nanosamp *smp, SPFLOAT *out)
{
    if(!smp->selected) {
        *out = 0;
        return SP_NOT_OK;
    }

    if(smp->curpos < (SPFLOAT)smp->sample->size) {
        SPFLOAT x1 = 0 , x2 = 0, frac = 0, tmp = 0;
        uint32_t index = 0;
        SPFLOAT *tbl = smp->ft->tbl;
        tmp = (smp->curpos + smp->sample->pos);
        index = floorf(tmp);
        frac = fabs(tmp - index);

        if(index >= smp->ft->size) {
            index = smp->ft->size - 1;
        }

        x1 = tbl[index];
        x2 = tbl[index + 1];
        *out = x1 + (x2 - x1) * frac;
        smp->curpos += smp->sample->speed;
    } else {
        smp->selected = 0;
        *out = 0;
    }

    return SP_OK;
}

int nano_dict_destroy(nano_dict *dict)
{
    int i;
    nano_entry *entry, *next;
    entry = dict->root.next;

    for(i = 0; i < dict->nval; i++) {
        next = entry->next;
        free(entry);
        entry = next;
    }
    return SP_OK;
}

int nano_destroy(nanosamp **smp)
{
    nanosamp *psmp = *smp;
    nano_dict_destroy(&psmp->dict);
    free(*smp);
    return SP_OK;
}



int nano_create_index(nanosamp *smp)
{
    nano_dict *dict = &smp->dict;
    smp->index = malloc(dict->nval * sizeof(nano_entry *));
    int i;
    nano_entry *entry, *next;
    entry = dict->root.next;

    for(i = 0; i < dict->nval; i++) {
        next = entry->next;
        smp->index[i] = entry;
        entry = next;
    }
    return SP_OK;
}

int nano_destroy_index(nanosamp *smp)
{
    free(smp->index);
    return SP_OK;
}

int sp_nsmp_create(sp_nsmp **p)
{
    *p = malloc(sizeof(sp_nsmp));
    return SP_OK;
}

int sp_nsmp_destroy(sp_nsmp **p)
{
    sp_nsmp *pp = *p;
    nano_destroy_index(pp->smp);
    nano_destroy(&pp->smp);
    free(*p);
    return SP_OK;
}

int sp_nsmp_init(sp_data *sp, sp_nsmp *p, sp_ftbl *ft, int sr, const char *ini)
{
    if (nano_create(&p->smp, ini, sr) == SP_NOT_OK) {
        nano_destroy(&p->smp);
        return SP_NOT_OK;
    }
    nano_create_index(p->smp);
    p->smp->sr = sr;
    p->index= 0;
    p->triggered = 0;
    p->smp->ft = ft;
    return SP_OK;
}

int sp_nsmp_compute(sp_data *sp, sp_nsmp *p, SPFLOAT *trig, SPFLOAT *out)
{
    if (*trig != 0) {
       p->triggered = 1;
       nano_select_from_index(p->smp, p->index);
    }

    if(p->triggered == 1) {
        nano_compute(sp, p->smp, out);
    } else {
        *out = 0;
    }

    return SP_OK;
}

int sp_nsmp_print_index(sp_data *sp, sp_nsmp *p)
{
    uint32_t i;
    for(i = 0; i < p->smp->dict.nval; i++) {
        printf("%d: key = %s\n", i, p->smp->index[i]->name);
    }
    return SP_OK;
}

