#include "rap.h"
#include "memory.h"
#include "string.h"
#include <ctype.h>
#include <assert.h>
#include "darray.h"
#include "registry.h"
#include "RMFBuffer.h"

/*--------------------------------------------------*/
char * RapStr_duplicate(s)
char *s;
{
  if (s==NULL)
    return(strcpy(Memory_allocate(1),""));
  else
    return(strcpy(Memory_allocate(strlen(s)+1),
		  s));
}

/*--------------------------------------------------*/
Bool RapStr_is_empty(s)
char *s;
{
  unsigned i,l;
  if (s==NULL) return (Bool_TRUE);
  i=0;
  while (s[i]!='\0') {
    if (!isspace(s[i])) 
      return(Bool_FALSE);
    i++;
  }
  return(Bool_TRUE);
}

/*--------------------------------------------------*/
NORET RapStr_destroy(s)
char *s;
{
  Memory_free(s);
}

/*--------------------------------------------------*/
/* allows leading blanks for a number with inf. digits */
/*----------------------------------------*/
Bool RapStr_is_int(s)
char *s;
{
  int i,l,state;
  assert(s);
  l=strlen(s);
  state=0;

  for (i=0;i<l;i++) {
    if (s[i]==' ') {
      if (state==1) {
	state=2;
      }
    }
    else if (isdigit(s[i])) {
      if (state==2)
	return(Bool_FALSE);
      else
	state=1;
    }
    else
      return(Bool_FALSE);
  }
  if (state==1)
    return(Bool_TRUE);
  else
    return(Bool_FALSE);
}

/*==================================================================*/
/*                                                                  */
/*               RapPack                                            */
/*                                                                  */
/*==================================================================*/


Registry RapPacks=NULL;

/*--------------------------------------------------*/
RapPack RapPack_create2(a,b)
VOIDP a,b;
{
  RapPack p;
  if (RapPacks==NULL)
    RapPacks=Registry_create(Registry_ptrcmp,Registry_ptrhash);
  p=(RapPack)Memory_allocate(sizeof(struct RapPack_str));
  p->size=2;
  p->d=Darray_create();
  Darray_hint(p->d,0,2);
  Darray_addh(p->d,a);
  Darray_addh(p->d,b);
  if (Registry_add(RapPacks,(VOIDP)p,(VOIDP)p)==Bool_FALSE)
    Al_fatal_error("RapPacks: error adding rappack to existance list.");
  return(p);
}

/*--------------------------------------------------*/
RapPack RapPack_create3(a,b,c)
VOIDP a,b,c;
{
  RapPack p;
  if (RapPacks==NULL)
    RapPacks=Registry_create(Registry_ptrcmp,Registry_ptrhash);
  p=(RapPack)Memory_allocate(sizeof(struct RapPack_str));
  p->size=3;
  p->d=Darray_create();
  Darray_hint(p->d,0,3);
  Darray_addh(p->d,a);
  Darray_addh(p->d,b);
  Darray_addh(p->d,c);
  if (Registry_add(RapPacks,(VOIDP)p,(VOIDP)p)==Bool_FALSE)
    Al_fatal_error("RapPacks: error adding rappack to existance list.");
  return(p);
}
/*--------------------------------------------------*/
RapPack RapPack_create4(a,b,c,d)
VOIDP a,b,c,d;
{
  RapPack p;
  if (RapPacks==NULL)
    RapPacks=Registry_create(Registry_ptrcmp,Registry_ptrhash);
  p=(RapPack)Memory_allocate(sizeof(struct RapPack_str));
  p->size=4;
  p->d=Darray_create();
  Darray_hint(p->d,0,4);
  Darray_addh(p->d,a);
  Darray_addh(p->d,b);
  Darray_addh(p->d,c);
  Darray_addh(p->d,d);
  if (Registry_add(RapPacks,(VOIDP)p,(VOIDP)p)==Bool_FALSE)
    Al_fatal_error("RapPacks: error adding rappack to existance list.");
  return(p);
}
/*--------------------------------------------------*/
RapPack RapPack_create5(a,b,c,d,e)
VOIDP a,b,c,d,e;
{
  RapPack p;
  if (RapPacks==NULL)
    RapPacks=Registry_create(Registry_ptrcmp,Registry_ptrhash);
  p=(RapPack)Memory_allocate(sizeof(struct RapPack_str));
  p->size=5;
  p->d=Darray_create();
  Darray_hint(p->d,0,5);
  Darray_addh(p->d,a);
  Darray_addh(p->d,b);
  Darray_addh(p->d,c);
  Darray_addh(p->d,d);
  Darray_addh(p->d,e);
  if (Registry_add(RapPacks,(VOIDP)p,(VOIDP)p)==Bool_FALSE)
    Al_fatal_error("RapPacks: error adding rappack to existance list.");
  return(p);
}
/*--------------------------------------------------*/
RapPack RapPack_create6(a,b,c,d,e,f)
VOIDP a,b,c,d,e,f;
{
  RapPack p;
  if (RapPacks==NULL)
    RapPacks=Registry_create(Registry_ptrcmp,Registry_ptrhash);
  p=(RapPack)Memory_allocate(sizeof(struct RapPack_str));
  p->size=6;
  p->d=Darray_create();
  Darray_hint(p->d,0,6);
  Darray_addh(p->d,a);
  Darray_addh(p->d,b);
  Darray_addh(p->d,c);
  Darray_addh(p->d,d);
  Darray_addh(p->d,e);
  Darray_addh(p->d,f);
  if (Registry_add(RapPacks,(VOIDP)p,(VOIDP)p)==Bool_FALSE)
    Al_fatal_error("RapPacks: error adding rappack to existance list.");
  return(p);
}

