#include <stdio.h>
#include <string.h>
#include "cgiutils.h"
#include "taxon_tree.h"

int alldigits(char *s)
{
  char *t ;
  int res ;

  if (s[0] == '\0') return(0) ;

  for (res=1, t=s ; res && *t != '\0' ; t++) 
    res = isdigit(*t) || *t == '.' ;

  return res ;
}

typedef struct _expand_item {
  int val ;
  int start ;
  int end ;
  struct _expand_item *next ;
  struct _expand_item *child ;
  struct _expand_item *parent ;
} expand_item ;

expand_item *exp_root ;
char *items, *fname ;

expand_item *insert_item(expand_item **root, expand_item *parent, 
			 int val, int start, int end)
{
  expand_item *ptr, *newptr ;

  if (*root == NULL) {
    ptr = (expand_item *)malloc(sizeof(expand_item)) ;
    ptr->next = *root ;
    *root = ptr ;
  }
  else {
    for (ptr = *root ; ptr->next != NULL ; ptr = ptr->next) ;
    ptr->next = (expand_item *)malloc(sizeof(expand_item)) ;
    ptr = ptr->next ;
    ptr->next = NULL ;
  }
  ptr->parent = parent ;
  ptr->child = NULL ;
  ptr->val = val ;
  ptr->start = start ;
  ptr->end = end ;
  return(ptr) ;
}

void print_contraction_string(expand_item *ptr, expand_item *to_exclude)
{
  while (ptr != NULL) {
    if (ptr != to_exclude) {
      printf("%d", ptr->val) ;
      if (ptr->child != NULL && 
	  !(ptr->child == to_exclude && ptr->child->next == NULL)) {
	putchar('(') ;
	print_contraction_string(ptr->child, to_exclude) ;
	putchar(')') ;
      }
      else 
	if (ptr->next != NULL && ptr->next != to_exclude) putchar(',') ;
    }
    ptr = ptr->next ;
  }
  
}


