/* 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   BitImage3D.hpp */


#ifndef _BitImage3D_hpp
#define _BitImage3D_hpp

#include<imlib3dconfig.h>

#include<ImLib3D/CppTools.hpp>
#include<ImLib3D/RectZone3D.hpp>
#include<ImLib3D/Vect3D.hpp>
#include <assert.h>
#include <fstream>
#include<ImLib3D/FileException.hpp>
#include<ImLib3D/ImLib3DFile.hpp>
#include<ImLib3D/Size3D.hpp>
#include<ImLib3D/Properties.hpp>
#include<ImLib3D/Image3D.hpp>


#define bitsPerField   (8*sizeof(FieldType))
#define valuesPerField (bitsPerField/bitsPerValue)
#define valueMask      ((1<<bitsPerValue)-1)




#define _BitImage3D_internal
#include<ImLib3D/BitImage3DIterators.hpp>
#undef  _BitImage3D_internal


extern void BitImage3D_Test();

template<class FieldType,int bitsPerValue,class ValueType> class BitImage3D;

// temporary object for assigning a value to an image position
template<class FieldType,int bitsPerValue,class ValueType>
class BitImage3DValue
{
	typedef BitImage3D<FieldType,bitsPerValue,ValueType> ImageType;
	typedef BitImage3DValue _Self;
	ImageType *ima;
	size_t vpos;
	ValueType val;
	inline ValueType Get() const {return ima ? ima->Get(vpos) : val;}
	inline void      Set(const ValueType &v) {if(ima){ima->Set(vpos,v);}else{val=v;}}
public:
	inline bool operator< (const _Self &other){return Get()< other.Get();}
	inline bool operator<=(const _Self &other){return Get()<=other.Get();}
	inline bool operator> (const _Self &other){return Get()> other.Get();}
	inline bool operator>=(const _Self &other){return Get()>=other.Get();}

	inline _Self &operator+=(const _Self &other){Set(Get()+other.Get());return *this;}
	inline _Self &operator-=(const _Self &other){Set(Get()-other.Get());return *this;}
	inline _Self &operator*=(const _Self &other){Set(Get()*other.Get());return *this;}
	inline _Self &operator/=(const _Self &other){Set(Get()/other.Get());return *this;}

	inline bool operator< (ValueType v){return Get()< v;}
	inline bool operator<=(ValueType v){return Get()<=v;}
	inline bool operator> (ValueType v){return Get()> v;}
	inline bool operator>=(ValueType v){return Get()>=v;}

	inline bool operator==(const _Self &other){return Get()==other.Get();}
	inline bool operator!=(const _Self &other){return Get()!=other.Get();}

	inline bool operator==(ValueType v){return Get()==v;}
	inline bool operator!=(ValueType v){return Get()!=v;}


  	template<class FieldType1,int bitsPerValue1,class ValueType1>
  	inline void operator=(const BitImage3DValue<FieldType1,bitsPerValue1,ValueType1>  &other)
  	{Set((ValueType1)other);}

	inline void operator=(const ValueType &v){Set(v);}
	inline void operator=(const _Self  &other){Set(other.Get());}
	inline operator ValueType() const {return Get();}
	BitImage3DValue(ImageType *_ima,int _vpos):ima(_ima),vpos(_vpos){}
	BitImage3DValue(const ImageType *_ima,int _vpos):
		ima((ImageType *)_ima),vpos(_vpos){}
	BitImage3DValue():ima(NULL){}
	BitImage3DValue(const BitImage3DValue &other):
		ima((ImageType *)other.ima),vpos(other.vpos),val(other.val){}

	template<class NumType>
	BitImage3DValue(NumType _val):ima(NULL),val((ValueType)_val){}
//    		BitValue(const ValueType &_val):ima(NULL),val(_val){}
//    		BitValue(float  _val):ima(NULL),val((ValueType)_val){}
//  		BitValue(double _val):ima(NULL),val((ValueType)_val){}
};

