#include <config.h>
#include <stdio.h>
#include <math.h>
#include <errno.h>

#include "GFile_TIFF.h"

/* GFile (ie. GImage) decendent for reading TIFF files.
 *
 * Written by:  Chris Studholme
 * Last Update: 28-May-2000
 * Copyright:   GPL (http://www.fsf.org/copyleft/gpl.html)
 */


//#define _CHECKS
#ifdef _CHECKS
double VerifyImage(GImageComponent* image, const unsigned char* imagedata,
		   int w, int h) {
  double error=0;
  for (int y=0; y<h; ++y)
    for (int x=0; x<w; ++x) {
      int residule = (imagedata[y*w+x]-128)*128 - image->getPixel(x,y,x+1,y+1);
      error += residule*residule;
      //error += residule<0 ? -residule : residule;
    }
  return sqrt(error/w/h)/128;
  //return error/w/h/128;
}
#endif


/* ================ GFile_TIFF methods  ================ */

GFile_TIFF::GFile_TIFF(const char* filename, bool fast) {
  imagefile = TIFFOpen(filename,"r");
  if (imagefile==0) {
    fprintf(stderr,"GFile_TIFF::GFile_TIFF, cannot read file '%s'\n",filename);
    return;
  }
  ReadImage(fast);
}

/*
  GFile_TIFF::GFile_TIFF(FILE* infile) {
  imagefile = infile;
  ReadImage();
}
*/

GFile_TIFF::~GFile_TIFF() {
  if (imagefile)
    TIFFClose(imagefile);
  if (red)
    delete red;
  if (green)
    delete green;
  if (blue)
    delete blue;
}

bool GFile_TIFF::supportsFile(FILE* file) {
  if (fseek(file,0,SEEK_SET)!=0) {
    fprintf(stderr,"GFile_TIFF::supportsFile() fseek() failed %d\n",errno);
    return false;
  }
  unsigned char header[4];
  if (fread(header,sizeof(header),1,file)!=1) {
    fprintf(stderr,"GFile_TIFF::supportsFile() fread() failed %d\n",errno);
    return false;
  }
  return (((header[0]=='M')&&(header[1]=='M')&&
           (header[2]==0)&&(header[3]==42))||
          ((header[0]=='I')&&(header[1]=='I')&&
           (header[2]==42)&&(header[3]==0)));
}

void GFile_TIFF::ReadImage(bool fast) {

  TIFFGetField(imagefile, TIFFTAG_IMAGEWIDTH, &w);
  TIFFGetField(imagefile, TIFFTAG_IMAGELENGTH, &h);

  int npixels = w*h;
  uint32* raster = new uint32[npixels];
  if (raster==NULL) {
    fprintf(stderr,"GFile_TIFF::ReadImage, failed to allocate memory\n");
    TIFFClose(imagefile);
    imagefile=0;
    return;
  }

  if (!TIFFReadRGBAImage(imagefile, w, h, raster, 0)) {
    fprintf(stderr,"GFile_TIFF::ReadImage, failed to read image\n");
    TIFFClose(imagefile);
    imagefile=0;
    return;
  }
  
  // process image
  unsigned char* color = new unsigned char[npixels];

  fprintf(stderr,"Initializing linear matrix... ");
  for (int y=0; y<h; ++y)
    for (int x=0; x<w; ++x)
      color[(h-1-y)*w+x] = TIFFGetR(raster[y*w+x]);
  red = new GImageComponent0(color,w,h,fast?-1:0);
#ifdef _CHECKS
  fprintf(stderr,"\nRed Error(l1): %g\n",red->getTotalError());
  fprintf(stderr,"Red Error(l2): %g\n",VerifyImage(red,color,w,h));
#endif
 
  fprintf(stderr,"red... ");
  for (int y=0; y<h; ++y)
    for (int x=0; x<w; ++x)
      color[(h-1-y)*w+x] = TIFFGetG(raster[y*w+x]);
  green = new GImageComponent0(color,w,h,fast?-1:0);
#ifdef _CHECKS
  fprintf(stderr,"\nGreen Error(l1): %g\n",green->getTotalError());
  fprintf(stderr,"Green Error(l2): %g\n",VerifyImage(green,color,w,h));
#endif

  fprintf(stderr,"green... ");
  for (int y=0; y<h; ++y)
    for (int x=0; x<w; ++x)
      color[(h-1-y)*w+x] = TIFFGetB(raster[y*w+x]);
  blue = new GImageComponent0(color,w,h,fast?-1:0);
#ifdef _CHECKS
  fprintf(stderr,"\nBlue Error(l1): %g\n",blue->getTotalError());
  fprintf(stderr,"Blue Error(l2): %g\n",VerifyImage(blue,color,w,h));
#endif

  fprintf(stderr,"blue, done.\n");
  if (!fast)
    fprintf(stderr,"Total Error is %g\n",red->getTotalError()+
	    green->getTotalError()+blue->getTotalError());

  delete[] color;
  delete[] raster;
}

const char* GFile_TIFF::getComments() {
  return NULL;
}

/* width/height of individual pixel */
double GFile_TIFF::getAspectRatio() {
  return 1;
}

 
