/*
** read.c
*/

#include <stdio.h>
#include "peek.h"

/*
** read_vert
** reads one vertex from given object_file, adds it to given piece.
*/
int
read_vert(FILE *object_file, Piece *piece, int space_d) {
  int 
    i,
    result;
  char err2[ERRSTRLEN];
  Part *vert;

#ifdef DEBUG
  printf("read_vert: calling build_part()\n");
#endif
  build_part(&vert, 0, 0, 0, NULL, NULL);
#ifdef DEBUG
  printf("read_vert: calling tag()\n");
#endif
  tag(piece, vert);
  for (i=0; i<space_d; i++) {
    if (EOF == get_float(object_file, (vert->coord_hold)+i)) {
      sprintf(err2,"read_vert: coord %d for vert/part %d\n", i, vert->ID);
      strcat(err, err2); return(-1);
    }
    (vert->coord)[i] = (vert->coord_hold)[i];
  }
#ifdef DEBUG
  printf("read_vert: done reading coords, pos = %ld\n", 
	 1+ftell(object_file));
#endif
  /* make sure we're at end of coord list */
  if (ENDLIST != get_int(object_file, NULL)) {
    sprintf(err2, "read_vert: expected ENDLCH after coords for vert %d\n",
	    vert->ID);
    strcat(err, err2); return(-1);
  }
#ifdef DEBUG
  printf("read_vert: now reading color, pos = %ld\n",
	 1+ftell(object_file));
#endif
  for (i=0; i<COLORS; i++) {
    if (EOF == get_float(object_file, (vert->color)+i)) {
      sprintf(err2, "read_vert: color %d for ver/part %d\n", i, vert->ID);
      strcat(err, err2); return(-1);
    }
  }
  return(0);
}

/*
** read_part
** reads one part from given object_file, adds it to given piece.
** Interprets link values according to offset[d]
*/
int
read_part(FILE *object_file, Piece *piece, int d, int space_d) {
  int 
    link,
    result,
    i;
  Image *image;
  Part *part;
  char err2[ERRSTRLEN];

  result = 0;
  image = NULL;
#ifdef DEBUG
  printf("read_part: calling build_part()\n");
#endif
  build_part(&part, d, 0, 0, NULL, NULL);
#ifdef DEBUG
  printf("read_art: calling tag()\n");
#endif
  tag(piece, part);
  /* read link values, create image list */
  while (ENDLIST != result) {
    result = get_int(object_file, &link);
    if (EOF == result) {
      sprintf(err2, "read_part: link values for part %d\n", part->ID);
      strcat(err, err2); return(-1);
    }
    else if (ENDLIST != result) {
      if (!image) {
	if (image_alloc(&(part->thought))) {
	  sprintf(err2, "read_part: first image for part %d\n", part->ID);
	  strcat(err, err2); return(-1);
	}
	image = part->thought;
      }
      else {
	if (image_alloc(&(image->next))) {
	  sprintf(err2, "read_part: other image for part %d\n", part->ID);
	  strcat(err, err2); return(-1);
	}
	image = image->next;
      }
      /* THE BIG IMPORTANT STEP:
	 link this image to the part referred to by link, which is
	 to be interpreted according to the offset array */
      image->sense = (piece->catalog)[(piece->offset)[d-1] + link];
#ifdef DEBUG
      printf("read_part: made part %d a kid of part %d\n", 
	     image->sense->ID, part->ID);
#endif
    }
  }
  image->next = NULL;
  if (d < piece->piece_d) {
    /* read in colors */
    for (i=0; i<COLORS; i++) {
      if (EOF == get_float(object_file, (part->color) + i)) {
	sprintf(err2, "read_part: colors for part %d\n", part->ID);
	strcat(err, err2); return(-1);
      }
    }
  }
  else {
#ifdef DEBUG
    printf("read_part: will read open/closed\n");
    printf("read_part: file position now %ld\n", 1+ftell(object_file));
#endif
    /* read in open/closed */
    if (EOF == get_int(object_file, &(part->spare))) {
      sprintf(err2, "read_part: open/closed for part %d\n", part->ID);
      strcat(err, err2); return(-1);
    }
#ifdef DEBUG
    printf("read_part: read open/closed as %d\n", part->spare);
    printf("read_part: file position now %1d\n", 1+ftell(object_file));
#endif
  }
  return(0);
}

