#include "evas_common_private.h"
#include "evas_private.h"

#include <tiffio.h>

static int evas_image_save_file_tiff(RGBA_Image *im, const char *file, const char *key, int quality, int compress, const char *encoding);

static Evas_Image_Save_Func evas_image_save_tiff_func =
{
   evas_image_save_file_tiff
};

static int
save_image_tiff(RGBA_Image *im, const char *file, int compress EINA_UNUSED, int interlace EINA_UNUSED)
{
   TIFF               *tif = NULL;
   uint8              *buf = NULL;
   DATA32              pixel;
   DATA32             *data;
   uint32              x, y;
   uint8               r, g, b, a = 0;
   int                 i = 0;
   int                 has_alpha;

   if (!im || !im->image.data || !file)
      return 0;

   has_alpha = im->cache_entry.flags.alpha;
   data = im->image.data;

   tif = TIFFOpen(file, "w");
   if (!tif)
      return 0;

   /* None of the TIFFSetFields are checked for errors, but since they */
   /* shouldn't fail, this shouldn't be a problem */

   TIFFSetField(tif, TIFFTAG_IMAGELENGTH, im->cache_entry.h);
   TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, im->cache_entry.w);
   TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
   TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
   TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
   TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_NONE);

   /* By default uses patent-free use COMPRESSION_DEFLATE,
    * another lossless compression technique */
   TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);

   if (has_alpha)
     {
        uint16 extras[] = { EXTRASAMPLE_ASSOCALPHA };
        TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 4);
        TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, 1, extras);
     }
   else
     {
        TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
     }

   TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
   TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, 0));

   buf = (uint8 *) _TIFFmalloc(TIFFScanlineSize(tif));
   if (!buf)
     {
        TIFFClose(tif);
        return 0;
     }

   for (y = 0; y < im->cache_entry.h; y++)
     {
        i = 0;
        for (x = 0; x < im->cache_entry.w; x++)
          {
             pixel = data[(y * im->cache_entry.w) + x];

             r = (pixel >> 16) & 0xff;
             g = (pixel >> 8) & 0xff;
             b = pixel & 0xff;
             if (has_alpha)
                a = (pixel >> 24) & 0xff;

             /* This might be endian dependent */
             buf[i++] = r;
             buf[i++] = g;
             buf[i++] = b;
             if (has_alpha)
                buf[i++] = a;
          }

        if (!TIFFWriteScanline(tif, buf, y, 0))
          {
             _TIFFfree(buf);
             TIFFClose(tif);
             return 0;
          }
     }

   _TIFFfree(buf);
   TIFFClose(tif);

   return 1;
}

static int evas_image_save_file_tiff(RGBA_Image *im, const char *file, const char *key EINA_UNUSED,
                                     int quality EINA_UNUSED, int compress, const char *encoding EINA_UNUSED)
{
   return save_image_tiff(im, file, compress, 0);
}

static int
module_open(Evas_Module *em)
{
   if (!em) return 0;
   em->functions = (void *)(&evas_image_save_tiff_func);
   return 1;
}

static void
module_close(Evas_Module *em EINA_UNUSED)
{
}

static Evas_Module_Api evas_modapi =
{
   EVAS_MODULE_API_VERSION,
   "tiff",
   "none",
   {
     module_open,
     module_close
   }
};

EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_SAVER, image_saver, tiff);

#ifndef EVAS_STATIC_BUILD_TIFF
EVAS_EINA_MODULE_DEFINE(image_saver, tiff);
#endif

