/* ImLib3D
 * Copyright (c) 2001, ULP-IPB Strasbourg.
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
/*!
  \file   ImageProcessor.hpp
  \brief  This file contains the base class for all Image Processing classes

  <long description> 

  See AUTHORS and COPYING files for more information
  \date   2001-01-16
*/


#ifndef _ImageProcessor_hpp
#define _ImageProcessor_hpp

#include<ImLib3D/Image3D.hpp>


//! Base Class for all Image processors
class CImageProcessor
{
public:
	
};

/*! \enum ImageArgFlag defines if the calculation can be done inplace or not
 */
enum ImageArgFlag	
{
	IMARG_NOTDEFINED,			//!< Not defined
	IMARG_INPLACE,				//!< Calculation can be done inplace
	IMARG_NOTINPLACE			//!< Calculation cannot be made inplace
};


template<class ImageType> class ImageProcessorArgs;

//! Internal for ImageProcessor's, image argument descriptor
/*!
  
 */
template <class ImageType,class ImageTypeCst=ImageType>
class ImageArg
{
    friend class ImageProcessorArgs<ImageType>;
	ImageTypeCst *image;
	bool srcIsConst;
	ImageType *duplicate;
	Size3D newSize;
public:
	void SetConst(bool v=true){srcIsConst=v;}
	ImageArg(ImageTypeCst &_image,ImageArgFlag f0=IMARG_NOTDEFINED):
		image(&_image),srcIsConst(true),duplicate(NULL)
	{
		if(f0==IMARG_INPLACE){srcIsConst=false;}
		if(f0==IMARG_NOTINPLACE){srcIsConst=true;}
	}
};


#define TMPDEF ImageArg<Im,const Im>

template <class Im> inline vector<TMPDEF > ImArgs(const Im &a1,const Im &a2,const Im &a3,const Im &a4)
{TMPDEF s[]={TMPDEF(a1),TMPDEF(a2),TMPDEF(a3),TMPDEF(a4)};vector<TMPDEF > v;v.insert(v.end(),s,s+4);return v;}
template <class Im> inline vector<TMPDEF > ImArgs(const Im &a1,const Im &a2,const Im &a3)
{TMPDEF s[]={TMPDEF(a1),TMPDEF(a2),TMPDEF(a3)};vector<TMPDEF > v;v.insert(v.end(),s,s+3);return v;}
template <class Im> inline vector<TMPDEF > ImArgs(const Im &a1,const Im &a2)
{TMPDEF s[]={TMPDEF(a1),TMPDEF(a2)};vector<TMPDEF > v;v.insert(v.end(),s,s+2);return v;}
template <class Im> inline vector<TMPDEF > ImArgs(const Im &a1)
{TMPDEF s[]={TMPDEF(a1)};vector<TMPDEF > v;v.insert(v.end(),s,s+1);return v;}

#undef TMPDEF
//! Internal for ImageProcessor's, image argument handling
/*!
  Internal ImageProcessor, image argument handling,
  this is used for checking if image arguments to an ImageProcessor
  have correct properties ( correct size, correctly masked ... )
  and for creating temporary images if dest==src ...
 */
template <class ImageType>
class ImageProcessorArgs
{
private:
  	typedef ImageArg<ImageType,      ImageType> ImArg;
  	typedef ImageArg<ImageType,const ImageType> ImArgCst;
	bool useLargerSrcBounds;
	Size3D bounds;

	vector<ImArgCst>  srcArgs;
	vector<ImArg   > destArgs;
public:
	ImageProcessorArgs(const vector<ImageArg<ImageType,const ImageType> > &srcs,ImageArg<ImageType> dest):
		useLargerSrcBounds(false)
	{
		for(uint i=0;i<srcs.size();i++)
		{
			AddSrc (ImageArg<ImageType,const ImageType>(srcs[i]));
		}
		AddDest(dest);
	}
	ImageProcessorArgs():
		useLargerSrcBounds(false)
	{
	}
	~ImageProcessorArgs()
	{
		Finished();
	}
	//! Adds another source image argument
	void AddSrc (ImArgCst arg){ srcArgs.push_back(arg);}
	//! Adds another destination image argument
	void AddDest(ImArg    arg){destArgs.push_back(arg);}


	void SameSize();
	void SetDestSize(Size3D size);
	void InPlace();

	//! Asserts that all images (srcs AND dests) have the same size
	void AllSameSizeAssert();
//	void AllSameSizeForce();
	void NoMasksAssert(){;}
//	void NoSupportAssert();
	void UseLargerSrcBounds();

	//! Get the nth destination image you should use in your algorithm
	ImageType &GetDest(int argn=0);
	//! Get the nth source image, resized if UseLargerSrcBounds
	const ImageType &GetSrc(int argn=0);

	//! Call this when algorithm is finished
    /*!
	  This copies back all dulpicated destination temporary images into the
      final destination images if needed
	 */
	void Finished();

};


#ifdef  USE_EXPLICIT_INSTANTIATION
// explicit instantiation of common templates, only for faster compilation
extern template class ImageArg<Mask3D,Mask3D>;
extern template class ImageArg<Mask3D,const Mask3D>;
extern template class ImageArg<Image3Df,Image3Df>;
extern template class ImageArg<Image3Df,const Image3Df>;

extern template class ImageProcessorArgs<Mask3D>;
extern template class ImageProcessorArgs<Image3Dlinear<byte> >;
extern template class ImageProcessorArgs<Image3Df>;
//  extern template class ImageProcessorArgs<const Mask3D>;
//  extern template class ImageProcessorArgs<const Image3Dlinear<byte> >;
//  extern template class ImageProcessorArgs<const Image3Df>;
//  extern template class vector<ImageArg<Mask3D, Mask3D const> >;
//  extern template class vector<ImageArg<Image3Df, Image3Df const> >;
#endif // USE_EXPLICIT_INSTANTIATION

#include<ImLib3D/ImageProcessor.hxx>

#endif  //_ImageProcessor_hpp
