#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "indexl.h"

static INLINE int
files_off_comp(const void *v1,const void *v2) {

  const File *f1=v1,*f2=v2;

  return f1->off.u>f2->off.u ? 1 : -1;

}

static INLINE int
qcomp(const void *v1,const void *v2) {

  char * const *q1=v1,* const *q2=v2;

  return strcmp(*q1,*q2);

}

static INLINE int
files_load_list(Files *f) {

  Hash_totals *ht;
  Gen g;
  Datum *n;
  File tf,*q1,*qe;
  char **qq1,**qq,**qqe,z=0;
  Map q={0},t={0};
  void *v;

  ht=hash_get_totals(&f->d);
  
  if (!map_get(&f->p,0,sizeof(File)*ht->nw))
    return 0;
  if (!map_get(&f->n,0,sizeof(char)*(ht->nc+ht->nw)))
    return 0;

  for (;(n=hash_seq(&f->d,&g));) {
    if (!map_write_gen(&t,g))
      return 0;
    if (!map_write_element(&t,z))
      return 0;
  }

  for (v=t.m1;v<t.m;v+=strlen(v)+1)
    if (!map_write_element(&q,v))
      return 0;
    

  qq1=q.m1;
  qqe=q.m;
  qsort(qq1,qqe-qq1,sizeof(*qq1),qcomp);

  memset(&tf,0,sizeof(tf));
  for (qq=qq1;qq<qqe;qq++) {

    g.v=*qq;
    g.w=strlen(*qq);

    if (!(n=hash_get(&f->d,&g))) {
      err("Can't get %s from file hash\n",*qq);
      return 0;
    }

    tf.n=f->n.m;
    tf.off=n->off;

    if (!map_write_element(&f->p,tf))
      return 0;
    if (!map_write_string(&f->n,*qq))
      return 0;

  }

  if (!map_close(&q))
    return 0;
  if (!map_close(&t))
    return 0;
  if (!map_true(&f->p))
    return 0;
  if (!map_true(&f->n))
    return 0;

  q1=f->p.m1;
  qe=f->p.me;
  qsort(q1,qe-q1,sizeof(*q1),files_off_comp);

  return 1;

}

static INLINE int
files_make_list(Files *f,const char *s) {

  FILE *p;
  File tf,*q,*qe;
  char end[2];

  if (!(p=popen("find * -type f -name \"*.txt\" |sort","r")))
    return 0;
 
  memset(&tf,0,sizeof(tf));
  for (;map_fgets(&f->n,p);tf.n=(char *)(f->n.m-f->n.m1)) 
    if (!map_write_element(&f->p,tf))
      return 0;

  if (pclose(p))
    return 0;

  end[0]='z'+1;
  end[1]=0;
  if (!map_write_string(&f->n,end))
    return 0;
  if (!map_write_element(&f->p,tf))
    return 0;

  if (!map_true(&f->p))
    return 0;
  for (q=f->p.m1,qe=f->p.me;q<qe;q++)
    q->n=f->n.m1+(unsigned)q->n;

  if (!map_true(&f->n))
    return 0;

  return 1;

}


int
files_close(Files *f) {

  int i=1;

  if (!map_close(&f->n))
    i=0;
  if (!map_close(&f->p))
    i=0;
  if (!hash_close(&f->d))
    i=0;

  return i;

}

int
files_open(Files *f,const char *s,const char *s1,int new) {


  if (!files_close(f))
    return 0;

  if (!hash_open(&f->d,map_temp_str(".%s.findex",s),new))
    return 0;

  if (new)
    return files_make_list(f,s1);
  else 
    return files_load_list(f);
  
}

const File *
files_get_by_offset(Files *f,Offset o) {

  File *f1,*fe,*ff,ft;
  int i;

  f1=f->p.m1;
  fe=f->p.me;
  ft.off.o=o;
  ff=bsearch1(&ft,f1,fe-f1,sizeof(*f1),files_off_comp,&i);
  if (ff==f1) {
    err("Files offset search error\n");
    return NULL;
  }

  return ff-1;

}


  
