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

#include "backend.h"
#include "bool_tree.h"
#include "bool_query.c"

int mg_doc_contains_str(void *qd, u_long docnum, char *s)
{
  unsigned char *buf=NULL ;
  int len=0, doclen=0, retval ;
  mg_get_raw_doc(qd, docnum, &buf, &len, &doclen) ;
  if (strstr((char *)buf, s) != NULL)
    retval = 1 ;
  else retval = 0 ;
  free(buf) ;
  return(retval) ;
}

void mg_doc_get_line(unsigned char *docbuf, int *p_offset, char *line)
{
  int i ;
  char *linestart ;

  line[0] = '\0' ;
  linestart = (char *)docbuf + *p_offset ;

  i = 0 ;
  while (linestart[i] != '\n' && linestart[i] != '\0') i++ ;
  strncpy(line, linestart, i) ;
  if (linestart[i] == '\n') {
    line[i] = '\0' ;
    *p_offset += i+1 ;
  }
  else 
    *p_offset += i ;
}

int mg_get_raw_doc(void *qd, u_long docnum, unsigned char **p_ucbuf, 
		    int *p_ucbuf_len, int *p_retlen)
{
  query_data *real_qd ;
  static last_pos = 0 ;
  static u_char *c_buffer = NULL ;
  u_long pos, len ;
  int newucbuf_len ;
  int temp_retlen, temp_ucbuf_len ;

  if (p_retlen == NULL) p_retlen = &temp_retlen ;
  if (p_ucbuf_len == NULL) {
    p_ucbuf_len = &temp_ucbuf_len ;
    *p_ucbuf_len = 0 ;
  }

  real_qd = (query_data *)qd ;
  FetchDocStart(real_qd, docnum, &pos, &len) ;
  newucbuf_len = (int)(real_qd->td->cth.ratio * 1.01 * len)+101 ;

  if (c_buffer != NULL)
    Xfree(c_buffer) ;
  if (!(c_buffer = Xmalloc(len)))
    return -1 ;

  if (newucbuf_len > *p_ucbuf_len) {
    if (*p_ucbuf != NULL) 
      Xfree(*p_ucbuf) ;
    if (!(*p_ucbuf = Xmalloc(newucbuf_len))) 
      return -1 ;
    *p_ucbuf_len = newucbuf_len ;
  }
  if (last_pos != pos)
    Fseek(real_qd->td->TextFile, pos, 0) ;
  Fread(c_buffer, 1, len, real_qd->td->TextFile) ;
  last_pos = pos+len ;
  DecodeText(real_qd->cd, c_buffer, len, *p_ucbuf, p_retlen) ;
  (*p_ucbuf)[*p_retlen]='\0' ;
  return 0 ;
}

void mg_bool_query(char *qstr, char *dir, char *file, void **rqd)
{
  InitQueryTimes iqt ;
  query_data *qd ;
  BooleanQueryInfo bqi ;
  char *line ;

  InitEnv() ;
  qd = InitQuerySystem(dir, file, &iqt) ;
  bqi.MaxDocsToRetrieve=-1 ;

  if(qd != NULL)
  {
    bool_tree_node *tree ;
    DocList *Docs ;
    int res=0;
    
    tree = ParseBool(qstr, strlen(qstr),
		     &(qd->TL), qd->sd->sdh.stem_method, &res) ;
    if (res != 0) {
      qd->DL = NULL ;
    }
    else {
      ReadInTermInfo(qd) ;
      FindNoneTerms(qd, tree) ;
      OptimiseBoolTree(tree, qd->TL, 1) ;
      qd->hops_taken=qd->num_of_ptrs=qd->num_of_terms=0 ;
      Docs = BooleanGet(qd, tree, &bqi) ;
      if (qd->id->ifh.InvfLevel==3) AdjustParaDocs(qd, Docs) ;
      FreeQueryDocs(qd) ;
      qd->DL = Docs ;
    }
  }

  *rqd = (void *)qd ;
}

int mg_get_num_returned(void *qd)
{
  if (qd == NULL || ((query_data *)qd)->DL == NULL) return(0) ;
  else return(((query_data *)qd)->DL->num) ;
}

int mg_get_doc_num(void *qd)
{
  return GetDocNum((query_data *)qd) ;
}

int mg_goto_next_doc(void *qd)
{
  return NextDoc((query_data *)qd) ;
}

typedef struct {
  unsigned char *buffer ;
  int buflen ;
  int doclen ;
  int offset ;
} doc_line_producer_t ;

void mg_setup_doc_line_producer(void *qd, int docnum, void **rdlp_v)
{
  doc_line_producer_t *dlp ;

  if (*rdlp_v == NULL) {
    dlp = (doc_line_producer_t *)malloc(sizeof(doc_line_producer_t)) ;
    dlp->buffer = NULL ;
    dlp->buflen = 0 ;
    *rdlp_v = dlp ;
  }
  else dlp = *(doc_line_producer_t **)rdlp_v ;

  dlp->offset = 0 ;
  mg_get_raw_doc(qd, docnum, &(dlp->buffer), &(dlp->buflen), 
		 &(dlp->doclen)) ;
}

void mg_dlp_next_line(void *dlp_v, char *line)
{
  doc_line_producer_t *dlp = (doc_line_producer_t *)dlp_v ;

  mg_doc_get_line(dlp->buffer, &(dlp->offset), line) ;
}

int mg_dlp_more_lines(void *dlp_v)
{
  doc_line_producer_t *dlp = (doc_line_producer_t *)dlp_v ;

  return dlp->offset < dlp->doclen ;
}

void dispose_doc_line_producer(void *dlp)
{
  free(((doc_line_producer_t *)dlp)->buffer) ;
  free(dlp) ;
}
