#include "moss.h"

/*
******** mossValidPNM()
**
** checks to see if given Nrrd could be a PGM or PPM
**
** returns 1 if valid, 0 otherwise
*/
int
mossValidPNM(Nrrd *img) {
  char me[]="mossValidPNM", err[128];

  if (!img) {
    sprintf(err, BIFF_NULL, me);
    return 0;
  }
  
  if (nrrdTypeUChar != img->type) {
    sprintf(err, "%s: type isn't unsigned char", me);
    biffAdd(MOSS, err); 
    return 0;
  }
  if (2 != img->dim) {
    if (3 == img->dim) {
      if (3 != img->size[0]) {
	sprintf(err, "%s: need axis 0 size == 3 (not %d)", me, img->size[0]);
	biffAdd(MOSS, err);
	return 0;
      }
    }
    else {
      sprintf(err, "%s: need dimension 2 or 3 (not %d)", me, img->dim);
      biffAdd(MOSS, err);
      return 0;
    }
  }

  return 1;
}

/*
******** mossValidPoints()
**
** sees if the given Nrrd could contain valid correspondance point info
**
** returns 1 if valid, 0 otherwise
*/
int
mossValidPoints(Nrrd *points, int numImgs) {
  char me[]="mossValidPoints", err[128];
  
  if (!points) {
    sprintf(err, BIFF_NULL, me);
    return 0;
  }

  if (nrrdTypeFloat != points->type) {
    sprintf(err, "%s: type isn't float", me);
    biffAdd(MOSS, err); 
    return 0;
  }
  if (3 != points->dim) {
    sprintf(err, "%s: dimension is %d (not 3)", me, points->dim);
    biffAdd(MOSS, err);
    return 0;
  }
  if (2 != points->size[0]) {
    sprintf(err, "%s: size[0] is %d (not 2)", me, points->size[0]);
    biffAdd(MOSS, err);
    return 0;
  }
  if (numImgs != points->size[1]) {
    sprintf(err, "%s: mosaicing %d images, but have point info for %d", me,
	    numImgs, points->size[1]);
    biffAdd(MOSS, err);
    return 0;
  }

  return 1;
}

/*
******** mossValidArgs()
**
** checks to see if the args passed to mossDoit() are valid
**
** returns 1 if valid, 0 otherwise
*/
int
mossValidArgs(Nrrd **imgs, int numImgs, int which, Nrrd *points) {
  char me[]="mossValidArgs", err[128];
  int i, dim;

  if (!(imgs && points)) {
    sprintf(err, BIFF_NULL, me);
    return 0;
  }
  for (i=0; i<=numImgs-1; i++) {
    if (!mossValidPNM(imgs[i])) {
      sprintf(err, "%s: problem with input image %d", me, i);
      biffAdd(MOSS, err);
      return 0;
    }
  }
  dim = imgs[0]->dim;
  for (i=0; i<=numImgs-1; i++) {
    if (dim != imgs[i]->dim) {
      sprintf(err, "%s: image %d has dimension %d (not %d)", 
	      me, i, imgs[i]->dim, dim);
      biffAdd(MOSS, err);
      return 0;
    }
  }
  if (which < 0 || which > numImgs-1) {
    sprintf(err, "%s: reference image number (%d) not in range [0,%d]",
	    me, which, numImgs-1);
    biffAdd(MOSS, err);
    return 0;
  }
  if (!mossValidPoints(points, numImgs)) {
    sprintf(err, "%s: trouble with correspondence points information", me);
    biffAdd(MOSS, err);
    return 0;
  }
    
  return 1;
}


/*
******** mossDoit()
**
** the main function which performs the image mosaicing
*/
Nrrd *
mossDoit(Nrrd **imgs, int numImgs, int which, Nrrd *points) {
  char me[]="mossDoit", err[128];
  Nrrd *out;
  mossMatrix *matx;
  float minX, maxX, minY, maxY;
  int sizeX, sizeY;

  printf("%s: bingo 0\n", me);
  if (!(out = nrrdNew())) {
    sprintf(err, BIFF_NRRDNEW, me); return NULL;
  }

  printf("%s: bingo 1\n", me);
  if (!mossValidArgs(imgs, numImgs, which, points)) {
    sprintf(err, "%s: major trouble with input arguments", me);
    biffAdd(MOSS, err); return NULL;
  }

  printf("%s: bingo 2\n", me);
  if (!(matx = mossNewMatrix(numImgs))) {
    sprintf(err, "%s: couldn't create info matrix (size %d)", me, numImgs);
    biffAdd(MOSS, err); return NULL;
  }
  
  printf("%s: bingo 3\n", me);
  if (mossSetMatrix(matx, points)) {
    sprintf(err, "%s: trouble learning correspondence info", me);
    biffAdd(MOSS, err); return NULL;
  }

  printf("%s: bingo 4\n", me);
  if (mossLearnBounds(&minX, &maxX, &minY, &maxY, 
		      matx, imgs, numImgs, which)) {
    sprintf(err, "%s: trouble determining bounds of composite image", me);
    biffAdd(MOSS, err); return NULL;
  }
  printf("%s: ranges in X:[%g,%g], Y:[%g,%g]\n", me, minX, maxX, minY, maxY);
  
  sizeX = maxX - minX;
  sizeY = maxY - minY;
  if (!(out = nrrdNewAlloc(sizeX*sizeY*imgs[0]->size[0], 
			   nrrdTypeUChar, imgs[0]->dim))) {
    sprintf(err, "%s: couldn't allocate output image", me);
    biffMove(MOSS, err, NRRD); return NULL;
  }
  if (2 == imgs[0]->dim) {
    out->size[0] = sizeX;
    out->size[1] = sizeY;
    out->axisMin[0] = minX;
    out->axisMax[0] = maxX;
    out->axisMin[1] = minY;
    out->axisMax[1] = maxY;
  }
  else {
    out->size[0] = 3;
    out->size[1] = sizeX;
    out->size[2] = sizeY;
    out->axisMin[1] = minX;
    out->axisMax[1] = maxX;
    out->axisMin[2] = minY;
    out->axisMax[2] = maxY;
    printf("%s: axisMin = %g,%g; axisMax = %g,%g\n", me,
	   out->axisMin[1], out->axisMin[2],
	   out->axisMax[1], out->axisMax[2]);
  }

  if (mossFillImage(out, matx, imgs, numImgs, which)) {
    sprintf(err, "%s: trouble calculating values in output image", me);
    biffAdd(MOSS, err); return NULL;
  }
  
  return out;
}

