/*********************** PGraphplan **************************************
  (C) Copyright 1999 Avrim Blum and John Langford,
  based on Graphplan code Copyright 1995 by Avrim Blum and Merrick Furst

  This software is made available AS IS, and neither the authors nor CMU make 
  any warranty about the software or its performance. 
*************************************************************************/

#include "graphplan.h"
#ifndef FALSE
#define FALSE 0
#endif
extern hashtable_t *fact_table, *op_table;  /* the arrays of hash tables */
extern int hash_hits, hash_inserts, hash_numctr, hash_ctr;
extern int do_remove, do_heuristic_value;
char templine[100]; /* global var that can use to store lines read in */

fact_list fact_list_from_vertex_list(vertex_t vlist);


/***given a string, makes a new one with NOOP in front***
  Returns new storage.
*/
char *make_noop_string(char *str)
{
  char *newp;
  newp = (char *) calloc(strlen(str) + strlen(NOOP) + 2, sizeof(char));
  sprintf(newp,"%s_%s",NOOP,str);
  return newp;
}

/*set uid_mask and uid_block*/
void set_uid(vertex_t v, int id)
{
  v->uid_block = id/32;
  v->uid_mask = 1 << (id % 32);
  v->uid = id;
}

edgelist_t make_edge(incl_list with)
{
  edgelist_t newedge = (edgelist_t) calloc(1,sizeof(edgelist_s));
  newedge->incl=with;
  return newedge;
}

edgelist_t insert_edge(edgelist_t e, vertex_t v, incl_list with)
{
  edgelist_t newedge=make_edge(with);
  newedge->next = e;
  newedge->endpt = v;
  return newedge;
}

/* like above, but insert at end of list */
edgelist_t insert_edge_at_end(edgelist_t e, vertex_t v, incl_list with)
{
  edgelist_t newedge;
  if (e == NULL) {
    newedge = make_edge(with);
    newedge->endpt = v;
    return newedge;
  } else {
    e->next = insert_edge_at_end(e->next, v, with);
    return e;
  }
}


/* makes a fact list from the hash table */
fact_list make_list_from_htable(hashtable_t h)
{
  int i;
  fact_list the_facts = NULL,current, p;
  for(i=0; i < HSIZE; ++i)
    if (h[i] != NULL) {
      current = fact_list_from_vertex_list(h[i]);
      for(p = current;  p->next; p = p->next);
      p->next = the_facts;
      the_facts = current;
    }
  return( the_facts );
}

void completely_free_fact_list(fact_list l)
{
  fact_list temp;
  while(l) { temp = l->next; free_token_list(l->item); free(l); l = temp;}
}

void free_token_list(token_list l)
{
  token_list temp;
  while(l) {   temp = l->next; free(l->item); free(l); l = temp;  }
}


/* makes string list into fact list. */
fact_list fact_list_from_vertex_list(vertex_t vlist)
{
  fact_list retval = NULL, f;
  char *str;
  for(; vlist; vlist = vlist->next) {
    str = vlist->name;
    f = (fact_list) malloc(sizeof(fact_list_elt));
    f->next = retval;
    retval = f;
    f->item = token_list_from_string(str);
  }
  return retval;
}

token_list token_list_from_string(char str[])
{
  char *p = str, *q, temp[50];
  token_list_elt dummy, *current;
  current = &dummy;
  while (*p) {
    current->next = (token_list) malloc(sizeof(token_list_elt));
    current = current->next;
    for(q = temp; (*p != '\0') && (*p != CONNECTOR); *q++ = *p++);
    if (*p == CONNECTOR) ++p;
    *q = '\0';
    current->item = (char *) calloc(1 + strlen(temp),sizeof(char));
    strcpy(current->item, temp);
  }
  current->next = NULL;
  return( dummy.next );
}



/* insert into instantiation list */
instantiation_list insert_inst(char *v, char *c, instantiation_list i)
{
  instantiation_list temp=(instantiation_list) malloc(sizeof(instantiation_s));
  temp->var_part = v;
  temp->const_part = c;
  temp->next = i;
  return( temp );
}