/*--------------------------------------------------*/
NORET RapPack_destroy(p)
RapPack p;
{
  if (RapPacks==NULL)
    Al_fatal_error("RapPack:cannot destroy a rappack before any are created.");
  if (Registry_remove(RapPacks,(CONSTVOIDP)p)==Bool_FALSE)
    Al_fatal_error("RapPack:cannot destroy a rappack which does not exist.");
  Darray_destroy(p->d);
  Memory_free(p);
}

/*..................................................*/    
NORET RapPack_kill_one(k,v,d)
VOIDP k,v,d;
{
  RapPack p;
  p=(RapPack)k;
  if (Registry_remove(RapPacks,(CONSTVOIDP)p)==Bool_FALSE)
    Al_fatal_error("RapPack:cannot destroy a rappack which does not exist.");
  Darray_destroy(p->d);
  Memory_free(p);
  Registry_remove(RapPacks,p);
}
/*--------------------------------------------------*/
NORET RapPack_destroy_all()
{
  if (RapPacks==NULL)
    Al_fatal_error("RapPack:cannot destroy all rappacks before any are\
 created.");
  Registry_traverse(RapPacks,RapPack_kill_one,(VOIDP)NULL);
  Registry_destroy(RapPacks);
  RapPacks=NULL;
}

/*--------------------------------------------------*/
VOIDP RapPack_get(p,n)
RapPack p;
int n;
{
#ifdef RE_DEBUG
  if (RapPacks==NULL)
    Al_fatal_error("RapPack_get:can't before any are created.");
  if (Registry_get(RapPacks,p)==NULL)
    Al_fatal_error("RapPack_get: passed in invalid rappack.");
#else
  assert(RapPacks);
  assert(p);
#endif

  if (n<0)
    Al_fatal_error("RapPack:can not get negative compnent of a rappack");
  if (n>=p->size)
    Al_fatal_error("RapPack:can not get compnent of a rappack: index too\
  large");

  return(Darray_get(p->d,n));
}
/*--------------------------------------------------*/
/* these next two functions are exact duplicates of the rl.c ones.  Remove */
 /* the rl.c ones when you get a chance.!!!!!!!!!! */
/*----------------------------------------*/ 
NORET RapList_parse_into_darray(d,s)
Darray d;
char* s;
{
  unsigned low, high;
  char c;

  low=0;
  while (isspace(s[low]) && s[low]!='\0') low++;
  high=low;
  while (s[high]!='\0') {
    low=high;
    while (isspace(s[low]) && s[low]!='\0') low++;
    high=low;
    if (s[low]!='\0') {
      while (s[high]!=',' && (s[high]!='\0')) high++;
      while (s[high]==' ') high--;              /* remove trailing blanks */
      c=s[high];
      s[high]='\0';
      Darray_addh(d,RapStr_duplicate(&(s[low])));
      s[high]=c;
    }
    while (s[high]!=',' && s[high]!='\0') high++;
    if (s[high]==',') high++;
  }
}

/*--------------------------------------------------*/
NORET RapList_destroy_darray_contents(d)
Darray d;
{
  unsigned i,l;
  l=Darray_len(d);
  for(i=0;i<l;i++)
    RapStr_destroy(Darray_reml(d));
}


