// VIPS image wrapper

/*

    This file is part of VIPS.
    
    VIPS is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser 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 Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

 */

/*

    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk

 */

#ifndef IM_VIMAGE_H
#define IM_VIMAGE_H

#ifdef IM_VIPS_H
/* vips.h has lots of #defines for MULTIBAND etc. which mess up our enums.
 */
#undef MULTIBAND	
#undef B_W	
#undef LUMINACE
#undef XRAY
#undef IR
#undef YUV
#undef RED_ONLY	
#undef GREEN_ONLY
#undef BLUE_ONLY
#undef POWER_SPECTRUM
#undef HISTOGRAM
#undef FOURIER
#undef LUT
#undef XYZ
#undef LAB		
#undef CMC	
#undef CMYK
#undef LABQ		
#undef RGB	
#undef UCS
#undef LCH		
#undef LABS	
#undef sRGB	
#undef YXY	

#undef FMTNOTSET	
#undef FMTUCHAR	
#undef FMTCHAR	
#undef FMTUSHORT
#undef FMTSHORT	
#undef FMTUINT		
#undef FMTINT		
#undef FMTFLOAT	
#undef FMTCOMPLEX	
#undef FMTDOUBLE	
#undef FMTDPCOMPLEX	

#undef NOCODING		
#undef COLQUANT		
#undef LABPACK			
#undef LABPACK_COMPRESSED	
#undef RGB_COMPRESSED		
#undef LUM_COMPRESSED		

#undef NO_COMPRESSION		
#undef TCSF_COMPRESSION	
#undef JPEG_COMPRESSION	
#endif /*IM_VIPS_H*/

#include <list>
#include <complex>

/* VIPS image class.
 *
 * Slightly tricky: we have two sorts of sharing. Several VImage can share one
 * refblock (while results are being returned from functions, for example),
 * and several other refblocks can have IMAGEs which depend upon this IMAGE
 * for their result.
 */
class VImage {
	// Count ref etc. in one of these. One for each open VIPS image.
	struct refblock {
		void *im;			// IMAGE pointer
		int close_on_delete;		// Set if we must im_close()
		int nrefs;			// Number of refs to us
		std::list<refblock*> orefs;	// Refs im makes 

		// Construct/destruct
		refblock();
		virtual ~refblock();

		// Add a ref - this (output image) depends upon IMAGE in
		void addref( refblock *in );

		// Remove a ref
		void removeref();

		// Debugging
		void print();

		// Linked list needs "==" -- use address equivalence
		friend int operator==( const refblock &left, 
			const refblock &right ) { return( &left == &right ); }
	};

	refblock *_ref;

public:
#ifdef DEBUG
	/* All the refblocks in the world.
	 */
	static std::list<refblock*> all_refblock;
#endif /*DEBUG*/

	/* Print all refblocks ... debugging. Compile with DEBUG to enable
	 * this.
	 */
	static void print_all();

	/* Typedefs and enums we need.
	 */

	// Type type
	enum TType {
		MULTIBAND      = 0,
		B_W            = 1,
		LUMINACE       = 2,
		XRAY           = 3,
		IR             = 4,
		YUV            = 5,
		RED_ONLY       = 6,
		GREEN_ONLY     = 7,
		BLUE_ONLY      = 8,
		POWER_SPECTRUM = 9,
		HISTOGRAM      = 10,
		LUT            = 11,
		XYZ            = 12,
		LAB            = 13,
		CMC            = 14,
		CMYK           = 15,
		LABQ           = 16,
		RGB            = 17,
		UCS            = 18,
		LCH            = 19,
		LABS           = 21,
		sRGB	       = 22,
		YXY	       = 23,
		FOURIER	       = 24
	};

	// Format type
	enum TBandFmt {
		FMTNOTSET      = -1,
		FMTUCHAR       = 0,
		FMTCHAR        = 1,
		FMTUSHORT      = 2,
		FMTSHORT       = 3,
		FMTUINT        = 4,
		FMTINT         = 5,
		FMTFLOAT       = 6,
		FMTCOMPLEX     = 7,
		FMTDOUBLE      = 8,
		FMTDPCOMPLEX   = 9
	};

	// Coding type
	enum TCoding {
		NOCODING              = 0,
		COLQUANT              = 1,
		LABPACK               = 2,
		LABPACK_COMPRESSED    = 3,
		RGB_COMPRESSED        = 4,
		LUM_COMPRESSED        = 5
	};

	// Compression type
	enum TCompression {
		NO_COMPRESSION        = 0,
		TCSF_COMPRESSION      = 1,
		JPEG_COMPRESSION      = 2
	};

	/* Start of wrappers for iofuncs.
	 */

	// Plain constructors
	VImage( const char *name, const char *mode = "r" );
	VImage( void *data, int width, int height, 
		int bands, TBandFmt format );
	VImage( void *image );
	VImage();

	// Copy constructor 
	VImage( const VImage &a );

	// Assignment - delete old ref
	VImage &operator=( const VImage &a );

	// Destructor
	virtual ~VImage() { _ref->removeref(); }

	// Extract underlying IMAGE* pointer
	void *image() const { return( _ref->im ); }

	// Extract underlying data pointer
	void *data() const;

	// Write this to another VImage, to a file, or to a mem buffer
	VImage write( VImage out );
	VImage write( const char *name );
	VImage write();

	// Debugging ... print header fields
	void print();

	// Projection functions to get header fields
	int Xsize();
	int Ysize();
	int Bands();
	TBandFmt BandFmt();
	TCoding Coding();
	TType Type();
	float Xres();
	float Yres();
	int Length();
	TCompression Compression();
	short Level();
	int Xoffset();
	int Yoffset();

