/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id: dbinterface.c 17847 2008-06-28 18:10:04Z bagder $
 *
 * Copyright (C) 2005 by Michiel van der Kolk 
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/
#include "searchengine.h"
#include "dbinterface.h"

#undef SONGENTRY_SIZE
#undef FILEENTRY_SIZE
#undef ALBUMENTRY_SIZE
#undef ARTISTENTRY_SIZE
#undef FILERECORD2OFFSET

#define SONGENTRY_SIZE    (rb->tagdbheader->songlen+12+rb->tagdbheader->genrelen+12)
#define FILEENTRY_SIZE    (rb->tagdbheader->filelen+12)
#define ALBUMENTRY_SIZE   (rb->tagdbheader->albumlen+4+rb->tagdbheader->songarraylen*4)
#define ARTISTENTRY_SIZE  (rb->tagdbheader->artistlen+rb->tagdbheader->albumarraylen*4)
#define RUNDBENTRY_SIZE   20

#define FILERECORD2OFFSET(_x_) (rb->tagdbheader->filestart + _x_ * FILEENTRY_SIZE)

struct dbentry *currententry;
struct dbglobals dbglobal;
static struct dbentry *entryarray;

int database_init() {
    char *p;
    unsigned int i;
    // allocate room for all entries
    entryarray=(struct dbentry *)my_malloc(sizeof(struct dbentry)*rb->tagdbheader->filecount);
    p=(char *)entryarray;
    // zero all entries.
    for(i=0;i<sizeof(struct dbentry)*rb->tagdbheader->filecount;i++) 
        *(p++)=0;
    if(!*rb->tagdb_initialized) {
        if(!rb->tagdb_init()) {
            // failed loading db
            return -1;
        }
    }
    dbglobal.playcountmin=0;
    dbglobal.playcountmax=0;
    dbglobal.gotplaycountlimits=0;
    return 0;
}

long readlong(int fd) {
    long num;
    rb->read(fd,&num,4);
#ifdef ROCKBOX_LITTLE_ENDIAN
    num=BE32(num);
#endif
    return num;
}

short readshort(int fd) {
    short num;
    rb->read(fd,&num,2);
#ifdef ROCKBOX_LITTLE_ENDIAN
    num=BE16(num);
#endif
    return num;
}


void loadentry(int filerecord) {
    if(entryarray[filerecord].loadedfiledata==0) {
        rb->lseek(*rb->tagdb_fd,FILERECORD2OFFSET(filerecord),SEEK_SET);
        entryarray[filerecord].filename=(char *)my_malloc(rb->tagdbheader->filelen);
        rb->read(*rb->tagdb_fd,entryarray[filerecord].filename,rb->tagdbheader->filelen);
        entryarray[filerecord].hash=readlong(*rb->tagdb_fd);
        entryarray[filerecord].songentry=readlong(*rb->tagdb_fd);
        entryarray[filerecord].rundbentry=readlong(*rb->tagdb_fd);
        entryarray[filerecord].loadedfiledata=1;
    }
    currententry=&entryarray[filerecord];
    dbglobal.currententryindex=filerecord;
}

void loadsongdata() {
    if(currententry->loadedsongdata) 
        return;
    currententry->title=(char *)my_malloc(rb->tagdbheader->songlen);
    currententry->genre=(char *)my_malloc(rb->tagdbheader->genrelen);
    rb->lseek(*rb->tagdb_fd,currententry->songentry,SEEK_SET);
    rb->read(*rb->tagdb_fd,currententry->title,rb->tagdbheader->songlen);
    currententry->artistoffset=readlong(*rb->tagdb_fd);
    currententry->albumoffset=readlong(*rb->tagdb_fd);
    rb->lseek(*rb->tagdb_fd,4,SEEK_CUR);
    rb->read(*rb->tagdb_fd,currententry->genre,rb->tagdbheader->genrelen);
    currententry->bitrate=readshort(*rb->tagdb_fd);
    currententry->year=readshort(*rb->tagdb_fd);
    currententry->playtime=readlong(*rb->tagdb_fd);
    currententry->track=readshort(*rb->tagdb_fd);
    currententry->samplerate=readshort(*rb->tagdb_fd);
    currententry->loadedsongdata=1;
}

void loadrundbdata() {
    currententry->loadedrundbdata=1;
    if(!*rb->rundb_initialized) 
        return;
    if(currententry->rundbentry==-1)
        return;
    rb->lseek(*rb->rundb_fd,currententry->rundbentry,SEEK_SET);
    currententry->rundbfe=readlong(*rb->rundb_fd);
    currententry->rundbhash=readlong(*rb->rundb_fd);
    currententry->rating=readshort(*rb->rundb_fd);
    currententry->voladj=readshort(*rb->rundb_fd);
    currententry->playcount=readlong(*rb->rundb_fd);
    currententry->lastplayed=readlong(*rb->rundb_fd);
}

void loadartistname() {
   /* memory optimization possible, only malloc for an album name once, then
    * write that pointer to the entrys using it.
   */
   if(currententry->loadedartistname)
       return;
   loadsongdata();
   currententry->artistname=(char *)my_malloc(rb->tagdbheader->artistlen);
   rb->lseek(*rb->tagdb_fd,currententry->artistoffset,SEEK_SET);
   rb->read(*rb->tagdb_fd,currententry->artistname,rb->tagdbheader->artistlen);
   currententry->loadedartistname=1;
}

void loadalbumname() {
   /* see the note at loadartistname */
   if(currententry->loadedalbumname)
       return;      
   loadsongdata();
   currententry->albumname=(char *)my_malloc(rb->tagdbheader->albumlen);
   rb->lseek(*rb->tagdb_fd,currententry->albumoffset,SEEK_SET);
   rb->read(*rb->tagdb_fd,currententry->albumname,rb->tagdbheader->albumlen);
   currententry->loadedalbumname=1;
}

char *getfilename(int entry) {
   if(entryarray[entry].loadedfiledata==0)
       return "error O.o;;;";
   else
       return entryarray[entry].filename;
}