/*----------------------------------------*/ 
NORET RapList_parse_into_registry(d,s)
Registry d;
char* s;
{
  unsigned low, high;
  char c;

  low=0;
  while (isspace(s[low]) && s[low]!='\0') low++;
  high=low;
  while (s[high]!='\0') {
    low=high;
    while (isspace(s[low]) && s[low]!='\0') low++;
    high=low;
    if (s[low]!='\0') {
      while (!(isspace(s[high])) && (s[high]!=',') && (s[high]!='\0')) high++;
      c=s[high];
      s[high]='\0';
      Registry_add(d,RapStr_duplicate(&(s[low])),"TRUE");
      s[high]=c;
    }
    while (s[high]!=',' && s[high]!='\0') high++;
    if (s[high]==',') high++;
  }
}

static int string_get_int_from_char(c)
char c;
{
  if (c<'0' || c>'9')
    Al_warning("convering to octal: character not an integer: %c\n",c);
  return(c-'0');
}

/*--------------------------------------------------*/
char RapString_get_char_from_octal(s)
char *s;
{
  char ret;
  ret=0;
  ret+=(string_get_int_from_char(s[0])*64);
  ret+=(string_get_int_from_char(s[1])*8);
  ret+=(string_get_int_from_char(s[2])*1);
  return(ret);
}

/*--------------------------------------------------*/
const char* RapString_get_octal_string_from_char(ic)
int ic;
{
  char c=(char)ic;
  static const char ret[4];
  ret[0]=(char)('0'+(int)c/64);
  c=c-(64*((int)c/64));
  ret[1]=(char)('0'+(int)c/8);
  c=c-(8*((int)c/8));
  ret[2]=(char)('0'+(int)c);
  ret[3]='\0';
  return((const char*)ret);
}

/*--------------------------------------------------*/
static Bool RapString_is_member(ic,s)
char *s;
int ic;
{
  char c=(char)ic;
  int i;
  i=0;
  while (s[i]!='\0') if (c==s[i++]) return(Bool_TRUE);
  return(Bool_FALSE);
}


/*--------------------------------------------------*/
char * RapString_encode_string(s,additional_encode)
     char *s, *additional_encode;
{
  RMFBuffer out=RMFBuffer_create(NULL,20);
  int i;
  char *ret;
  
  i=0;
  while (s[i]!='\0') {
    if (!(isprint(s[i])) || 
	(RapString_is_member(s[i],additional_encode)==Bool_TRUE)) {
      RMFBuffer_append_char(out,'\\');
      RMFBuffer_append(out,(char*)
		       RapString_get_octal_string_from_char((int)s[i]));
    }
    else
      RMFBuffer_append_char(out,s[i]);
    i++;
  }
  ret=RMFBuffer_copy_of_buff(out);
  RMFBuffer_destroy(out);
  return(ret);
}



/*--------------------------------------------------*/
char* RapString_decode_string(s)
char *s;
{
  int i,l,j;
  char c;

  l=strlen(s);
  i=0; j=0;
  while ((c=s[i++])!='\0') {
    if (c=='\\') {
      if (isdigit(s[i])) {
	s[j++]=RapString_get_char_from_octal(&(s[i]));
	i+=3;
      }
      else
	s[j++]=s[i++];
    }
    else
      s[j++]=c;
  }
  s[j]='\0';
  return(s);
}
  
      
/*--------------------------------------------------*/
NORET RapDarray_print(s,d)
     char *s;
     Darray d;
{
  int i,l;
  l=Darray_len(d);
  printf("-------------- %s --------------\n",s);
  for (i=0;i<l;i++)
    printf("-> %s\n",(char*)Darray_get(d,i));
  printf("------------------------------------\n");
}

/*--------------------------------------------------*/
Bool RapDarray_pointer_index(d,p,ret)
     Darray  d;
     VOIDP   p;
     int*   ret;
{
  int i,l;
  l=Darray_len(d);
  for (i=0;i<l;i++) {
    if (p==Darray_get(d,i)) {
      *ret=i;
      return(Bool_TRUE);
    }
  }
  return(Bool_FALSE);
}

/*--------------------------------------------------*/
int  RapDarray_pointer_get_index(d,p)
     Darray d;
     VOIDP  p;
{
  int i,l;
  l=Darray_len(d);
  for (i=0;i<l;i++) {
    if (p==Darray_get(d,i))
      return(i);
  }
  return(-1);
}

/*--------------------------------------------------*/
char* RapStr_strip_surrounding_space(S)
     char *S;
{
  int i,l,start,end,s,d;
  char c;
  start=(-1); end=(-1);
  i=0;
  while ((c=S[i])!='\0' && isspace(c)) i++;
  if (c=='\0') {
    S[0]='\0';
    return(S);
  }
  start=i;

  l=strlen(S);
  i=l-1;
  while (isspace(S[i])) i--;
  end=i;

  for (d=0,s=start;s<end;d++,s++)
    S[d]=S[s];

  S[d+1]='\0';
  return(S);
}
