/* common.c: */

#include <ctype.h>

#include "pnm_private.h"
#include "common.h"
#include "pools.h"

/* reads one symbol from fp. If this symbol is a space, the function
 * returns 0, if it is not, it returns non-zero: used to skip one space
 * before reading raw ppm, pgm, pbm data */
int skip_one_space(FILE *fp)
{
#ifdef DDEBUG
  fprintf(stderr, "\nskip_one_space:\n");
#endif /*DDEBUG*/
  if (isspace(myfgetc(fp)))
    return 0;

  PnmError(
#ifdef DEBUG
	"skip_one_space",
#else
	NULL,
#endif
	"Input is not valid");
  return 1;
}

/* skips characters up to and including the first newline */
void skip_until_eol(FILE *fp)
{
  int c;
#ifdef DDEBUG
  fprintf(stderr, "\nskip_until_eol:\n");
#endif /*DDEBUG*/

  while ((c = myfgetc(fp)) != '\n') {}
}

/* skips spaces and comments - does nothing if the first read character is 
 * not a space or a '#'. */
void skipspace(FILE *fp)
{
  int c;
#ifdef DDEBUG
  fprintf(stderr, "\nskipspace:\n");
#endif /*DDEBUG*/

  while (isspace(c = myfgetc(fp))) {}
  if (c == '#') {	/* skip comment */
    skip_until_eol(fp);
    skipspace(fp);
  }
  else	
    myungetc(c, fp);
}

/* skips comments: if the first symbol read is a '#' all following symbols
 * up to and including the next newline character are skipped. If not,
 * nothing happens. */
void skip_comment(FILE *fp)
{
  int c;
#ifdef DDEBUG
  fprintf(stderr, "\nskip_comment:\n");
#endif /*DDEBUG*/

  if ((c = myfgetc(fp)) == '#') 
    skip_until_eol(fp);
  else
    myungetc(c,fp);
}

/* reads a series of successive digits until a non-digit is encountered,
 * converts the digits to number, returns that (non negative) number. 
 * returns negative if the first read symbol is not a digit. */
unsigned int getnatural(FILE *fp)
{
  int c;
  unsigned int num = 0;
#ifdef DDEBUG
  fprintf(stderr, "\ngetnatural:\n");
#endif /*DDEBUG*/
	
  if (!isdigit(c = myfgetc(fp))) {
    PnmError(
#ifdef DEBUG
	  "getnatural",
#else
	  NULL,
#endif
	  "Input is not valid");
    return -1;
  }
  while (isdigit(c)) {
    num *= 10;
    num += (c - '0');
    c = myfgetc(fp);
  }
  myungetc(c, fp);
  
  return num;
}

/*
 * returns 1 if reading a '0' (white) 
 *         0              '1' (black)
 *         negative     something else
 */
CVAL getbit(FILE *fp)
{
#ifdef DDEBUG
  fprintf(stderr, "\ngetbit:\n");
#endif /*DDEBUG*/

  switch (myfgetc(fp)) {
  case '0': return 1;
  case '1': return 0;
  default:
    PnmError( 
#ifdef DEBUG
	  "getbit",
#else
	  NULL,
#endif
	  "Input is not valid");
  }

  return -1;
}

/* round a up to an integer multiple of b */
#define up_mult(a, b) (b*((a+b-1)/b))

/* allocates space to hold the graphics data: nr. of channels, height and
 * width as specified in the IMAGE struct - returns zero if succesful,
 * nonzero otherwise. */
int AllocPixmap(IMAGE *pnm)
{
  int chan, row, col, pad_height, pad_width;
#ifdef DEBUG
  fprintf(stderr, "AllocPixmap: pnm->nrchannels = %ld, pnm->height = %ld, pnm->width = %ld\n", pnm->nrchannels, pnm->height, pnm->width);
#endif /*DEBUG*/
  pad_height = up_mult(pnm->height, PAD_SIZE);
  pad_width = up_mult(pnm->width, PAD_SIZE);

  pnm->pix = (CVAL ***)Alloc(pnm->nrchannels * sizeof(CVAL **));
  for (chan=0; chan < pnm->nrchannels; chan++) {
    pnm->pix[chan] = (CVAL **)Alloc(pad_height * sizeof(CVAL *));
    for (row=0; row < pad_height; row++) {
      pnm->pix[chan][row] = (CVAL *)Alloc(pad_width * sizeof(CVAL));

/* clear to zeroes */
      for (col = 0; col < pad_width; col++)
	pnm->pix[chan][row][col] = 0;
    }
  }

  return 0;
}

/* deallocates the storage allocated for the image */
void PnmFree(IMAGE *pnm)
{
  int chan, row, col, pad_height, pad_width;

  pad_height = up_mult(pnm->height, PAD_SIZE);
  pad_width = up_mult(pnm->width, PAD_SIZE);

  for (chan=0; chan < pnm->nrchannels; chan++) {
    for (row=0; row < pad_height; row++) {
      Free((char *)(pnm->pix[chan][row]), pad_width * sizeof(CVAL));
    }
    Free((char *)(pnm->pix[chan]), pad_height * sizeof(CVAL *));
  }
  Free((char *)(pnm->pix), pnm->nrchannels * sizeof(CVAL **));

  Free((char *)pnm, sizeof(IMAGE));
}