/*
** read_partseg
** reads one part segment from given object_file, adds parts to given
** piece.  
*/
int
read_partseg(FILE *object_file, Piece *piece, int d, int space_d) {
  int
    num_parts,
    p;           /* which part is now being read */
  char err2[ERRSTRLEN];

  /* read num_parts */
  if (EOF == get_int(object_file, &num_parts)) {
    sprintf(err2, "read_partseg: couldn't read num_parts\n");
    strcat(err, err2); return(-1);
  }
  if (num_parts < 1) {
    sprintf(err, "read_partseg: num_parts of %d is not valid\n", num_parts);
    strcat(err, err2); return(-1);
  }

  /* read in parts */
  for (p=1; p<=num_parts; p++) {
    if (0 == d) {
#ifdef DEBUG
      printf("read_partseg: calling read_vert(); d = %d, p = %d\n", 
	     d, p);
#endif
      if (read_vert(object_file, piece, space_d)) {
	sprintf(err2, "read_partseg: p = %d\n", p);
	strcat(err, err2); return(-1);
      }
    }
    else {
#ifdef DEBUG
      printf("read_partseg: calling read_part(); d = %d, p = %d\n", 
	     d, p);
#endif
      if (read_part(object_file, piece, d, space_d)) {
	sprintf(err, "read_partseg: p = %d\n", p);
	strcat(err, err2); return(-1);
      }
    }
  }
#ifdef DEBUG
  printf("**********\n *********\n\n read_partseg: done with segment for d = %d\n************\n*********\n\n", d);
#endif
  /* knowing how many parts of dimension d there were, we set 
     offset[d+1] */
  (piece->offset)[d+1] = num_parts + (piece->offset)[d];
#ifdef DEBUG
  printf("read_partseg: (d = %d) ** (piece->offset)[%d] = %d\n",
	 d, d+1, (piece->offset)[d+1]);
#endif
  return(0);
}

/*
** read_piece()
** reads one piece section from given object_file, points *piece to new piece
*/
int
read_piece(FILE *object_file, Piece **piece, int space_d) {
  int 
    piece_d,
    d,          /* dimension of parts in current part segment */
    result,
    link,
    i;
  char err2[ERRSTRLEN];
  Image *image;
  
#ifdef DEBUG
  printf("read_piece: &piece = %ld, piece = %ld, *piece = %ld\n",
	 &piece, piece, *piece);
#endif
  /* read piece_d */
  if (EOF == get_int(object_file, &piece_d)) {
    sprintf(err2, "read_piece: couldn't read piece_d\n");
    strcat(err, err2); return(-1);
  }
  /* check validity of piece_d */
  if (piece_d < 1 || piece_d > MAXSPACED) {
    sprintf(err, "read_piece: piece_d of %d not valid\n");
    return(-1);
  }

  build_piece(piece, piece_d, space_d, NULL, NULL);
#ifdef DEBUG
  printf("read_piece: built piece; *piece = %ld; (*piece)->catalog = %ld\n",
	 *piece, (*piece)->catalog);
#endif
  /* we have the luxery of reading parts in dimensional order; so
     do build the offset array */
  (*piece)->offset = (int *) malloc((MAXSPACED+1) * sizeof(int));
  (*piece)->offset[0] = 0;

  /* read all part segments for this piece */
  for (d=0; d<=piece_d; d++) {
#ifdef DEBUG
    printf("read_piece: calling read_partseg(), d = %d\n", d);
    printf("read_piece: file position now %ld\n", 1+ftell(object_file));
#endif
    if (read_partseg(object_file, *piece, d, space_d)) {
      sprintf(err2, "read_piece: failed on partseg of d = %d\n", d);
      strcat(err, err2); return(-1);
    }
  }
  
#ifdef DEBUG
     printf("read_piece: Done reading all partsegs\n");
    printf("read_piece: file position now %ld\n", 1+ftell(object_file));
#endif
  /* build list of surfaces under piece */
  result = 0;
  image = NULL;
  while (ENDLIST != result) {
    result = get_int(object_file, &link);
    if (EOF == result) {
      sprintf(err2, "read_piece: couldn't read link values for surfaces\n");
      strcat(err, err2); return(-1);
    }
#ifdef DEBUG
    printf("read_piece: read a (surface) link value of %d\n", link);
    printf("read_piece: file position now %ld\n", 1+ftell(object_file));
#endif
    if (ENDLIST != result) {
      if (!image) {
	if (image_alloc(&image)) {
	  sprintf(err2, "read_piece: making first surface image\n");
	  strcat(err, err2); return(-1);
	}
	(*piece)->thought = image;
      }
      else {
	if (image_alloc(&(image->next))) {
	  sprintf(err2, "read_piece: making other surface image\n");
	  strcat(err, err2); return(-1);
	}
	image = image->next;
      }
      /* here we are cheating somewhat.  At this point d has a value
	 one more than piece_d, but is still useful because the
	 surfaces-comprising-piece level is just one higher than
	 all the previous parts-comprising-part levels, so it makes
	 sense to use the offset array when assembling surfaces into
	 pieces just as we did to assemble parts into other parts */
#ifdef DEBUG
/*      printf("read_piece: d-1 = %d, ((*piece)->offset)[d-1] + link = %d\n",
	     d-1, ((*piece)->offset)[d-1] + link);*/
#endif
      image->sense = ((*piece)->catalog)[((*piece)->offset)[d-1] + link];
    }
  }
  image->next = NULL;
  /* read in color for interior of this piece */
  for (i=0; i<COLORS; i++) {
    if (EOF == get_float(object_file, ((*piece)->color) + i)) {
      sprintf(err2, "read_piece: color %d for piece\n", d);
      strcat(err, err2); return(-1);
    }
  }
  return(0);
}