void dump_work(FILE *fp, char *cur_dom, expand_item *exp_ptr, 
	       int tablevel, char *pre_str, char *post_str) 
{
  char s[80] ;
  char domain[80] ;
  int num ;
  char new_dom[128] ;
  int paren_total ;
  int item_count ;
  int i ;
  char pre_space[1024], post_space[1024] ;
  char *new_pre_str, *new_post_str ;

  item_count = 1 ;
  fgets(s, 80, fp) ;
  do {
    if (!feof(fp) && strchr(s, ')') == NULL) {
      *strrchr(s, '\n') = '\0' ;
      sscanf(s, "%s %d", &domain, &num) ;
      if (cur_dom[0] == '\0')
	strcpy(new_dom, domain) ;
      else if (alldigits(cur_dom))
	sprintf(new_dom, "%s.%s", cur_dom, domain) ;
      else sprintf(new_dom, "%s.%s", domain, cur_dom) ;
      for (i=0 ; i < tablevel ; i++) putchar(' ') ;
      if (strchr(s, '(') != NULL) {
	new_pre_str = new_post_str = NULL ;
	printf("<a href=\"/FLORA/cgi/domain_hit_expand?f=%s&items=",
	       fname) ;
	if (exp_ptr == NULL) {
	  if (exp_root == NULL) {
	    /* nothing expanded - just add the item */
	    printf("%d", item_count) ;
	  }
	  else {
	    /* stuff expanded, item is currently a leaf, so add it
	       in current context */
	    printf("%s%d%s", pre_str, item_count, post_str) ;
	  }
	}
	else if (exp_ptr->val != item_count) {
	  /* stuff expanded, but item is not a leaf */
	  /* need to examine exp_ptr to figure out the context */
	  i = 0 ;
	  if (item_count < exp_ptr->val) {
	    /* i.e. this item is not "after" all currently expanded
	       items at this level */
	    while (i < exp_ptr->start)
	      putchar(items[i++]) ;
	    printf("%d,", item_count) ;
	    while (items[i] != '\0') putchar(items[i++]) ;
	  }
	  else {
	    /* item should be tacked onto end of list */
	    while (i < exp_ptr->end)
	      putchar(items[i++]) ;
	    printf(",%d", item_count) ;
	    printf("%s", items+exp_ptr->end) ;
	  }
	}
	else {
	  /* this item is currently being expanded.
	     must construct a URL to indicate contraction
	     plus, one must also construct pre and post strings */

	  print_contraction_string(exp_root, exp_ptr) ;

	  new_pre_str = pre_space ;
	  new_post_str = post_space ;

	  for (i=0 ; i < exp_ptr->end ; i++)
	    new_pre_str[i] = items[i] ;
	  new_pre_str[i] = '(' ;
	  new_pre_str[i+1] = '\0' ;
	  new_post_str[0] = ')' ;
	  if (items[exp_ptr->end] == ',') 
	    strcpy(new_post_str+1, items+exp_ptr->end+1) ;
	  else strcpy(new_post_str+1, items+exp_ptr->end) ;
	}
	printf("\">") ;
      }
      printf("%s", new_dom) ;
      if (strchr(s, '(') != NULL) 
	printf("</a>") ;
      printf(": %d\n", num) ;
      if (strchr(s, '(') != NULL) {
	if (exp_ptr != NULL && exp_ptr->val == item_count) {
	  dump_work(fp, new_dom, exp_ptr->child, tablevel+2,  
		    new_pre_str, new_post_str) ;
	  if (exp_ptr->next != NULL) exp_ptr = exp_ptr->next ;
	}
	else {
	  paren_total = 1 ;
	  while (paren_total > 0) {
	    fgets(s, 80, fp) ;
	    if (strchr(s, '(') != NULL) paren_total++ ;
	    else if (strchr(s, ')') != NULL) paren_total-- ;
	  }
	}
      }
      item_count++ ;
      fgets(s, 80, fp) ;
    }
  } while (!feof(fp) && strchr(s, ')') == NULL) ;
}

void add_tree_items(expand_item **root, char *s, int start)
{
  int i ;
  char temp[10] ;
  expand_item *nptr ;

  i = 0 ;
  while (s[i] != '\0' && s[i] != ')') {
    while (isdigit(s[i])) i++ ;
    strncpy(temp, s, i) ;
    temp[i] = '\0' ;		/* the number */
    
    if (s[i] == ',') {
      if (i > 0)
	insert_item(root, NULL, atoi(temp), start, start+i) ;
      i++ ;
      s += i ;
      start += i ;
      i = 0 ;
    }
    else if (s[i] == '(') {
      int subitems_start, subitems_end, paren_count, j ;

      subitems_start = start+i+1 ;

      paren_count = 1 ;
      i++ ;
      j = i ;
      while (paren_count > 0) {
	if (s[j] == '(')
	  paren_count++ ;
	else if (s[j] == ')')
	  paren_count-- ;
	j++ ;
      }
      subitems_end = start+j ;
      nptr = insert_item(root, NULL, atoi(temp), start, subitems_end) ;
      add_tree_items(&(nptr->child), s+i, subitems_start) ;
      s += j ;
      start = subitems_end ;
      i = 0 ;
    }
    else {
      insert_item(root, NULL, atoi(temp), start, start+i) ;
    }
  }
}

main()
{
  FILE *fp ;
  int last_expanded_depth ;

  decode_query_string("f", &fname, "items", &items, NULL) ;

  exp_root = NULL ;

  if (items != NULL) 
    add_tree_items(&exp_root, items, 0) ;

  return_header("text/html") ;
  printf("<pre>\n") ;

  fp = fopen(fname, "r") ;

  dump_work(fp, "", exp_root, 0, NULL, NULL) ;

  fclose(fp) ;
  printf("</pre>") ;
}