/* Returns instantiate token list in a string (last argument) Uses
   CONNECTOR to connect the tokens together. 
   if "failflag" is 0 then Return 1 if ok, 0 if failure.
   Otherwise, exit on failure.
   */
int instantiate_into_string(token_list l, instantiation_list inst,char str[],
			    int failflag)
{
  instantiation_list i;
  char *p;
  token_list t = l;

  for(p = str; t; t = t->next) {
    if (is_const(t->item))  /* just copy over */
      { strcpy(p,t->item); p+=strlen(t->item); *p++ = CONNECTOR; }
    else {
      for(i=inst; i; i = i->next)
        if (strcmp(i->var_part, t->item) == SAME) {
	  if (i->const_part == NULL) {i = NULL; break;}
          strcpy(p,i->const_part);p+=strlen(i->const_part);*p++ = CONNECTOR;
          break;
        }
      if (!i) {
	if (failflag) do_error("instantiation failed");
	return 0;
      }
    }
  }
  *(--p) = '\0';
  return 1;
}

/* "whitespace" is blank or paren */
int is_stopper(int c)
{
  return (isspace(c) || (c == ')') || (c == '('));
}

/* read the next "item".  An item is either a string of non-parentesis,
   non-blank characters, or a parenthesis.  In the former case, put into
   str and return OK. In the latter case, return LEFT_PAREN or RIGHT_PAREN
   appropriately.  Return EOF on end-of-file.

   if character is CONNECTOR, change it to REPLACEMENT
 */
#define REPLACEMENT '.'
#define PUSH_HEIGHT 2

int pushed=0;/*= next empty spot in stack.*/
char buf[PUSH_HEIGHT][MAX_TOKEN_LENGTH];

void push_back(char bufin[MAX_TOKEN_LENGTH])
{
  if (pushed==PUSH_HEIGHT)
    printf("What th'! you are trying to push too much!\n");
  strcpy(buf[pushed],bufin);
  pushed++;
}

int read_item(FILE *fp, char *str)
{
  char *strbegin;
  if (pushed){
    strbegin=str;
    strcpy(str,buf[--pushed]);
  }
  else{
    strbegin=str;
    /* first read in any blankspace and check for EOF */
    while(isspace(str[0] = getc(fp)));
    if (str[0] != EOF && !is_stopper(str[0]))
      {
	str++;
	while(!is_stopper(*str++ = getc(fp)))    /* read word in */
	  if (*(str-1) == CONNECTOR) *(str-1) = REPLACEMENT;/*change '_'to'.'*/
	
	ungetc(*--str, fp);                      /* went one too far */
	*str = '\0';                             /* end it nicely */
      }
  }
  if (strbegin[0] == EOF) return EOF;
  /* check if parenthesis */
  if (strbegin[0] == '(') return LEFT_PAREN;
  if (strbegin[0] == ')') return RIGHT_PAREN;
  if (isdigit(strbegin[0]) || (strbegin[0]=='.' && isdigit(strbegin[1])))
    return PROB;
  else
    return TOKEN;
}

/* string to describe an instantiated operator: re-reverse order */
void rec_make_op_string(op_ptr op,instantiation_list insts, char *str)
{
  if (insts == NULL) return;
  rec_make_op_string(op, insts->next, str);
  if (insts->const_part == NULL) 
    {fprintf(stderr,"op %s, ",op->name); do_error("bad instantiation");}
  sprintf(str + strlen(str), "_%s", insts->const_part);
}
/* string to describe an instantiated operator */
void make_op_string(op_ptr op, char *str)
{
  sprintf(str, "%s",op->name);
  rec_make_op_string(op, op->insts, str + strlen(str));
}

void do_error(char *s)
{
  fprintf(stderr,"%s\n",s); exit( 1 );
}

int equal_facts(token_list f1, token_list f2)
{
  for(; f1 && f2; f1 = f1->next, f2 = f2->next)
    if (!equal_tokens(f1->item,f2->item)) return 0;  /* different tokens*/
  if (f1 || f2) return 0;  /* different lengths */
  return 1;
}

