#include "memory.h"
#include "useful.h"
#include "darray.h"
#include "textP.h"
#include "profile.h"
#include "rap.h"
#include "al.h"
#include "RMFBuffer.h"
#include "string.h"
#include "assert.h"

static Registry TextReg=NULL;
static char*    TextRegDir=NULL;

#define T_NOTHING 1
#define T_NAME    2
#define T_BODY    3
#define T_FEND    4
#define T_BEG     5
/*--------------------------------------------------*/
static TextFile open_new_file(file_name)
     char *file_name;
{
  int l;
  RMFBuffer pathB;
  char *path, *temp;
  TextFile tf;
  temp=NULL;

  if (TextRegDir==NULL) {
    if (AlProfile_has_value(ALPROF_MESSAGES_DIR)==Bool_TRUE)
      TextRegDir=AlProfile_get_CP_val(ALPROF_MESSAGES_DIR);
    else 
      Al_fatal_error("Could not find the message directory.  Make sure the profile component MessageDirectory is set.\n");

    /* MAKE SURE THERE IS A TRAILING '/' and its in its own memory */
    l=strlen(TextRegDir);
    if (TextRegDir[l-1]!='/') {
      temp=Memory_allocate(l+3);
      strcpy(temp,TextRegDir);
      temp[l]='/';
      temp[l+1]='\0';
      TextRegDir=temp;
    }
  }
  pathB=RMFBuffer_create(TextRegDir,50);
  RMFBuffer_append(pathB,file_name);
  path=RMFBuffer_copy_of_buff(pathB);
  RMFBuffer_destroy(pathB);

  if (temp!=NULL)
    Memory_free(temp);
  
  tf=(TextFile)Memory_allocate(sizeof(struct TextFile_str));
  tf->reg=Registry_create(Registry_strcmp,Registry_strhash);
  tf->the_file=fopen(path,"r");
  if (tf->the_file==NULL) {
    Al_warning1("Text: Could not open file %s\n",path);
    return(NULL);
  }
  tf->current_offset=(-1);
  tf->max_offset=(-1);
  tf->max_place=T_NAME;
  return(tf);
}

/*--------------------------------------------------*/
static long get_text_offset(tfile,text_name)
     TextFile tfile;
     char* text_name;
{
  char *line;
  int doing;
  extern char* RapStr_strip_surrounding_space PROTOTYPE((char*));

  assert(tfile->the_file);
  /* we always assume that the max_offset is at the beginning of a body. */
  /* i.e. positioned on a "[\n" */
  if (tfile->current_offset!=tfile->max_offset)
    fseek(tfile->the_file,tfile->max_offset,0);

  line=Memory_allocate(2000);
  doing=tfile->max_place;
  while((line=fgets(line,2000,tfile->the_file))!=NULL) {
    if (line[0]=='#')
      continue;
    switch (doing) {
    case T_NAME: 
      if (RapStr_is_empty(line)==Bool_TRUE) continue;
      line=RapStr_strip_surrounding_space(line);
      if (strcmp(text_name,line)==0) {
	tfile->current_offset=ftell(tfile->the_file);
	Registry_add(tfile->reg,(VOIDP)RapStr_duplicate(text_name),
		     (VOIDP)tfile->current_offset);
	tfile->max_offset=tfile->current_offset;
	tfile->max_place=T_BEG;
	Memory_free(line);
	return (tfile->current_offset);
      }
      else {
	doing=T_BEG;
	Registry_add(tfile->reg,(VOIDP)RapStr_duplicate(line),
		     (VOIDP)ftell(tfile->the_file));
      }
      break;
      
    case T_BEG:
      if (line[0]=='[')
	doing=T_BODY;
      break;
      
    case T_BODY:
      if (line[0]==']')
	doing=T_NAME;
      break;

    case T_FEND:
      break;
      
    default:
      Al_fatal_error("bad doing in get_text_offset\n");
      break;
    }
  }
  tfile->current_offset=ftell(tfile->the_file);
  tfile->max_offset=tfile->current_offset;
  tfile->max_place=T_FEND;
  Memory_free(line);
  return(-1);
}

