/*
 * text.c:
 *
 * Copyright (c) 2000 James McKenzie <james@fishsoup.dhs.org>,
 * All rights reserved.
 *
 */

static char rcsid[] =
    "$Id: text.c,v 1.14 2002/06/23 17:16:39 root Exp root $";

/*
 * $Log: text.c,v $
 * Revision 1.14  2002/06/23 17:16:39  root
 * #
 *
 * Revision 1.13  2001/10/12 13:51:11  root
 * #
 *
 * Revision 1.12  2001/10/04 18:21:16  root
 * #
 *
 * Revision 1.11  2001/10/04 18:00:36  root
 * #
 *
 * Revision 1.10  2001/01/30 06:16:18  root
 * #
 *
 * Revision 1.9  2000/12/01 04:42:10  root
 * #
 *
 * Revision 1.8  2000/11/23 23:45:19  root
 * #
 *
 * Revision 1.7  2000/10/07 18:30:03  root
 * #
 *
 * Revision 1.6  2000/10/06 19:52:18  root
 * #
 *
 * Revision 1.5  2000/09/24 01:58:21  root
 * #
 *
 * Revision 1.4  2000/09/24 01:48:12  root
 * #
 *
 * Revision 1.3  2000/09/24 01:44:47  root
 * #
 *
 * Revision 1.2  2000/09/24 01:12:43  root
 * #
 *
 * Revision 1.1  2000/09/19 03:53:27  root
 * #
 *
 */

#include "project.h"

#include <regex.h>
#include <ctype.h>

static DB *textdb = NULL;

#define N_MAGIC_HEADS (sizeof(magic_head)/sizeof(char *))
static char *magic_head[] = {
  "ZZZ_Plebs"
};

static int do_magic_heads = 0;

EXTERNAL void enable_magic_heads(void)
{
  do_magic_heads++;
}

/*Initialize the inode -> name database*/
static void text_init(char *name)
{
  int ret;

  if (textdb)
    return;

  ret = db_create(&textdb, NULL, 0);
  if (ret) {
    fprintf(stderr, "db_create: %s\n", db_strerror(ret));
    textdb = NULL;
    return;
  }

  ret = textdb->open(textdb, name, NULL, DB_BTREE, DB_CREATE, 0x600);

  if (ret) {
    textdb->err(textdb, ret, "textdb");
    textdb->close(textdb, 0);
    textdb = NULL;
  }

}

/* ensure textdb is initialized */
#define DOINIT  { if (!textdb) text_init(NULL); };

INTERNAL void text_remove(Eweid e)
{
  DBT key = { 0 };
  int ret;
  char *f;

  key.size = sizeof(e->e);
  key.data = e->e;

  DOINIT;

  ret = textdb->del(textdb, NULL, &key, 0);
  if (ret == DB_NOTFOUND)
    return;

  if (ret) {
    textdb->err(textdb, ret, "DB->del");
  }
}



INTERNAL void text_add(Eweid e, const char *s)
{
  DBT key = { 0 };
  DBT data = { 0 };
  int ret;
  char *f;


  key.size = sizeof(e->e);
  key.data = e->e;

  data.size = strlen(s);
  data.data = (char *) s;

  DOINIT;

  ret = textdb->put(textdb, NULL, &key, &data, 0);

  if (ret) {
    textdb->err(textdb, ret, "DB->put");
  }
}


INTERNAL char *eweid_to_text_nocheat(Eweid e)
{
  DBT key;
  DBT data;
  int ret;
  char *r;


  DOINIT;

  bzero(&key, sizeof(key));
  bzero(&data, sizeof(data));

  key.data = e->e;
  key.size = sizeof(e->e);

  ret = textdb->get(textdb, NULL, &key, &data, 0);

  if (ret == DB_NOTFOUND)
    return NULL;

  if (ret) {
    textdb->err(textdb, ret, "DB->get");
    return NULL;
  }

  r = (char *) malloc(data.size + 1);

  bcopy(data.data, r, data.size);
  r[data.size] = 0;

  return r;
}


/* Horid hack*/

INTERNAL char *text_guess_name_from_file(char *uin)
{
/*Ok for the moment we turn */
/* ..../a/b/nnn.mp3 -> a/b/nnn */
/* ..../a/b/foo.mp3 -> b/foo */

  char *s1, *s2, *s3, *ptr;
  char *in;
  int i;

  if (!uin)
    return NULL;

  in = strdup(uin);
  i = strlen(uin);


  ptr = in;

  while (*ptr) {
    if (!strncasecmp(ptr, "/unsorted/",10))
      memmove(ptr, ptr + 9, strlen(ptr + 8));
    ptr++;
  }


  if ((i > 3) && (!strcasecmp(&in[i - 4], ".mp3")))
    in[i - 4] = 0;

  s1 = s2 = s3 = ptr = in;

  while (*ptr) {
    if (!isdigit(*ptr))
      i++;

    if (*ptr == '/') {
      s1 = s2;
      s2 = s3;
      s3 = ptr;
      i = 0;
    }

    ptr++;
  }


  if (!i) {
/*all digits*/
    if (*s1 == '/')
      s1++;
    ptr = strdup(s1);
  } else {
    if (*s2 == '/')
      s2++;
    ptr = strdup(s2);
  }
  free(in);



  if (do_magic_heads) {
    for (i = 0; i < N_MAGIC_HEADS; ++i) {
      if (strstr(uin, magic_head[i])) {
        in = ptr;
        ptr = malloc(strlen(in) + strlen(magic_head[i]) + 2);
        strcpy(ptr, magic_head[i]);
        strcat(ptr, " ");
        strcat(ptr, in);
      }
    }
//    fprintf(stderr, "%s: gave %s\n", uin, ptr);
  }





  return ptr;
}