// ********************** BitImage3D ********************
//! Image whose values are a predefined number of bits
/*! Number of bits of each value can be any number less then the biggest
  machine storable number (ie.32 bits). The value type returned by accessors
is not not directly an integer type. It is a class called "BitValue" that "looks"
like an (unsigned)int but when  a value is assigned to it, it can write it into the correct place 
in the image*/
// *******************************************************
template<class FieldType,int bitsPerValue,class ValueType=FieldType>
class BitImage3D : public Image3D , public MaskConcept<BitImage3D<FieldType,bitsPerValue,ValueType> >,
	public ArithmeticOperators<BitImage3D<FieldType,bitsPerValue,ValueType>,ValueType >
{
public:
	typedef BitImage3DValue<FieldType,bitsPerValue,ValueType> BitValue;
private:
	friend class BitImage3DValue<FieldType,bitsPerValue,ValueType>;
	typedef BitImage3D<FieldType,bitsPerValue,ValueType> _Self;
	typedef Container3D<FieldType> FieldImage;
	//! The actual contained data
	FieldImage imageData;
	//! Speedup 
	int widthXheight;

public:
	//! So that other templates know 
	typedef BitValue value_type;
	typedef ValueType Value;
public:
//@{ \name Iterator Typedefs    

	typedef BIM3D_iteratorFast<BitImage3D,BitValue>    iterator;
	typedef BIM3D_iteratorFast<BitImage3D,BitValue>    iteratorFast;
	typedef BIM3D_iteratorXYZ< BitImage3D,BitValue>    iteratorXYZ;
	typedef BIM3D_iteratorZone<BitImage3D,BitValue>    iteratorZone;

	typedef BIM3D_iteratorFast<const BitImage3D,const BitValue>    const_iterator;
	typedef BIM3D_iteratorFast<const BitImage3D,const BitValue>    const_iteratorFast;
	typedef BIM3D_iteratorXYZ< const BitImage3D,const BitValue>    const_iteratorXYZ;
	typedef BIM3D_iteratorZone<const BitImage3D,const BitValue>    const_iteratorZone;

	typedef iterator iteratorFastMasked;
	typedef const_iterator const_iteratorFastMasked;

	typedef reverse_iterator<const_iterator> const_reverse_iterator;
	typedef reverse_iterator<      iterator>       reverse_iterator;
//@}

	//! one past the last data element (used for iterator end check)
	iterator imageDataEnd;
	const_iterator const_imageDataEnd;

public:
	//@{ \name Begin and end iterating through an image
	//! (stl-like) get an  iterator positioned at the begining of this container
	iteratorFast         begin()       {return iteratorFast(this,0);}
  	const_iteratorFast   begin() const {return const_iteratorFast(this,0);}
	//! (stl-like) get an  iterator positioned at the end of this container
	inline iteratorFast         end()         {return imageDataEnd;}
	inline const_iteratorFast   end()   const {return const_imageDataEnd;}

	inline       reverse_iterator rbegin()         { return       reverse_iterator(end()); }
	inline const_reverse_iterator rbegin() const   { return const_reverse_iterator(end()); }
	inline       reverse_iterator rend()           { return       reverse_iterator(begin()); }
	inline const_reverse_iterator rend() const     { return const_reverse_iterator(begin()); }

	//@}
	// **************************************************
	// ****************** accessors *********************
	// **************************************************
	//@{ \name Accesors to Properties
   	RectZone3Df    &AddSupport(const Vect3Df &p0,const Vect3Df &p1)
	{properties.Add("Support",RectZone3Df(p0,p1));return Support();}
   	RectZone3Df       &Support()       {return Property<RectZone3Df>("Support");}
   	RectZone3Df const &Support() const {return Property<RectZone3Df>("Support");}	
	//@}
	//@{ \name BitImage3D Accesors 
	//! avoid using this directly :-(
	inline       FieldImage GetData()          {return imageData;}
	inline const FieldImage GetData() const    {return imageData;}
	//@}
	
	//@{ \name Accesors to specific image positions
private:
	inline void Set(size_t vpos,ValueType v)
	{
		// very simple (but common) case speedup, 1 bit = 1 voxel
		if(bitsPerValue==1 && bitsPerField==8)
		{
			if(v&1){imageData(vpos>>3)|= (1<<(vpos&7));}
			else   {imageData(vpos>>3)&=~(1<<(vpos&7));}
		}
		else
		{
			// must split vpos into two to avoid integer overlow
			size_t a=vpos>>16;
			size_t b=vpos&((1<<16)-1);
			size_t fieldNumber=(a*bitsPerValue)*((1<<16)/bitsPerField)+(b*bitsPerValue)/bitsPerField;
			size_t bitOffsetInField=(b*bitsPerValue)%bitsPerField;
			if(bitOffsetInField>(bitsPerField-bitsPerValue))
			{			
				FieldType &f1=imageData(fieldNumber);
				FieldType &f2=imageData(fieldNumber+1);
				// clear old value 
				f1&=~(valueMask<<(bitOffsetInField));
				// set new value 
				f1|=(v&valueMask)<<(bitOffsetInField);
				int remainingBits=bitOffsetInField+bitsPerValue-bitsPerField;
				ValueType mask1=((1<<remainingBits)-1);
				// clear old value 
				f2&=~mask1;
				// set new value 
				f2|=(v>>(bitsPerValue-remainingBits))&mask1;
			}
			else
			{
				FieldType &f1=imageData(fieldNumber);
				// clear old value 
				f1&=~(valueMask<<(bitOffsetInField));
				// set new value 
				f1|=(v&valueMask)<<(bitOffsetInField);
			}
		}
	}
	inline ValueType Get(size_t vpos) const
	{
		// very simple (but common) case speedup, 1 bit = 1 voxel
		if(bitsPerValue==1 && bitsPerField==8)
		{
			return imageData(vpos>>3)&(1<<(vpos&7)) ? 1 : 0;
		}
		else
		{
			// general case
			ValueType res;
			// must split vpos into two to avoid integer overlow
			size_t a=vpos>>16;
			size_t b=vpos&((1<<16)-1);
			size_t fieldNumber=(a*bitsPerValue)*((1<<16)/bitsPerField)+(b*bitsPerValue)/bitsPerField;
			size_t bitOffsetInField=(b*bitsPerValue)%bitsPerField;
			if(bitOffsetInField>(bitsPerField-bitsPerValue))
			{			
				const FieldType &f1=imageData(fieldNumber);
				const FieldType &f2=imageData(fieldNumber+1);
				int remainingBits=bitOffsetInField+bitsPerValue-bitsPerField;
				// clear old value 
				res=f2&((1<<remainingBits)-1);
				res<<=bitsPerValue-remainingBits;
				res|=(f1>>bitOffsetInField)&((1<<(bitsPerValue-remainingBits))-1);
				return res;
			}
			else
			{
				const FieldType &f1=imageData(fieldNumber);
				res=(f1>>bitOffsetInField)&valueMask;
				return res;
			}
		}
	}
public:
#ifdef SAFE_DEBUG
	inline BitValue   operator()(int pos)       {AssertBounds(pos);return  BitValue(this,pos);}
	inline BitValue   operator()(int pos) const {AssertBounds(pos);return            Get(pos);}	
	inline BitValue   operator()(int x,int y,int z)       
	{AssertBounds(x,y,z);return BitValue(this,x+y*width+z*widthXheight);}
	inline BitValue   operator()(int x,int y,int z) const 
	{AssertBounds(x,y,z);return           Get(x+y*width+z*widthXheight);}
	inline BitValue   operator()(const Vect3Di &v)        
	{AssertBounds(v.x,v.y,v.z);return BitValue(this,v.x+v.y*width+v.z*widthXheight);}
	inline BitValue   operator()(const Vect3Di &v)  const 
	{AssertBounds(v.x,v.y,v.z);return           Get(v.x+v.y*width+v.z*widthXheight);}
#else //SAFE_DEBUG
	inline BitValue   operator()(int pos)       {return BitValue(this,pos);}
	inline BitValue   operator()(int pos) const {return           Get(pos);}
	inline BitValue   operator()(int x,int y,int z)       {return BitValue(this,x+y*width+z*widthXheight);}
	inline BitValue   operator()(int x,int y,int z) const {return           Get(x+y*width+z*widthXheight);}
	inline BitValue   operator()(const Vect3Di &v)        {return BitValue(this,v.x+v.y*width+v.z*widthXheight);}
	inline BitValue   operator()(const Vect3Di &v)  const {return           Get(v.x+v.y*width+v.z*widthXheight);}
#endif //SAFE_DEBUG
	//@}


	// **************************************************
	// ****************** methods   *********************
	// **************************************************

	//! Sets all elements of the container to this value 
	void  Fill(const ValueType & value)
	{
		// try to use a smart method for filling 
		
		// zero : easy, just set everything to zero
		if(value==0){imageData.Fill(0);return;}
		// integer num of values fit into field : fill image data
		if((bitsPerField%bitsPerValue)==0 && imageData.GetNVoxels()!=0)
		{
			for(uint i=0;i<valuesPerField;i++){(*this)(i)=value;}
			FieldType fval=imageData(0);
			imageData.Fill(fval);			
			return;
		}
		// the slow way
		fill(begin(),end(),value);
	}

	//@{ \name File READ/WRITE methods
public:
	virtual string GetTypeName() const;
	//! This is where all the information is written
	/*! This virtual function writes xml/bin of any unset/unwritten  information
        (type,image size,image data,,...)
	    If you override it in a child class, you should still call it (using
		_Base::Write...), you can even call it several times...
	 */
	virtual void Read( ImLib3DFile *file,XMLNode *parentNode=NULL,XMLNode *node=NULL)      ;
	virtual void Write(ImLib3DFile *file,XMLNode *parentNode=NULL,XMLNode *node=NULL) const;
public:
	//! Write the image to file fname: This is the fct the end user should call
	virtual void WriteToFile (const string &fname) const {Streamable::WriteToFile(fname);}
	//@}

public:
	void Resize(const Size3D &newSize);
	ValueType GetZero() const {return 0;}

    //@{ \name Copy and compare operators
	_Self& operator= (const _Self & other);
  	template<class OtherImageType >
  	_Self& operator= (const OtherImageType & other)
	{
		if(other.Size()!=Size()){Resize(other.Size());}
		//if (this == &other){return *this;}
		// call parent operator =
		Image3D::operator=(other);
		// now copy the actual image data
		iteratorFast p;
		typename OtherImageType::const_iteratorFast op;
		for(p=begin(),op=other.begin();p!=end();++p,op++)
		{
			*p=(value_type)(*op);
		}
//		copy(other.begin(),other.end(),begin());
		return *this;
	}

  	bool   operator==(const _Self & other) const;
  	bool   operator!=(const _Self & other) const {return !(this->operator==(other));}
  	template<class OtherImage >
  	bool operator== (const OtherImage & other){return Size()==other.Size() && equal(other.begin(),other.end(),begin());}
  	template<class OtherImage >
  	bool operator!= (const OtherImage & other){return !((*this)==other);}
	//@}

	BitValue      SafeValue(int pos)     const {return IsInside(pos) ?           Get(pos) : 0;}
  	BitValue      SafeValue(int x,int y,int z) const 	
	{return IsInside(x,y,z) ?           (*this)(x,y,z) : BitValue(0) ;}
  	BitValue      SafeValue(const Vect3Di &v)  const 	
	{return IsInside(v    ) ?           (*this)(v    ) : BitValue(0) ;}


	// **************************************************
	// ****************** constructors/destructors*******
	// **************************************************
	//! \name Constructors and destructors
	//@{
public:
	//! Destructor
	virtual ~BitImage3D();
public:
  	BitImage3D();
	BitImage3D(int _width, int _height, int _depth);
  	explicit BitImage3D(const string& fname){ReadFromFile(fname);}
  	explicit BitImage3D(const char   *fname){ReadFromFile(fname);}
	explicit BitImage3D(int _cubeSideSize);
	/*! Copy constructor */
	BitImage3D(const Size3D &size);
	BitImage3D(const BitImage3D & origCont);
//    	template<class OtherImageType >
//  	BitImage3D(const OtherImageType & other):
//  		Image3D(other)
//  	{}
	//@}
};


template<class FieldType,int bitsPerValue,class ValueType>
struct HasPointerIterators<BitImage3D<FieldType,bitsPerValue,ValueType> >
{
	typedef __false_type value;
};

template<class FieldType,int bitsPerValue,class ValueType>
struct HasPointerIterators<const BitImage3D<FieldType,bitsPerValue,ValueType> >
{
	typedef __false_type value;
};


typedef BitImage3D<byte,1,byte> BitMask3D;

#include<ImLib3D/BitImage3D.hxx>
#undef bitsPerField   
#undef valuesPerField 
#undef valueMask      


#endif  // _BitImage3D_hpp