/*
** read_object()
** reads object from given object_file, points *object_ptr to new object
*/
int
read_object(FILE *object_file, Piece **object_ptr) {
  int 
    space_d,
    num_pieces,
    which_piece;
  char err2[ERRSTRLEN];
  Piece 
    *piece,
    *last;
  
#ifdef DEBUG
  printf("welcome to read_object()\n");
#endif

  /* read space_d */
  if (EOF == get_int(object_file, &space_d)) {
    sprintf(err2, "read_object: Couldn't read space_d from object file\n");
    strcat(err, err2); return(-1);
  }
  /* check validity of space_d */
  if (space_d < 1 || space_d > MAXSPACED) {
    sprintf(err, "read_object: space_d of %d is not valid (%s)\n", space_d);
    return(-1);
  }
#ifdef DEBUG
  printf("space_d = %d\n", space_d);
#endif
  /* read num_pieces */
  if (EOF == get_int(object_file, &num_pieces)) {
    sprintf(err2, "read_object: Couldn't read num_pieces from object file\n");
    strcat(err, err2); return(-1);
  }
  /* check validity of num_pieces */
  if (num_pieces < 1) {
    sprintf(err, "read_object: %d is not a valid num_pieces\n", num_pieces);
    return(-1);
  }
#ifdef DEBUG
  printf("num_pieces = %d\n", num_pieces);
#endif
  /* go to end of preamble, we should already be there */
  if (next_sect(object_file)) {
    sprintf(err2, "read_object: Couldn't get to first piece section\n");
    strcat(err, err2); return(-1);
  }

#ifdef DEBUG
  printf("starting to read piece sections\n");
#endif

  /* read piece sections, assemble piece list */
  last = NULL;
  for (which_piece=1; which_piece<=num_pieces; which_piece++) {
#ifdef DEBUG
    printf("read_object: calling read_piece(); which_piece = %d\n",
	   which_piece);
#endif
    if (read_piece(object_file, &piece, space_d)) {
      sprintf(err2, "read_object: couldn't read piece %d\n", which_piece);
      strcat(err, err2); return(-1);
    }
    if (1 == which_piece) {
      (*object_ptr) = piece;
    }
    if (last)
      last->next = piece;
    last = piece;
    if (next_sect(object_file)) {
      sprintf(err2, "read_object: seeking section end after piece %d\n", 
	      which_piece);
      strcat(err, err2); return(-1);
    }
  }
  piece->next = NULL;
  return(0);
}