	// Derived fields
	char *filename();
	char *Hist();

	// Set header fields
	void initdesc( int, int, int, TBandFmt, TCoding, TType, 
		float = 1.0, float = 1.0, int = 0, int = 0 );

	/* Insert automatically generated headers.
	 */
#include "vipsc++.h"

	// And some in-line operator equivalences done by hand
	friend VImage operator+( VImage a, VImage b ) 
		{ return( a.add( b ) ); }
	friend VImage operator+( double a, VImage b ) 
		{ return( b.lin( 1.0, a ) ); }
	friend VImage operator+( VImage a, double b ) 
		{ return( a.lin( 1.0, b ) ); }

	friend VImage operator-( VImage a, VImage b ) 
		{ return( a.subtract( b ) ); }
	friend VImage operator-( double a, VImage b ) 
		{ return( b.lin( -1.0, a ) ); }
	friend VImage operator-( VImage a, double b ) 
		{ return( a.lin( 1.0, -b ) ); }

	friend VImage operator*( VImage a, VImage b ) 
		{ return( a.multiply( b ) ); }
	friend VImage operator*( double a, VImage b ) 
		{ return( b.lin( a, 0.0 ) ); }
	friend VImage operator*( VImage a, double b ) 
		{ return( a.lin( b, 0.0 ) ); }

	friend VImage operator/( VImage a, VImage b ) 
		{ return( a.divide( b ) ); }
	friend VImage operator/( double a, VImage b ) 
		{ return( b.pow( -1.0 ).lin( a, 0.0 ) ); }
	friend VImage operator/( VImage a, double b ) 
		{ return( a.lin( 1.0/b, 0.0 ) ); }

	friend VImage operator%( VImage a, VImage b ) 
		{ return( a.remainder( b ) ); }
	friend VImage operator%( VImage a, double b ) 
		{ return( a.remainderconst( b ) ); }

	friend VImage operator<( VImage a, VImage b ) 
		{ return( a.less( b ) ); }
	friend VImage operator<( double a, VImage b ) 
		{ return( b.moreconst( a ) ); }
	friend VImage operator<( VImage a, double b ) 
		{ return( a.lessconst( b ) ); }

	friend VImage operator<=( VImage a, VImage b ) 
		{ return( a.lesseq( b ) ); }
	friend VImage operator<=( double a, VImage b ) 
		{ return( b.moreeqconst( a ) ); }
	friend VImage operator<=( VImage a, double b ) 
		{ return( a.lesseqconst( b ) ); }

	friend VImage operator>( VImage a, VImage b ) 
		{ return( a.more( b ) ); }
	friend VImage operator>( double a, VImage b ) 
		{ return( b.lessconst( a ) ); }
	friend VImage operator>( VImage a, double b ) 
		{ return( a.moreconst( b ) ); }

	friend VImage operator>=( VImage a, VImage b ) 
		{ return( a.moreeq( b ) ); }
	friend VImage operator>=( double a, VImage b ) 
		{ return( b.lesseqconst( a ) ); }
	friend VImage operator>=( VImage a, double b ) 
		{ return( a.moreeqconst( b ) ); }

	friend VImage operator==( VImage a, VImage b ) 
		{ return( a.equal( b ) ); }
	friend VImage operator==( double a, VImage b ) 
		{ return( b.equalconst( a ) ); }
	friend VImage operator==( VImage a, double b ) 
		{ return( a.equalconst( b ) ); }

	friend VImage operator!=( VImage a, VImage b ) 
		{ return( a.notequal( b ) ); }
	friend VImage operator!=( double a, VImage b ) 
		{ return( b.notequalconst( a ) ); }
	friend VImage operator!=( VImage a, double b ) 
		{ return( a.notequalconst( b ) ); }

	friend VImage operator&( VImage a, VImage b ) 
		{ return( a.andimage( b ) ); }
	friend VImage operator&( int a, VImage b ) 
		{ return( b.andconst( a ) ); }
	friend VImage operator&( VImage a, int b ) 
		{ return( a.andconst( b ) ); }

	friend VImage operator|( VImage a, VImage b ) 
		{ return( a.orimage( b ) ); }
	friend VImage operator|( int a, VImage b ) 
		{ return( b.orconst( a ) ); }
	friend VImage operator|( VImage a, int b ) 
		{ return( a.orconst( b ) ); }

	friend VImage operator^( VImage a, VImage b ) 
		{ return( a.eorimage( b ) ); }
	friend VImage operator^( int a, VImage b ) 
		{ return( b.eorconst( a ) ); }
	friend VImage operator^( VImage a, int b ) 
		{ return( a.eorconst( b ) ); }

	friend VImage operator<<( VImage a, int b ) 
		{ return( a.shiftleft( b ) ); }
	friend VImage operator>>( VImage a, int b ) 
		{ return( a.shiftright( b ) ); }

	friend VImage operator-( VImage a ) 
		{ return( a * -1 ); }

	// Type conversion: VImage to VDMask and VIMask
	operator VDMask() { return( this->vips2mask() ); }
	operator VIMask() { return( VIMask( VDMask( *this ) ) ); }
};

/* Other decls we need.
 */

// Other VIPS protos
extern "C" {
extern int im_init_world( const char *argv0 ); 
extern void im__print_all(); 
extern void im_col_Lab2XYZ( 
	float, float, float,
	float *, float *, float * );
}

#endif /*IM_VIMAGE_H*/
