/*
 *  Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#ifndef _KIS_TIFF_READER_H_
#define _KIS_TIFF_READER_H_

// On some platforms, tiffio.h #defines NULL in a bad
// way for C++, as (void *)0 instead of using the correct
// C++ value 0. Include stdio.h first to get the right one.
#include <stdio.h>
#include <tiffio.h>

// #include <tqvaluevector.h>
// #include <tdeio/job.h>
// #include <kis_progress_subject.h>

#include <kis_paint_device.h>

#include "kis_types.h"
#include "kis_global.h"
// #include "kis_annotation.h"

#include <kis_iterator.h>
#include <kis_paint_device.h>

#define TQ_UINT32_MAX 4294967295u

class TIFFStreamBase;

class KisTIFFPostProcessor {
    public:
        KisTIFFPostProcessor(uint8 nbcolorssamples) : m_nbcolorssamples(nbcolorssamples) { }
    public:
        virtual void postProcess8bit( TQ_UINT8* ) { };
        virtual void postProcess16bit( TQ_UINT16* ) { };
        virtual void postProcess32bit( TQ_UINT32* ) { };
    protected:
        inline uint8 nbColorsSamples() { return m_nbcolorssamples; }
    private:
        uint8 m_nbcolorssamples;
};

class KisTIFFPostProcessorInvert : public KisTIFFPostProcessor {
    public:
        KisTIFFPostProcessorInvert(uint8 nbcolorssamples) : KisTIFFPostProcessor(nbcolorssamples) {}
    public:
        virtual void postProcess8bit( TQ_UINT8* data )
        {
            for(int i = 0; i < nbColorsSamples(); i++)
            {
                data[i] = TQ_UINT8_MAX - data[i];
            }
        }
        virtual void postProcess16bit( TQ_UINT16* data )
        {
            TQ_UINT16* d = (TQ_UINT16*) data;
            for(int i = 0; i < nbColorsSamples(); i++)
            {
                d[i] = TQ_UINT16_MAX - d[i];
            }
        }
        virtual void postProcess32bit( TQ_UINT32* data )
        {
            TQ_UINT32* d = (TQ_UINT32*) data;
            for(int i = 0; i < nbColorsSamples(); i++)
            {
                d[i] = TQ_UINT32_MAX - d[i];
            }
        }
};

class KisTIFFPostProcessorICCLABtoCIELAB : public KisTIFFPostProcessor {
    public:
        KisTIFFPostProcessorICCLABtoCIELAB(uint8 nbcolorssamples) : KisTIFFPostProcessor(nbcolorssamples) {}
    public:
        void postProcess8bit(TQ_UINT8* data)
        {
            TQ_INT8* ds = (TQ_INT8*) data;
            for(int i = 1; i < nbColorsSamples(); i++)
            {
                ds[i] = data[i] - TQ_UINT8_MAX/2;
            }
        }
        void postProcess16bit(TQ_UINT16* data)
        {
            TQ_UINT16* d = (TQ_UINT16*) data;
            TQ_INT16* ds = (TQ_INT16*) data;
            for(int i = 1; i < nbColorsSamples(); i++)
            {
                ds[i] = d[i] - TQ_UINT16_MAX /2;
            }
        }
        void postProcess32bit(TQ_UINT32* data)
        {
            TQ_UINT32* d = (TQ_UINT32*) data;
            TQ_INT32* ds = (TQ_INT32*) data;
            for(int i = 1; i < nbColorsSamples(); i++)
            {
                ds[i] = d[i] - TQ_UINT32_MAX /2;
            }
        }
};


class KisTIFFReaderBase {
    public:
        KisTIFFReaderBase( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor) : m_device(device), m_alphapos(alphapos), m_sourceDepth(sourceDepth), m_nbcolorssamples(nbcolorssamples), m_nbextrasamples(extrasamplescount), m_poses(poses), m_transformProfile(transformProfile), m_postprocess(postprocessor)
        {
            
        }
    public:
        /**
         * This function copy data from the tiff stream to the paint device starting at the given position.
         * @param x horizontal start position
         * @param y vertical start position
         * @param dataWidth width of the data to copy
         * @param tiffstream source of data
         * 
         * @return the number of line which were copied
         */
        virtual uint copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream) =0;
        /**
         * This function is called when all data has been read and should be used for any postprocessing.
         */
        virtual void finalize() { };
    protected:
        inline KisPaintDeviceSP paintDevice() { return m_device; }
        inline TQ_UINT8 alphaPos() { return m_alphapos; }
        inline TQ_UINT8 sourceDepth() { return m_sourceDepth; }
        inline TQ_UINT8 nbColorsSamples() { return m_nbcolorssamples; }
        inline TQ_UINT8 nbExtraSamples() { return m_nbextrasamples; }
        inline TQ_UINT8* poses() { return m_poses; }
        inline cmsHTRANSFORM transform() { return m_transformProfile; }
        inline KisTIFFPostProcessor* postProcessor() { return m_postprocess; }
    private:
        KisPaintDeviceSP m_device;
        TQ_UINT8 m_alphapos;
        TQ_UINT8 m_sourceDepth;
        TQ_UINT8 m_nbcolorssamples;
        TQ_UINT8 m_nbextrasamples;
        TQ_UINT8* m_poses;
        cmsHTRANSFORM m_transformProfile;
        KisTIFFPostProcessor* m_postprocess;
        TQ_UINT32 m_tiffDataWidth;
};

class KisTIFFReaderTarget8bit : public KisTIFFReaderBase {
    public:
        KisTIFFReaderTarget8bit( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount,  cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor) : KisTIFFReaderBase(device, poses, alphapos, sourceDepth,  nbcolorssamples, extrasamplescount, transformProfile, postprocessor )
        {
            
        }
    public:
        virtual uint copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream);
};


class KisTIFFReaderTarget16bit : public KisTIFFReaderBase {
    public:
        KisTIFFReaderTarget16bit( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor) : KisTIFFReaderBase(device, poses, alphapos, sourceDepth,  nbcolorssamples, extrasamplescount, transformProfile, postprocessor )
        {
            
        }
    public:
        virtual uint copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream) ;
};

class KisTIFFReaderTarget32bit : public KisTIFFReaderBase {
    public:
        KisTIFFReaderTarget32bit( KisPaintDeviceSP device, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor) : KisTIFFReaderBase(device, poses, alphapos, sourceDepth,  nbcolorssamples, extrasamplescount, transformProfile, postprocessor )
        {
            
        }
    public:
        virtual uint copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream) ;
};

class KisTIFFReaderFromPalette : public  KisTIFFReaderBase {
    public:
        KisTIFFReaderFromPalette( KisPaintDeviceSP device, uint16 *red, uint16 *green, uint16 *blue, TQ_UINT8* poses, int8 alphapos, uint8 sourceDepth, uint8 nbcolorssamples, uint8 extrasamplescount, cmsHTRANSFORM transformProfile, KisTIFFPostProcessor* postprocessor) : KisTIFFReaderBase(device, poses, alphapos, sourceDepth,  nbcolorssamples, extrasamplescount, transformProfile, postprocessor ), m_red(red), m_green(green), m_blue(blue)
        {
            
        }
    public:
        virtual uint copyDataToChannels( TQ_UINT32 x, TQ_UINT32 y, TQ_UINT32 dataWidth, TIFFStreamBase* tiffstream) ;
    private:
        uint16 *m_red,  *m_green, *m_blue;
};

#endif
