#include <stdio.h>
#include <string.h>
#include <malloc.h>
/* The SuSE 7.3 copy of jpeglib.h is missing the extern "C" !! */
extern "C" {
#include <jpeglib.h>
}
#include <tiffio.h>
#include <image.h>
#include "dms/FileImage.h"

#define FILETYPE_UNKNOWN    0
#define FILETYPE_TIFF   1
#define FILETYPE_JPEG   2
#define FILETYPE_SGI    3


namespace dms
{

FileImage::FileImage(char *filename)
    {
    if (filename)
        loadFile(filename);
    }


void FileImage::loadFile(char *filename)
    {
    int filetype = fileType(filename);
    if (filetype == FILETYPE_UNKNOWN)
        fprintf(stderr,"FileImage::loadFile: image file '%s' is of unknown type\n");
    else if (filetype == FILETYPE_TIFF)
        loadTiffFile(filename);
    else if (filetype == FILETYPE_JPEG)
        loadJpegFile(filename);
    else if (filetype == FILETYPE_SGI)
        loadSgiFile(filename);
    }


int FileImage::fileType(char *filename)
    {
    static struct { char *ext; int typ; } table[] =
            { { ".tif", FILETYPE_TIFF },
              { ".tiff", FILETYPE_TIFF },
              { ".jpg", FILETYPE_JPEG },
              { ".jpeg", FILETYPE_JPEG },
              { ".rgb", FILETYPE_SGI },
              { ".sgi", FILETYPE_SGI },
              { NULL, FILETYPE_UNKNOWN }
            };
    char *extension = strrchr(filename,'.');
    if (extension)
        {
        for (int i=0; table[i].ext; i++)
            {
            if (strcasecmp(extension, table[i].ext) == 0)
                return table[i].typ;
            }
        }
    return FILETYPE_UNKNOWN;
    }


void FileImage::loadTiffFile(char *filename)
    {
    TIFF *tif = TIFFOpen(filename, "r");
    if (tif)
        {
        uint32 * data;
        uint32 width, height;
        TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
        TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
        data = (uint32 *) _TIFFmalloc(width * height * sizeof(uint32));
        if ((data) &&
            (TIFFReadRGBAImage(tif, width, height, data, 0)))
                {
                setSize(width, height);
                setData(data);
                }
        else
            {
            if (data)
                _TIFFfree(data);
            }
        TIFFClose(tif);
        }
    }


void FileImage::loadJpegFile(char *filename)
    {
    FILE * fp = fopen(filename, "r");
    if (!fp)
        perror(filename);
    else
        {
        unsigned long * data;
        GLsizei width, height;
        struct jpeg_decompress_struct cinfo;
        struct jpeg_error_mgr jerr;
        int buffersize, i;
        JSAMPARRAY buffer;
        cinfo.err = jpeg_std_error(&jerr);
        jpeg_create_decompress(&cinfo);
        jpeg_stdio_src(&cinfo, fp);
        jpeg_read_header(&cinfo, TRUE);
        cinfo.out_color_space = JCS_RGB;
        jpeg_start_decompress(&cinfo);
        width = cinfo.output_width;
        height = cinfo.output_height;
        data = (unsigned long *) malloc(width * height * sizeof(unsigned long));
        if (!data)
            {
            perror("FileImage::loadJpegFile(): malloc");
            return;
            }
        buffersize = cinfo.output_width * cinfo.output_components;
        buffer = (*(cinfo.mem->alloc_sarray))
                    ((j_common_ptr) &cinfo, JPOOL_IMAGE, buffersize, 1);
        while (cinfo.output_scanline < cinfo.output_height)
            {
            jpeg_read_scanlines(&cinfo, buffer, 1);
            for (i=0; i < cinfo.output_width; i++)
                {
                data[i+cinfo.output_scanline*width] =
                        (*buffer)[i*3] | ((*buffer)[i*3+1] << 8) |
                        ((*buffer)[i*3+2] << 16) | 0xff000000;
                }
            }
        jpeg_finish_decompress(&cinfo);
        jpeg_destroy_decompress(&cinfo);
        fclose(fp);

        setSize(width, height);
        setData(data);
        }
    }


void FileImage::loadSgiFile(char *filename)
    {
    unsigned short *img_rbuf, *img_gbuf, *img_bbuf, *img_abuf;
    IMAGE *imagefp;
    int x,y;
    unsigned long *p, *data;
    GLsizei width, height;
    if ((imagefp=iopen(filename,"r")) == NULL)
        {
        fprintf(stderr,"FileImage::loadSgiFile: can't open input file %s\n",
                filename);
        return;
        }
    width = imagefp->xsize;
    height = imagefp->ysize;
    img_rbuf = (unsigned short *) malloc(imagefp->xsize*sizeof(unsigned short));
    img_gbuf = (unsigned short *) malloc(imagefp->xsize*sizeof(unsigned short));
    img_bbuf = (unsigned short *) malloc(imagefp->xsize*sizeof(unsigned short));
    img_abuf = (unsigned short *) malloc(imagefp->xsize*sizeof(unsigned short));
    data = (unsigned long *) malloc(width*height*sizeof(unsigned long));
    if (!data)
        {
        perror("FileImage::loadSgiFile(): malloc");
        return;
        }
    for (y=0, p=data; y < imagefp->ysize; y++)
        {
        getrow(imagefp,img_rbuf,y,0);
        getrow(imagefp,img_gbuf,y,1);
        getrow(imagefp,img_bbuf,y,2);
        if (imagefp->zsize > 3)
            {
            getrow(imagefp,img_abuf,y,3);
            for (x=0; x < imagefp->xsize; x++)
                *p++ = img_rbuf[x] | (img_gbuf[x]<<8) |
                    (img_bbuf[x]<<16) | (img_abuf[x]<<24);
            }
        else
            {
            for (x=0; x < imagefp->xsize; x++)
                *p++ = img_rbuf[x] | (img_gbuf[x]<<8) |
                    (img_bbuf[x]<<16) | (0xff000000);
            }
        }
    iclose(imagefp);
    free(img_abuf);
    free(img_bbuf);
    free(img_gbuf);
    free(img_rbuf);
    setSize(width, height);
    setData(data);
    }

}