/*************************** Begin Mutual Exclusions Part *****************/
int are_mutex(vertex_t v1, vertex_t v2)
{
  return ((v1->exclusive_vect[v2->uid_block]) & (v2->uid_mask));
}
/*************************END MUTUAL EXCLUSION PART**********************/



/* put in delete edges */
void put_in_del_edges(vertex_t v, int time)
{
  delete_list slist;
  vertex_t nextfact;

  for(slist = v->del_list; slist; slist = slist->next) {
    nextfact = lookup_from_table(fact_table[time+1], slist->item);
    if (nextfact == NULL) {
      if (DEBUG_FLAG > 2) printf("%s deleting nonexistent fact\n",v->name);
      continue;
    }

    /* now put into del_edges (and put info into FACT too, for DELETES)*/
    v->del_edges = insert_edge(v->del_edges, nextfact,slist->with);
    nextfact->del_edges = insert_edge(nextfact->del_edges,v,slist->with);
  }

  /* free storage of delete list */
  while(v->del_list) {
    slist = v->del_list;
    v->del_list = v->del_list->next;
    free(slist);
  }

}

/* given time in op hash table, put in all the delete edges */
void put_in_all_del_edges(hashtable_t harr[], int time)
{
  vertex_t v;
  get_next(harr[time],0); /* initialize */
  while((v = get_next(harr[time],1)) != NULL)
    put_in_del_edges(v, time);
  return;
}


/************ ROUTINES FOR PRINTING OUT INFORMATION TO USER**************/
void print_info_piece(hashtable_t t, int flag)
{
  vertex_t vert;
  edgelist_t edge;
  get_next(t, 0); /* get ready */
  while((vert = get_next(t, 1)) != NULL) {
    if ((do_remove && vert->needed == 0) || IS_NOOP(vert)) continue;
    if (do_heuristic_value) {
      printf("%s (%d)\n",vert->name, vert->heuristic_value);
    } else {
      printf("%s\n",vert->name);
    }
    if (flag>=2 && ((edge = vert->exclusive) != NULL)) {
      printf("   exclusive: "); /* now, includes noops */
      for(; edge; edge = edge->next)
	if (edge->endpt->needed) printf("%s ",edge->endpt->name);
      printf("\n");
    }
  }
}

/* for printing out info to user */
void print_info(int len)
{
  int i;

  for(i=0; i < len; ++i) {
    printf("\nTime: %d\n",i+1);
    print_info_piece(op_table[i], DEBUG_FLAG);
    if (DEBUG_FLAG > 1) {
      printf("\nFacts: \n");
      print_info_piece(fact_table[i+1], DEBUG_FLAG); /* PRINT FACTS*/
    }
  }
}


/************ more random utilities ***************/
void read_nitial_comments(FILE *fp)
{
  int c;
  while((c = getc(fp)) != '(');  /* read up to first left paren */
}

int allocs_in_use;

void my_free(void * p) {
    allocs_in_use--;
    free(p);
}
void * my_alloc(int size) {
    void * p = malloc(size);
    allocs_in_use++;
    if (p == NULL) {
        fprintf(stderr, "Ran out of space.  Requested size=%d.\n", size);
        exit(1);
    }
    return p;
}

void print_alloc(void)
{ printf("allocs - frees = %d\n",allocs_in_use); }


void yyerror(char *x)
{
	printf("%s\n",x);
}

fact_list fact_list_append(fact_list f1, fact_list f2)
{
	if (f2 == NULL) return f1;

	if (f1 == NULL) return f2;

	f1->next = fact_list_append(f1->next, f2);

	return f1;
}


token_list token_list_append(token_list f1, token_list f2)
{
	if (f2 == NULL) return f1;

	if (f1 == NULL) return f2;

	f1->next = token_list_append(f1->next, f2);

	return f1;
}
void print_cant_do(int time)
{
  fprintf(stderr,"Can't solve in %d steps\n",time);
  printf("%d entries in hash table and %d hits.\n",hash_inserts, hash_hits);
  printf("   avg set size %d\n", hash_numctr/hash_ctr);
}