EXTERNAL char *eweid_to_text(Eweid e)
{
  char *r = eweid_to_text_nocheat(e);


  if ((!r) || (!strcmp(r, " "))) {

    if (r)
      free(r);
    r = eweid_to_filename(e);
    if (!r)
      r = strdup("Unknown Eweid (file not found)");

    {
      char *foo = text_guess_name_from_file(r);
      free(r);
      r = foo;
    }
  }

  return r;
}

int compar(const void *e1, const void *e2)
{
  char *s1 = eweid_to_text_nocheat(*(Eweid *) e1);
  char *s2;
  int ret;
  if (!s1)
    return -1;
  s1 = strdup(s1);
  s2 = eweid_to_text_nocheat(*(Eweid *) e2);
  if (!s2) {
    free(s1);
    return -1;
  }


  ret = strcasecmp(s1, s2);

  if (s1)
    free(s1);

  return ret;
}

BEGIN_OBJECT(Submatch)
char *regex;
int freeme;
regex_t re;
END_OBJECT(Submatch)
static void submatch_destructor(Submatch s)
{
  if (s->regex)
    free(s->regex);
  if (s->freeme)
    regfree(&s->re);
  free(s);
}

CREATOR(Submatch) = (Creator(Submatch)) Obj_DefaultCreator;
DESTRUCTOR(Submatch) = submatch_destructor;

static Submatch new_submatch(char *in)
{
  Submatch s = CREATE_OBJ(Submatch);

  s->regex = strdup(in);

  if (regcomp(&s->re, s->regex, REG_ICASE | REG_NOSUB)) {
    Obj_Delete(s);
    return NULL;
  }

  s->freeme++;

  return s;


}

static int does_match(Submatch_list sl, char *match)
{
  Submatch s = sl->head;

  while (s && (!regexec(&s->re, match, 0, NULL, 0)))
    s = s->next;

  if (!s)
    return 1;

  return 0;

}

EXTERNAL Flock files_find(const char *text)
{
  Flock flock, tmp;
  Eweid *array;
  DBC *c;
  DBT data, key;
  Eweid e;
  char *r;
  int ret;
  int i = 0;
  Submatch_list sl = CREATE_LIST(Submatch);


  char wsp[] = " \t";

  DOINIT;

  {
    Submatch s;
    char *in = strdup(text);
    char *inptr = in;
    char *wptr;

    while (*inptr) {


      while ((*inptr) && (strchr(wsp, *inptr)))
        inptr++;

      if (*inptr) {

        wptr = inptr;

        while ((*inptr) && (!strchr(wsp, *inptr)))
          inptr++;

        if (*inptr) {
          *inptr = 0;
          inptr++;
        }

        printf("WPTRFISH %s\n", wptr);
        s = new_submatch(wptr);

        if (!s) {
          Obj_Delete(sl);
          free(in);
          return NULL;
        }

        Obj_Insert(sl, s, ObjInsertTail);
      }


    }




  }

  bzero(&data, sizeof(data));
  bzero(&key, sizeof(key));


  ret = textdb->cursor(textdb, NULL, &c, 0);
  if (ret) {
    textdb->err(textdb, ret, "cursor");
    return NULL;
  }

  e = CREATE_OBJ(Eweid);
  flock = CREATE_LIST(Eweid);

  while (1) {
    ret = c->c_get(c, &key, &data, DB_NEXT);

    if (ret == DB_NOTFOUND)
      break;

    if (ret) {
      textdb->err(textdb, ret, "fishr");
      c->c_close(c);
      Obj_Delete(e);
      Obj_Delete(flock);
      Obj_Delete(sl);
      return NULL;
    }

    bcopy(key.data, &e->e, sizeof(e->e));


/* Do stuff */

    r = (char *) malloc(data.size + 1);
    bcopy(data.data, r, data.size);
    r[data.size] = 0;

    if (does_match(sl, r)) {

      Eweid f = eweid_dup(e);
      char *d = eweidtoa(e);
      fprintf(stderr, "%s => %s matches %s\n", d, r, text);
      free(d);

      Obj_Insert(flock, f, ObjInsertTail);
      i++;

    }

    free(r);

  }

  c->c_close(c);
  Obj_Delete(e);
  Obj_Delete(sl);

  array = (Eweid *) malloc(sizeof(Eweid) * i);

  i = 0;
  while (flock->head) {
    e = flock->head;
    Obj_Remove(flock, e);
    array[i++] = e;
  }

  qsort(array, i, sizeof(Eweid), compar);

  for (ret = 0; ret < i; ++ret) {
    Obj_Insert(flock, array[ret], ObjInsertTail);
  }
  free(array);

  return flock;
}
