# include "pantasks.h"

# define FREEKEYS \
  if (keys) { for (i = 0; i < Nkeys; i++) { free (keys[i]); } free (keys); } \
  for (i = 0; i < setWordN; i++) { free (setWordList[i]); free (setWordValue[i]); } \
  free (setWordValue); free (setWordList);

// convert the named queue with ipptool metadata output into book format
int ipptool2book (int argc, char **argv) {

  int i, N, onPage, found, Unique, Nkeys, NKEYS;
  char *line, *tmpword, *tmpvalue;
  char pagename[512], *bookName, **keys, *p, *q;
  char **setWordList;
  char **setWordValue;
  int setWordN, setWordNalloc;

  Page *page = NULL;
  Book *book = NULL;
  Queue *queue = NULL;

  /* supply additional constant words */
  setWordN = 0;
  setWordNalloc = 10;
  ALLOCATE (setWordList, char *, setWordNalloc);
  ALLOCATE (setWordValue, char *, setWordNalloc);
  while ((N = get_argument (argc, argv, "-setword"))) {
    remove_argument (N, &argc, argv);
    setWordList[setWordN] = strcreate (argv[N]);
    remove_argument (N, &argc, argv);
    setWordValue[setWordN] = strcreate (argv[N]);
    remove_argument (N, &argc, argv);
    setWordN ++;
    if (setWordN >= setWordNalloc) {
      setWordNalloc += 10;
      REALLOCATE (setWordList, char *, setWordNalloc);
      REALLOCATE (setWordValue, char *, setWordNalloc);
    }      
  }

  Unique = FALSE;
  if ((N = get_argument (argc, argv, "-uniq"))) {
    remove_argument (N, &argc, argv);
    Unique = TRUE;
  }

  Nkeys = 0;
  keys = NULL;
  if ((N = get_argument (argc, argv, "-key"))) {
    remove_argument (N, &argc, argv);

    /* parse the key (word:word:word) into constituents */
    NKEYS = 10;
    ALLOCATE (keys, char *, NKEYS);
    
    p = q = argv[N];
    while (q != NULL) {
      q = strchr (p, ':');
      keys[Nkeys] = (q == NULL) ? strcreate (p) : strncreate (p, q - p);
      p = q + 1;
      Nkeys ++;
      CHECK_REALLOCATE (keys, char *, NKEYS, Nkeys, 10);
    }
    remove_argument (N, &argc, argv);
  }

  if (argc != 3) {
    gprint (GP_ERR, "USAGE: ipptool2book (queue) (book) [-uniq] [-key key[:key..]]\n");
    FREEKEYS;
    return (FALSE);
  }

  queue = FindQueue (argv[1]);
  if (queue == NULL) {
    gprint (GP_ERR, "queue %s not found\n", argv[1]);
    FREEKEYS;
    return (FALSE);
  }
    
  book = CreateBook (argv[2]);

  /* the first non-whitespace line of the queue should contain:
     BookName MULTI
  */

  /* scan for first non-emtpy line */
  while (TRUE) {
    line = PopQueue (queue);
    if (!line) {
      FREEKEYS;
      return (TRUE); // no output in queue - not an error?
    }
    if (*line) break;
    free (line);
  }
  bookName = thisword (line);
  tmpword = nextword (line);

  if (strcmp(tmpword, "MULTI")) {
    gprint (GP_ERR, "ERROR: missing metadata output name on first line\n");
    free (bookName);
    free (line);
    FREEKEYS;
    return FALSE;
  }
  if (strcmp(bookName, argv[2])) {
    gprint (GP_ERR, "WARNING: metadata output name %s does not match expected bookname %s\n", bookName, argv[2]);
  }
  free (line);
  
  onPage = FALSE;
  while (TRUE) {
    line = PopQueue (queue);
    if (!line) {
      free (bookName);
      if (onPage) {
	gprint (GP_ERR, "ERROR: unterminated metadata\n");
	FREEKEYS;
	return (FALSE);
      }
      FREEKEYS;
      return (TRUE);
    }
    if (!*line) {
      free (line);
      continue;
    }
    
    tmpword = thisword (line);
    if (tmpword == NULL) abort(); // should not happen if line exists

    if (!onPage) {
      if (strcmp(tmpword, bookName)) {
	gprint (GP_ERR, "ERROR: unexpected metadata name %s\n", tmpword);
	free (line);
	free (tmpword);
	free (bookName);
	FREEKEYS;
	return (FALSE);
      }
      free (tmpword);
      tmpword = thisword (nextword (line));
      if (strcmp(tmpword, "METADATA")) {
	gprint (GP_ERR, "ERROR: missing METADATA tag\n");
	free (line);
	free (tmpword);
	free (bookName);
	FREEKEYS;
	return FALSE;
      }
      onPage = TRUE;
      // we don't know the page name until we load its data?
      sprintf (pagename, "page.%03d", book[0].Npages);
      page = CreatePage (book, pagename);
      free (line);
      free (tmpword);
      continue;
    } 

    /* close out the page */
    if (!strcmp(tmpword, "END")) {
      // XXX set the page name based on the contents
      free (tmpword);
      free (line);

      if (keys) {
	memset (pagename, 0, 512);
	for (i = 0; i < Nkeys; i++) {
	  tmpword = BookGetWord (page, keys[i]);
	  if (tmpword == NULL) {
	    gprint (GP_ERR, "ERROR: missing key %s for ID\n", keys[i]);
	    FREEKEYS;
	    return (FALSE);
	  }
	  if (i > 0) strcat (pagename, ":");
	  strcat (pagename, tmpword);
	}
	free (page[0].name);
	page[0].name = strcreate (pagename);
      }

      // add the fixed words to the page
      for (i = 0; i < setWordN; i++) {
	BookSetWord (page, setWordList[i], setWordValue[i]);
      }

      if (Unique) {
	/* search for an existing page with this name
	   delete this one if one is found */
	/* XXX don't attach this page to the book until this step is passed */	

	found = FALSE;
	for (i = 0; !found && (i < book[0].Npages); i++) {
	  if (book[0].pages[i] == page) continue;
	  if (!strcmp (book[0].pages[i][0].name, page[0].name)) {
	    found = TRUE;
	  }
	}
	if (found) {
	  DeletePage (book, page);
	}
      }

      onPage = FALSE;
      continue;
    }

    tmpvalue = thisword (nextword(nextword(line)));
    if (tmpvalue == NULL) {
      gprint (GP_ERR, "ERROR: missing value for %s\n", tmpword);
      free (tmpword);
      free (line);
      free (bookName);
      FREEKEYS;
      return (FALSE);
    }
    BookSetWord (page, tmpword, tmpvalue);
    free (tmpword);
    free (tmpvalue);
    free (line);
  }    
  FREEKEYS;
  return (FALSE);
}

/* scan through the queue lines.  these should look like:  

bookName METADATA
key type value
key type value
...
END

bookName METADATA
key type value
key type value
...
END
*/
