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

#include "parse.h"
#include "globals_parse.h"
//#include "functions.h"

extern int first_concept;

int	pwp;

// method: read_grammar
//
// arguments:
//  Edge *edge: (input)
//  Gram *gram: (input)
//  char *s: (output) if not NULL, prints to this char*
//
// return: pointer to created Gram object. exit(-1) on error
//
// uses no global variables
// calls many functions to load the Gram object correctly. Exits -1 on error.
//if s is NOT NULL, prints to s, else prints to screen
//
char *print_edge(Edge *edge, Gram *gram, char *s) {
  Edge	    **cp;
  int	    nxt;
  int       i;
  
  if (s) {
    sprintf(s, "%s ( ", gram->labels[edge->net]);
    s += strlen(s);
  }
  else
    printf("%s ( ", gram->labels[edge->net]);
  
  pwp = edge->sw;

  // print children
  for (cp = edge->chld, i=0; i < edge->nchld; i++, cp++) {
    for (nxt = (*cp)->sw; pwp < nxt; pwp++) {
      if (script[pwp] == -1) continue;
      if (script[pwp] == start_token) continue;
      if (script[pwp] == end_token) continue;
      if (s) {
	sprintf(s, "%s ", gram->wrds[ script[pwp] ] );
	s += strlen(s);
      }
      else printf("%s ", gram->wrds[ script[pwp] ] );
    }
    s = print_edge( *cp, gram, s );
    pwp = (*cp)->ew+1;
  }
  for ( ; pwp <= edge->ew; pwp++) {
    if (script[pwp] == -1 ) continue;
    if (script[pwp] == start_token) continue;
    if (script[pwp] == end_token) continue;
    if (s) {
      sprintf(s, "%s ", gram->wrds[ script[pwp] ] );
      s += strlen(s);
    }
    else printf("%s ", gram->wrds[ script[pwp] ] );
  }
  if (s) { sprintf(s, ") "); s += strlen(s); }
  else printf(") ");
  
  return(s);
}

// method: print_extracts
//
// arguments:
//  Edge *edge: (input)
//  Gram *gram: (input)
//  char *s: (output) if not NULL, prints to this char*
//
// return: pointer to created Gram object. exit(-1) on error
//
// uses no global variables
// prints extracts
//
char *print_extracts(Edge *edge, Gram *gram, char *s, int level, char *fn) {
  Edge	**cp;
  int		nxt, i;
  char	concept,
    name[LABEL_LEN];
  
  
  /* get rid of [ */
  strcpy(name, gram->labels[edge->net]+1);
  if( isupper((int)name[0]) ) concept= 1;
  else concept= 0;
  
  /* if flag */
  if( name[0] == '_' ) {
    /* get rid of ] */
    name[strlen(name)-1]= 0;
    if( s ) {
      sprintf(s, "%s ", name+1 );
      s += strlen(s);
    }
    else printf("%s ", name+1 );
  }
  
  /* if concept */
  else if( concept ) {
    /* start slot on new line */
    if( !level && !first_concept ) {
      if( s ) { sprintf(s, "\n%s:", fn); s += strlen(s); }
      else printf("\n");
    }
    
    if( s ) {
      sprintf(s, "%s.", gram->labels[edge->net]);
      s += strlen(s);
    }
    else printf("%s.", gram->labels[edge->net]);
    
    first_concept= 0;
  }
  
  pwp = edge->sw;
  /* if concept leaf, print associated string */
  if( gram->leaf[edge->net] ) {
    /* if flag value */
    if( edge->nchld && (*(gram->labels[edge->chld[0]->net]+1) == '_') ) {
      strcpy(name, gram->labels[edge->chld[0]->net]+1);
      /* get rid of ] */
      name[strlen(name)-1]= 0;
      strip_underscore(name);
      if( s ) {
	/* get rid of _ */
	sprintf(s, "%s ", name +1 );
	s += strlen(s);
      }
      else printf("%s ", name+1 );
      pwp= edge->ew+1;
    }
    /* else print string */
    else {
      for( ; pwp <= edge->ew; pwp++) {
	if( script[pwp] == -1 ) continue;
	if( script[pwp] == start_token) continue;
	if( script[pwp] == end_token) continue;
	if( s ) {
	  sprintf(s, "%s ", gram->wrds[ script[pwp] ] );
	  s += strlen(s);
	}
	else printf("%s ", gram->wrds[ script[pwp] ] );
      }
    }
  }
  else {
    /* print children */
    for( cp= edge->chld, i=0; i < edge->nchld; i++, cp++) {
      for(nxt= (*cp)->sw; pwp < nxt; pwp++) ;
      s= print_extracts( *cp, gram, s, (concept) ? level+1 : level, fn);
      pwp= (*cp)->ew+1;
    }
  }
  
  return(s);
}

// method: print_seq
//
// arguments:
//  SeqNode *ss: (input) Seqnode node input
//  char **lbl: (input) pointer to an array of char*
//
// return: none. no error conditions either.
//
// uses no global variables
// goes through the SeqNode's links and prints all the back links.
//
void print_seq(SeqNode *ss, char **lbl) {
  SeqNode	*sq;
  SeqNode	*np;

  for (sq = ss; sq; sq = sq->link) {
    for (np = sq; np; np = np->back_link) {
      printf("%s ", lbl[np->edge->net]);
    }
    printf("\n");
  }
}

// method: strip_underscore
//
// arguments:
//  char *str: (input\output) string to remove underscores
//
// return: none. no error conditions either.
//
// uses no global variables
// changes all '__' to '_' and all '_' to ' ' in the input string, in place
//
void strip_underscore(char *str) {
  char *f = str;
  char *t = str;

  // Simple Error (Although it won't bomb on the for loop, it will bomb down
  // below on *t = 0)
  if (!str)
    return;

  for(; *f; f++) {
    // if it is NOT a _, just copy and move the to-pointer
    if (*f != '_') {
      *t++ = *f;
      continue;
    }
    // if we get here, then *f == '_'
    
    // so if the NEXT character is an underscore also eg "__"
    // then save one of the underscores.
    //
    if (*(f+1) == '_') {
      *t++ = *f;
      f++;
      continue;
    }
    // else if *f == '_' and '*(f+1) is not an underscore, eg "_"
    // make it a space
    //
    else {
      *t++ = ' ';
    }
  }
  // Dont forget null
  //
  *t = (char)0;
}