/*--------------------------------------------------*/
static char* read_text(tfile,file_offset,text_name)
     TextFile tfile;
     long file_offset;
     char* text_name;
{
  char *line, *ret;
  int doing;
  RMFBuffer body=RMFBuffer_create(NULL,160);

  assert(tfile->the_file);
  fseek(tfile->the_file,file_offset,0);

  line=Memory_allocate(2000);
  doing=T_BEG;
  while((line=fgets(line,2000,tfile->the_file))!=NULL) {
    if (line[0]=='#')
      continue;
    switch (doing) {
    case T_BEG: 
    case T_NAME:
      if (line[0]=='[')
	doing=T_BODY;
      break;
      
    case T_BODY:
      if (line[0]==']') {
	tfile->current_offset=ftell(tfile->the_file);
	if (tfile->current_offset>tfile->max_offset)
	  tfile->max_offset=tfile->current_offset;
	tfile->max_place=T_NAME;
	Memory_free(line);
	ret=RMFBuffer_copy_of_buff(body);
	RMFBuffer_destroy(body);
	return (ret);
      }
      else
	RMFBuffer_append(body,line);
      break;

    case T_FEND:
    case T_NOTHING:
      break;

    default:
      Al_fatal_error("read text. bad doing in get_text_offset\n");
    }
  }
  if (doing==T_BODY)
    Al_fatal_error1("Text: %s: unterminated message body.\n",
		    text_name);
  tfile->current_offset=ftell(tfile->the_file);
  tfile->max_offset=tfile->current_offset;
  tfile->max_place=T_FEND;
  Al_warning1("Text: %s: not found.\n",text_name);
  Memory_free(line);
  return(NULL);
}  
  
/*--------------------------------------------------*/
const char * AlText_get(file_name,text_name)
     char *file_name, *text_name;
{
  TextFile tfile;
  FILE *the_file;
  long file_offset;
  char *text;
  /* this constant length string is major league kludgy, but I've no time to */
  /* do it right */ 
  static char warning[800];

  if (text_name==NULL || file_name==NULL) 
    return((const char*)"no message available. If you see this it is a bug.");

  if (TextReg==NULL)
    TextReg=Registry_create(Registry_strcmp,Registry_strhash);
  
  if ((tfile=(TextFile)Registry_get(TextReg,file_name))==NULL) {
    tfile=open_new_file(file_name);
    if (tfile==NULL)
      return((const char*)NULL);
    Registry_add(TextReg,file_name,tfile);
  }
  
  if ((file_offset=(long)Registry_get(tfile->reg,
				      (VOIDP)text_name))==(int)NULL) {
    file_offset=get_text_offset(tfile,text_name);
  }
  
  if (file_offset!=(-1))
    text=read_text(tfile,file_offset,text_name);
  
  if (text==NULL || file_offset==(-1)) {
    sprintf(warning,"<could not find the message '%s'\nin the file %s>",
	    text_name, file_name);
    return((const char*)warning);
  }
  
  return((const char*)text);
}
	
/*--------------------------------------------------*/
static NORET altext_free(name,offset,cadda)
     char name;
     int offset;
     VOIDP cadda;
{
  Memory_free((VOIDP)name);
}

/*--------------------------------------------------*/
static NORET altext_clean(file_name,tf,cadda)
     char file_name;
     TextFile tf;
     VOIDP cadda;
{
  Darray names, values;
  int i,l;
  char *name;
  names=Darray_create(); values=Darray_create();
  fclose (tf->the_file);
  Registry_fetch_contents(tf->reg,names,values);
  l=Darray_len(names);
  for (i=0;i<l;i++) {
    name=Darray_get(names,i);
    /* printf("text kill=%s\n",name); */
    Memory_free(name);
  }
  Darray_destroy(names);  Darray_destroy(values);
  /* Registry_traverse(tf->reg,altext_free,NULL); */
  Registry_destroy(tf->reg);
  Memory_free(tf);
}

/*--------------------------------------------------*/
NORET AlText_cleanup()
{
  if (TextReg!=NULL)
    Registry_traverse(TextReg,altext_clean,NULL);
}

/*--------------------------------------------------*/
NORET AlText_init()
{
  if (TextReg==NULL)
    TextReg=Registry_create(Registry_strcmp,Registry_strhash);
}
