/* imageio: basic image functions*/
/* ImageMagick version, BETA Code*/

#include "defs.h"
#include <stdio.h>
#include <stdlib.h>
#include "magick/api.h"
#include <string.h>
#ifdef USE_CLUSTER
#include "cluster.h"
#endif


/*Internal functions:-------------------------------------------------------*/
int magick_initialized=0;
ExceptionInfo	magick_exception;

void init_if_needed() {

   if (magick_initialized==0) {
      magick_initialized=1;
      InitializeMagick("");
      GetExceptionInfo(&magick_exception);
   }

}


/*External functions:-------------------------------------------------------*/

typedef struct {
#ifdef USE_SPEEDHACK
   unsigned char *pixeldata;
   int width;
   int height;
#else
   Image *image;
   ImageInfo *info;
#endif
   int red[256];
   int green[256];
   int blue[256];
   int lastcolor;
} ImagePtr;

/*---------------------------------------------------------------------------*/

ImagePtr* loadim(char* filename) {
/*Loads an Image*/
/*Returns gdImagePtr to image structure if succesfull and NULL if not*/

   ImagePtr *im;		/*ImagePointer to the image*/
#ifdef USE_SPEEDHACK
   Image *image;
   ImageInfo *info;
#endif

#ifdef USE_DEBUG
   fprintf(stderr,"Opening image %s with Imagemagick...\n",filename);
#endif

   im=(ImagePtr*)malloc(sizeof(ImagePtr));
   init_if_needed();   

#ifdef USE_SPEEDHACK
   info=CloneImageInfo((ImageInfo *) NULL);
   strcpy(info->filename,filename);
   info->colorspace=RGBColorspace;
   info->depth=8;
   /*set to the same we use, to make pixelextraction potentially faster*/
   image=ReadImage(info,&magick_exception);
   if (image== NULL) {
#else
   im->info=CloneImageInfo((ImageInfo *) NULL);
   strcpy(im->info->filename,filename);
   im->info->colorspace=RGBColorspace;
   im->image=ReadImage(im->info,&magick_exception);
   if (im->image== NULL) {
#endif
      fprintf (stderr,"Error: Couldnt load %s\n",filename);
      return NULL;
   }

   if (magick_exception.severity != UndefinedException)
       CatchException(&magick_exception);
   im->lastcolor=0;

#ifdef USE_DEBUG
   #ifdef USE_SPEEDHACK
      DisplayImages(info,image);
   #else
      DisplayImages(im->info,im->image);
   #endif
#endif

  
#ifdef USE_SPEEDHACK
   im->height=image->rows;
   im->width=image->columns;
   im->pixeldata=(unsigned char *)malloc(sizeof(unsigned char)*im->height*im->width*3);
   if (im->pixeldata==NULL) {
      fprintf(stderr,"Error: Could not allocate image memory\n");
      return NULL;
   }
   ExportImagePixels ( image, 0, 0, im->width,im->height,
      "RGB", CharPixel, im->pixeldata, &magick_exception );
   if (magick_exception.severity != UndefinedException)
       CatchException(&magick_exception);
   DestroyImage(image);
   DestroyImageInfo(info);
#endif
   
   return im;
   /*Thats all folks*/
}

/*---------------------------------------------------------------------------*/

int saveim(ImagePtr *im, char* filename) {
/*Saves the Image in a file*/
/*Returns null if sucessfull and -1 if not*/

#ifdef USE_SPEEDHACK
   Image *image;
   ImageInfo *info;

#ifdef USE_DEBUG
   fprintf(stderr,"Saving as image %s with Imagemagick...\n",filename);
#endif
   
   init_if_needed();
   image= ConstituteImage ( im->width, im->height,
      "RGB", CharPixel, im->pixeldata, &magick_exception );
   if (magick_exception.severity != UndefinedException)
       CatchException(&magick_exception);
   if (image==NULL) {
      fprintf(stderr,"Error: could not allocate image for safing!\n");
   }
   info=CloneImageInfo((ImageInfo *) NULL);
   #ifdef USE_DEBUG
      DisplayImages(info,image);
   #endif
   strcpy(image->filename,filename);
   WriteImage(info,image);
   DestroyConstitute();
   DestroyImage(image);
   DestroyImageInfo(info);

#else
   #ifdef USE_DEBUG
      DisplayImages(im->info,im->image);
   #endif
   strcpy(im->image->filename,filename);
   WriteImage(im->info,im->image);
   /* TODO: ImageMagick could fail, but i just dunno the return value so
            for now i assume it always works.
            If it doesnt its no problem for me, since
            our program is possibly done with that image >;>>>*/

#endif
   return 0;

}

/*---------------------------------------------------------------------------*/

inline ImagePtr* createim(int width, int height) {
/*Creates an Image*/
/*Returns ImagePtr to image structure if succesfull and NULL if not*/

   ImagePtr *im;
   im=(ImagePtr*)malloc(sizeof(ImagePtr));

#ifndef USE_SPEEDHACK   
   #ifdef USE_DEBUG
      fprintf(stderr,
      "Creating empty image %ix%i with Imagemagick...\n",
      width,height);
   #endif
   im->info=CloneImageInfo((ImageInfo *) NULL);
   im->image=AllocateImage(im->info);
   im->image->columns=width;
   im->image->rows=height;
   im->image->colorspace=RGBColorspace;
   im->image->depth=8;
   
   if (im->image==NULL) {
#else
   #ifdef USE_DEBUG
      fprintf(stderr,
      "Creating empty image %ix%i with Motiontrack engine...\n",
      width,height);
   #endif
   im->height=height;
   im->width=width;
   im->pixeldata=(unsigned char *)malloc(sizeof(unsigned char)*im->height*im->width*3);

   if (im->pixeldata==NULL) {
#endif
      fprintf(stderr,"Error: Could not create new image\n");
      return NULL;
   }
   im->lastcolor=0;
  
   return im;

}

/*---------------------------------------------------------------------------*/

inline int destroyim (ImagePtr *im) {
/*Frees image memory*/



#ifdef USE_SPEEDHACK
   #ifdef USE_DEBUG
      fprintf(stderr,"Deallocating Motiontrack image structure...\n");
   #endif
   free(im->pixeldata);
#else
   #ifdef USE_DEBUG
      fprintf(stderr,"Deallocating Imagemagick image structure...\n");
   #endif
   DestroyImage(im->image);
   DestroyImageInfo(im->info);
#endif
   free(im);
   return 0;
}

/*---------------------------------------------------------------------------*/

inline int widthim(ImagePtr *im) {
/*Returns the images X width*/

#ifdef USE_SPEEDHACK
   return im->width;
#else
   return im->image->columns;
#endif
}

/*---------------------------------------------------------------------------*/

inline int heightim(ImagePtr *im) {
/*Returns the images X width*/
#ifdef USE_SPEEDHACK
   return im->height;
#else
   return im->image->rows;
#endif
}

/*---------------------------------------------------------------------------*/

inline int collorallocateim(ImagePtr *im,int r,int g,int b) {
/*Allocates a color structure*/
/*Returns an ID integer of this*/

   if (im->lastcolor<256) {
      im->red[im->lastcolor]=r;
      im->green[im->lastcolor]=g;
      im->blue[im->lastcolor]=b;
      return im->lastcolor++;
   } else {
      return 0;
   }

}

/*---------------------------------------------------------------------------*/

inline int pixelbrightcim(int r, int g, int b) {
/*Gives back the corresponding pixelbrightness*/
   return ((r+g+b)/3);
}

/*---------------------------------------------------------------------------*/

inline int pixelbrightim(ImagePtr *im,int x,int y) {
/*Gives back the pixelbrightness at x,y in im*/
/*Gives back 0 if error (x,y out of range or so)*/

#ifndef USE_SPEEDHACK
   PixelPacket t;
   t=GetOnePixel(im->image,x,y);
   return pixelbrightcim(t.red*256/MaxRGB,
      t.green*256/MaxRGB,t.blue*256/MaxRGB);
#else
   size_t t;
   t=3*(x+y*im->width); /*calculate pixel_memory_position*/
   return pixelbrightcim(
      im->pixeldata[t],
      im->pixeldata[t+1],
      im->pixeldata[t+2]);

#endif
}

/*---------------------------------------------------------------------------*/

inline int pixelredim(ImagePtr *im,int x,int y) {
/*Gives back the pixelredness at x,y in im*/
/*Gives back 0 if error (x,y out of range or so)*/

#ifndef USE_SPEEDHACK
   PixelPacket t;
   t=GetOnePixel(im->image,x,y);
   return (t.red*256/MaxRGB);
#else
   return im->pixeldata[3*(x+y*im->width)];
#endif
}

/*---------------------------------------------------------------------------*/
inline int pixelgreenim(ImagePtr *im,int x,int y) {
/*Gives back the pixelgreenness at x,y in im*/
/*Gives back 0 if error (x,y out of range or so)*/


#ifndef USE_SPEEDHACK
   PixelPacket t;
   t=GetOnePixel(im->image,x,y);
   return (t.green*256/MaxRGB);
#else
   return im->pixeldata[3*(x+y*im->width)+1];
#endif

}

/*---------------------------------------------------------------------------*/
inline int pixelblueim(ImagePtr *im,int x,int y) {
/*Gives back the pixelblueness at x,y in im*/
/*Gives back 0 if error (x,y out of range or so)*/

#ifndef USE_SPEEDHACK
   PixelPacket t;
   t=GetOnePixel(im->image,x,y);
   return (t.blue*256/MaxRGB);
#else
   return im->pixeldata[3*(x+y*im->width)+2];
#endif

}

/*---------------------------------------------------------------------------*/

inline int drawpixelim(ImagePtr *im,int x,int y,int color) {
/*Draws a Pixel into im*/
/*0 if OK, -1 if failed*/

#ifndef USE_SPEEDHACK
   PixelPacket *t;

   t=SetImagePixels(im->image,x,y,1,1);
   if (t!=NULL) {
      t->red=im->red[color]*MaxRGB/256;
      t->green=im->green[color]*MaxRGB/256;
      t->blue=im->blue[color]*MaxRGB/256;
   };
#else
   size_t t;
   t=3*(x+y*im->width); /*calculate pixel_memory_position*/
   im->pixeldata[t]=im->red[color];
   im->pixeldata[t+1]=im->green[color];
   im->pixeldata[t+2]=im->blue[color];
#endif
   return 0;

}

/*---------------------------------------------------------------------------*/

#ifdef USE_CLUSTER
#ifdef USE_SPEEDHACK
inline int processsyncim(ImagePtr *im,int spread) {
/*when working multithreaded, sync image data to pid 0
  spread is the amount used to calculate split_min / max
  when creating the image (important if != image width) */

   int x,y,y2,y3,t;
   unsigned char * pointer;
   size_t length;

   x=im->width*3;
   length=x*sizeof(unsigned char);
   y=im->height;
   y2=(cluster_split_min(0,spread)*y)/spread;
   y3=(cluster_split_max(0,spread)*y)/spread;

   if (pid()>0) {
      #ifdef USE_DEBUG
         fprintf(stderr,"cluster(%i)_io: writing image part (line %i - %i)to pid 0 ...\n",pid(),y2,y3);
      #endif
      t=y2;
      while (t<y3) {
	 pointer=im->pixeldata;
	 pointer=&pointer[x*t];
	 cluster_sync_data_tomaster(pointer,length);
         t++;
      }
      #ifdef USE_DEBUG
         fprintf(stderr,"cluster(%i)_io: done.\n",pid());
      #endif
   } else {
      t=y3;
      while (t<y) {
         #ifdef USE_DEBUG
	    if ((t/y3)!=y2) {
               fprintf(stderr,"cluster(0)_io: reading image parts from pid(%i)...\n",t/y3);
	       y2=(t/y3);
	    }
         #endif
	 pointer=im->pixeldata;
	 pointer=&pointer[x*t];
	 cluster_sync_data_fromslave(pointer,length,t/y3);
         t++;
      }
      #ifdef USE_DEBUG
         fprintf(stderr,"cluster(0)_io: done.\n");
      #endif
   }
   return 0;
}

/*---------------------------------------------------------------------------*/

#else
#error you cannot compile cluster support withoud speedhack, sorry
#endif
#endif


