#include "savant.h"
#include "savantio.h"
#include "yenta-savant.h"

int write_sizes(FILE *file)
{
  if ((fwrite_big(&DVM_rng, sizeof(int), 1, file) != 1) ||
      (fwrite_big(&Num_DocVecs, sizeof(int), 1, file) != 1) ||
      (fwrite_big(DVszs, sizeof(int), DVM_rng, file) != DVM_rng))
    return -1;
  return 0;
}

int read_sizes(FILE *file)
{
  if (fread_big(&DVM_rng, sizeof(DB_UINT), 1, file) != 1)
    return -1;
  if (fread_big(&Num_DocVecs, sizeof(DB_UINT), 1, file) != 1)
    return -1;
  DVM_max = 8;
  while (DVM_max <= DVM_rng)
    DVM_max = DVM_max << 1;
  DVszs = malloc(sizeof(DB_UINT) * DVM_max);
  if (fread_big(DVszs, sizeof(DB_UINT), DVM_rng, file) != DVM_rng)
    {
      free(DVszs);
      return -1;
    }
  return 0;
}

int in_write_wvtree(FILE *file, WV_Tree *tree)
{
  /* We do this in prefix order, since that means that we can get the exact
   * same tree by just loading each wv and inserting it; this operation could
   * actually balance the tree if we wanted, but the original tree should be
   * about balanced, since your documents probably don't introduce words in
   * alphabetical order. If someone decides to write a dictionary-- they don't
   * want to use Yenta on it. Duh. */

  WV_List *trav;
  char word[50];

  if (!tree)
    return 0;

  if (tree->num_docs)
    {
      decode_word(tree->wordcode, word);

#if 0
      printf("Saving %s: seen %d time(s), listed %d time(s)\n", word, 
	     tree->num_docs, tree->num_entries);
#endif

      if (fwrite_big(&tree->num_docs, sizeof(int), 1, file) != 1)
	return -1;
      
      if (fwrite_big(&tree->num_entries, sizeof(int), 1, file) != 1)
	return -1;

      if (fwrite_big(tree->wordcode, sizeof(int), WORD_ENCODE_WIDTH, file) !=
	  WORD_ENCODE_WIDTH)
	return -1;
      
      for (trav = tree->wvlist; trav; trav = trav->next)
	if (fwrite_big(&trav->docweight, sizeof(unsigned int), 1, file) != 1)
	  return -1;
    }

  if (in_write_wvtree(file, tree->left) ||
      in_write_wvtree(file, tree->right))
    return -1;
  return 0;
}

int write_wvtree(FILE *file, WV_Tree *tree)
{
  int zero = 0;
  if (in_write_wvtree(file, tree) ||
      (fwrite_big(&zero, sizeof(int), 1, file) != 1))
    return -1;
  return 0;
}

WV_Tree *read_wvtree(FILE *file)
{
  int num_entries, i, num_docs;
  WV_Tree *root = NULL, *temp, *trav;
  WV_List *tail;
  do
    {
      if (fread_big(&num_docs, sizeof(int), 1, file) != 1)
	num_docs = 0; /* Give 0 for EOF or an actual 0 */
      if (num_docs)
	{
	  fread_big(&num_entries, sizeof(int), 1, file);
	  temp = (WV_Tree *)malloc(sizeof(WV_Tree));
	  temp->num_entries = num_entries;
	  temp->num_docs = num_docs;
	  if (fread_big(temp->wordcode, sizeof(int), WORD_ENCODE_WIDTH, file)
	      != WORD_ENCODE_WIDTH)
	    printf("read failed.\n");
	  if (num_entries)
	    tail = temp->wvlist = (WV_List *)malloc(sizeof(WV_List));
	  else
	    temp->wvlist = NULL;
	  for (i = 0; i < num_entries;)
	    {
	      fread_big(&tail->docweight, sizeof(int), 1, file);
	      if (++i < num_entries)
		{
		  tail->next = (WV_List *)malloc(sizeof(WV_List));
		  tail = tail->next;
		}
	      else
		tail->next = NULL;
	    }
	  temp->left = temp->right = NULL;
	  if (root)
	    {
	      trav = root;
	      while (trav)
		{
		  i = wordcode_cmp(temp->wordcode, trav->wordcode);
		  if (i < 0)
		    if (trav->left)
		      trav = trav->left;
		    else
		      {
			trav->left = temp;
			trav = NULL;
		      }
		  else /* i can't be = 0, that would mean a bad save file */
		    if (trav->right)
		      trav = trav->right;
		    else
		      {
			trav->right = temp;
			trav = NULL;
		      }
		}
	    }
	  else
	    root = temp;
	}
    }
  while (num_docs);
  return root;
}
