/**
 * This file contains implementation of Cell::Scm* methods which handle the
 * global (floating-like) movement of cells, which is implemented using
 * the image transformations based on vector flow fields.
 */

#ifdef GTGEN_DEBUG
  #include <sys/time.h>
#endif

#include <sstream>
#include <values.h>
#include <time.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>

#include <i3d/DistanceTransform.h>
#include <i3d/neighbours.h>

#include "cell.h"
#include "toolbox/flowfields.h"
#include "toolbox/bp_lists.h"
#include "toolbox/rnd_generators.h"

//-----------------------------------------------------------------------------
// This function takes the mask of cell/nucleus as a domain where the voxels can
// be placed into. The position outside this domain are forbidden. Hence any voxel
// with forbidden position is to be projected into the mask. This projection is 
// performed as an nearest distance algorithm. For this purpose, the distance map is 
// required. If it does not exist, it is newly generated. As soon as the DM is available
// the iterative search for the nearest mask voxel is started.
//-----------------------------------------------------------------------------
template <class VOXEL>
i3d::Vector3d<float> FindNearestMaskVoxel(const i3d::Vector3d<float> v,
														const i3d::Image3d<VOXEL> &mask,
														const VOXEL value,
														i3d::Image3d<float>* &DM)
{
	 // If distance transform is not available, do it on your own
	 // (on demand). The currently created distance map is not destroyed
	 // when leaving this function as it can be used later by another 
	 // call of function 'FindNearestMaskVoxel'.
	 if (DM == NULL)
	 {
		  DM = new i3d::Image3d<float>();
		  DM->CopyMetaData(mask);
#ifdef GTGEN_DEBUG
		  float DMsum=0.f;
#endif
		  for (size_t i=0; i<mask.GetImageSize(); i++) 
		  {
				if (mask.GetVoxel(i) == value)
					 DM->SetVoxel(i, 1.0f); 
				else
					 DM->SetVoxel(i, 0.0f);
#ifdef GTGEN_DEBUG
		  		DMsum+=DM->GetVoxel(i);
#endif
		  } 
#ifdef GTGEN_DEBUG
		  REPORT("Regenerating distance map, it contains " << DMsum << " pixels")
#endif
		  //DM->SaveImage("DT_from_mask_before.ics"); //TODO VLADO REMOVE
		  //mask.SaveImage("DT_mask_for_new_DT.ics");
	
		  i3d::EDM(*DM, 0, 0.0f, false);
		  DEBUG_REPORT("Regeneration finished.");

		  //DM->SaveImage("DT_from_mask_after.ics"); //TODO VLADO REMOVE

		  remapped.clear();
	 }

	 i3d::Vector3d<float> res = mask.GetResolution().GetRes();
	 i3d::Vector3d<float> off = mask.GetOffset();
	 i3d::Vector3d<size_t> pos;

	 pos.x = (size_t) roundf((v.x - off.x) * res.x);
	 pos.y = (size_t) roundf((v.y - off.y) * res.y);
	 pos.z = (size_t) roundf((v.z - off.z) * res.z);

	 // if already computed before, fetch from the associative map
	 size_t index = mask.GetIndex(pos);

	 if (remapped.find(index) != remapped.end())
	 {
		  i3d::Vector3d<size_t> npos = mask.GetPos(remapped[index]);
		  i3d::Vector3d<float> posInMask = 
					 i3d::PixelsToMicrons(npos, res) + mask.GetOffset(); 

		  return posInMask;
	 }

	 // use either global or local distance map
	 std::vector<const float*> win;

	 //emergency break counter
	 size_t counter = 0;

	 do {
		  // collect neighbouring voxels of the current voxel
		  i3d::GetWindow(*DM, pos.x, pos.y, pos.z, i3d::nb3D_6, win);

		  // find the voxel with the lowest intensity 
		  float min_value = FLT_MAX;
		  size_t min_index = 0;
		  for (size_t j=0; j<win.size(); j++)
		  {
				float cur_value = *win[j];
				
	//			printf("(%f)",cur_value);

				if (min_value > cur_value)
				{
					 min_value = cur_value;
					 min_index = j;
				}
		  }

		  
	 //	  printf("[%lu,%lu,%lu] \n",pos.x, pos.y, pos.z);

		  if (min_value >= 80.0f) // in microns
		  {
				DEBUG_REPORT("would have thrown an error, min_value="
				<< min_value << " for input point " << v << ", render to " << pos)
				DM->SaveImage("DT_when_error.ics");
				//throw ERROR_REPORT("too big distance");
		  }
		  

		  // move to the voxel with the lowest intensity and
		  // repeat the process until you find the voxel with zero intensity, i.e.
		  // the mask voxel
		  size_t index = win[min_index] - DM->GetFirstVoxelAddr();
		  pos.x = DM->GetX(index);
		  pos.y = DM->GetY(index);
		  pos.z = DM->GetZ(index);

		  counter++;

	 } while ((DM->GetVoxel(pos) > 0.0f) && (counter < 100));

	 //DEBUG_REPORT("projection completed in " << counter << " step(s).");

	 if (counter < 100) {
		// store into associative map in case the emergency break has not been used
	 	remapped[index] = mask.GetIndex(pos);
		return ( i3d::PixelsToMicrons(pos, res) + DM->GetOffset() );
	 } else {
	 	// if in trouble, do not change the dot position
		REPORT("Couldn't find nearest mask position for the dot at position " << v << " (in microns)")
		return (v);
	 }
}

//-----------------------------------------------------------------------------

template <class MV, class PV>
void Cell<MV, PV>::ChrUpdateStats(void)
{
	//sanitary checks...
	if (chrDots * chrCount != chrDotList.size()) 
	{
		std::ostringstream err;
		err << "Cell ID=" << ID << " has bad number (" << chrDotList.size()
		    << ") of chrDotList items, should be " << chrDots*chrCount;
		throw ERROR_REPORT(err.str());
	}

	// During Anaphase and Cytokinesis the number of chromosomes 
	// is changing, i.e. avoid testing consistency during Anaphase
	if ((currentPhase == Anaphase) || (currentPhase == Cytokinesis))
	{
		 chrCentres.resize(chrCount);
		 chrSpreads.resize(chrCount);
	}
	else
	{ 
		 if (chrCount != chrCentres.size()) 
		 {
			  std::ostringstream err;
			  err << "Cell ID=" << ID << " has bad number (" << chrCentres.size()
						 << ") of chrCentres items, should be " << chrCount;
			  throw ERROR_REPORT(err.str());
		 } 
		 
		 if (chrCount != chrSpreads.size())
		 {
			  std::ostringstream err;
			  err << "Cell ID=" << ID << " has bad number (" << chrSpreads.size()
						 << ") of chrSpreads items, should be " << chrCount;
			  throw ERROR_REPORT(err.str());
		 }
	}

	//now the lengths are OK, let's make use of it

	//iterators, for computations of geometric centre
	std::vector<Molecule>::const_iterator dIter=chrDotList.begin();
	std::vector<Dot>::iterator cIter=chrCentres.begin();

	while (dIter != chrDotList.end()) {
		//chromosome geometric centre
		double X=0.; double Y=0.; double Z=0.;

		//until entire sub-sequence is read
		for (size_t i=0; i < chrDots; ++i, ++dIter) {
			//update centre...
			X+=dIter->pos.x;
			Y+=dIter->pos.y;
			Z+=dIter->pos.z;
		}

		//compute the centre of mass and save it into the "stats" variable
		cIter->pos.x=X/(double)chrDots;
		cIter->pos.y=Y/(double)chrDots;
		cIter->pos.z=Z/(double)chrDots;

		++cIter;
	}

	//iterators again, this time for computations of spread
	dIter=chrDotList.begin();
	cIter=chrCentres.begin();
	std::vector<float>::iterator sIter=chrSpreads.begin();

	while (dIter != chrDotList.end()) {
		//so far the best maximum distance ;-)
		*sIter=0;

		//until entire sub-sequence is read
		for (size_t i=0; i < chrDots; ++i, ++dIter) {
			//the current distance
			float dx=cIter->pos.x - dIter->pos.x;
			float dy=cIter->pos.y - dIter->pos.y;
			float dz=cIter->pos.z - dIter->pos.z;
			dx=dx*dx + dy*dy + dz*dz;
			if (dx > *sIter) *sIter=dx;
		}

		//finalize saving of the "stats" variable
		*sIter=sqrtf(*sIter);

		++cIter; ++sIter;
	}
}


//-----------------------------------------------------------------------------
/**
 * Internal helper function that actually does what Cell::ChrMoveByVector()
 * and Cell::ChrMoveByVectorBM() are supposed to do. The goal is not to duplicate
 * the same code. The parameter \e from is inclusive while the \e to is exclusive.
 */
template <class MV>
void __ChrMoveByVector( std::vector<Molecule> &chrDotList, 
								const size_t from,
								const size_t to,
								i3d::Vector3d<float> const &shift,
								i3d::Image3d<MV> const &mask, 
								i3d::Image3d<float>* &dmOfBackground,
								const MV value)
{
	//time savers:
	const float xRes=mask.GetResolution().GetX();
	const float yRes=mask.GetResolution().GetY();
	const float zRes=mask.GetResolution().GetZ();
	const float xOff=mask.GetOffset().x;
	const float yOff=mask.GetOffset().y;
	const float zOff=mask.GetOffset().z;

	//sweep over given portion of the chrDotList
	for (size_t i=from; i < to; ++i) {
		//a working copy of the new coordinate
		i3d::Vector3d<float> D(chrDotList[i].pos+shift);

		//nearest neighbor mask image pixel coordinate
		const int x=(int)roundf( (D.x-xOff) *xRes );
		const int y=(int)roundf( (D.y-yOff) *yRes );
		const int z=(int)roundf( (D.z-zOff) *zRes );

		//move the point to its new position
		if (mask.Include(x,y,z))
		{
			 if (mask.GetVoxel(x,y,z) == value) // is within the mask
				  chrDotList[i].pos = D;
			 else // escaped from the mask
				  chrDotList[i].pos = FindNearestMaskVoxel(D, mask, value, dmOfBackground);
		}
		else
		{
//			 throw ERROR_REPORT("The movement of dots is too fast.");
		}
	}
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrMoveByVector(const size_t chrID,
											  i3d::Vector3d<float> const &shift,
											  i3d::Image3d<MV> const &mask,
											  i3d::Image3d<float>* &dmOfBackground,
											  const MV value)
{
	//sanitary checks...
	if (chrDots * chrCount != chrDotList.size()) {
		std::ostringstream err;
		err << "Cell ID=" << ID << " has bad number (" << chrDotList.size()
		    << ") of chrDotList items, should be " << chrDots*chrCount;
		throw ERROR_REPORT(err.str());
	}
	if (chrID >= chrCount) {
		std::ostringstream err;
		err << "Cannot work with the asked chromosome no. " << chrID
		    << ", I have only " << chrCount;
		throw ERROR_REPORT(err.str());
	}

	//process the given portion of the chrDotList
	__ChrMoveByVector(chrDotList,
							chrDots * chrID,
							chrDots * (chrID+1), 
							shift,
							mask,
							dmOfBackground,
							value);
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrMoveByVectorBM(const size_t chrID,
												 i3d::Vector3d<float> const &shift,
												 i3d::Image3d<bool> const &mask,
												 i3d::Image3d<float>* &dmOfBackground,
												 const bool value)
{
	//sanitary checks...
	if (chrDots * chrCount != chrDotList.size()) {
		std::ostringstream err;
		err << "Cell ID=" << ID << " has bad number (" << chrDotList.size()
		    << ") of chrDotList items, should be " << chrDots*chrCount;
		throw ERROR_REPORT(err.str());
	}
	if (chrID >= chrCount) {
		std::ostringstream err;
		err << "Cannot work with the asked chromosome no. " << chrID
		    << ", I have only " << chrCount;
		throw ERROR_REPORT(err.str());
	}

	//process the given portion of the chrDotList
	__ChrMoveByVector(chrDotList,
							chrDots * chrID,
							chrDots * (chrID+1), 
							shift,
							mask,
							dmOfBackground,
							value);
}


//-----------------------------------------------------------------------------
/**
 * Internal helper function that actually does what Cell::ChrMoveWithBrown()
 * and Cell::ChrMoveWithBrownBM() are supposed to do. The goal is not to duplicate
 * the same code. The parameter \e from is inclusive while the \e to is exclusive.
 */
template <class MV>
void __ChrMoveWithBrown(std::vector<Molecule> &chrDotList, 
								const size_t from,
								const size_t to,
								const float step,
								i3d::Image3d<MV> const &mask, 
								i3d::Image3d<float>* &dmOfBackground,
								const MV value)
{
	//time savers:
	const float xRes=mask.GetResolution().GetX();
	const float yRes=mask.GetResolution().GetY();
	const float zRes=mask.GetResolution().GetZ();
	const float xOff=mask.GetOffset().x;
	const float yOff=mask.GetOffset().y;
	const float zOff=mask.GetOffset().z;

	//sweep over given portion of the chrDotList
	for (size_t i=from; i < to; ++i) {
		//a working copy of the new coordinate
		//const i3d::Vector3d<float> &D=chrDotList[i].pos;
		const i3d::Vector3d<float> D(chrDotList[i].pos);

		//up to 3x times Brownian motion while we are not in the mask
		i3d::Vector3d<float> V; //testing vector
		char tries=0;		//number of tries
		int x,y,z;		//new pixel position
		do {
			SuggestBrownianVector(V,step);
			++tries;

			//nearest neighbor mask image pixel coordinate
			x=(int)roundf( (D.x+V.x-xOff) *xRes );
			y=(int)roundf( (D.y+V.y-yOff) *yRes );
			z=(int)roundf( (D.z+V.z-zOff) *zRes );
			//REPORT(D << " (tries " << (int)tries << "): + " << V << " = (" << x << "," << y << "," << z << ")")
		} while ( ((!mask.Include(x,y,z)) || (mask.GetVoxel(x,y,z) != value))
			&& (tries < 3) );

		//move the point to its new position
		if (tries < 3) 
			 chrDotList[i].pos=D+V;
		else if (mask.Include(x,y,z) && (mask.GetVoxel(x,y,z) != value))
			 chrDotList[i].pos = FindNearestMaskVoxel(D+V, mask, value, dmOfBackground);
		// else do no motion
	}
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrMoveWithBrown(const size_t chrID,
												const float step,
												i3d::Image3d<MV> const &mask,
												i3d::Image3d<float>* &dmOfBackground,
												const MV value)
{
	//sanitary checks...
	if (chrDots * chrCount != chrDotList.size()) {
		std::ostringstream err;
		err << "Cell ID=" << ID << " has bad number (" << chrDotList.size()
		    << ") of chrDotList items, should be " << chrDots*chrCount;
		throw ERROR_REPORT(err.str());
	}
	if (chrID >= chrCount) {
		std::ostringstream err;
		err << "Cannot work with the asked chromosome no. " << chrID
		    << ", I have only " << chrCount;
		throw ERROR_REPORT(err.str());
	}

	//process the given portion of the chrDotList
	__ChrMoveWithBrown(chrDotList,
							 chrDots * chrID,
							 chrDots * (chrID+1), 
							 step,
							 mask,
							 dmOfBackground,
							 value);
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrMoveWithBrownBM(const size_t chrID,
												  const float step,
												  i3d::Image3d<bool> const &mask,
												  i3d::Image3d<float>* &dmOfBackground,
												  const bool value)
{
	//sanitary checks...
	if (chrDots * chrCount != chrDotList.size()) {
		std::ostringstream err;
		err << "Cell ID=" << ID << " has bad number (" << chrDotList.size()
		    << ") of chrDotList items, should be " << chrDots*chrCount;
		throw ERROR_REPORT(err.str());
	}
	if (chrID >= chrCount) {
		std::ostringstream err;
		err << "Cannot work with the asked chromosome no. " << chrID
		    << ", I have only " << chrCount;
		throw ERROR_REPORT(err.str());
	}

	//process the given portion of the chrDotList
	__ChrMoveWithBrown(chrDotList,
							 chrDots * chrID,
							 chrDots * (chrID+1), 
							 step,
							 mask,
							 dmOfBackground,
							 value);
}


//-----------------------------------------------------------------------------
/**
 * Internal helper function that actually does what Cell::ChrMoveWithGravity()
 * and Cell::ChrMoveWithGravityBM() are supposed to do. The goal is not to duplicate
 * the same code. The parameter \e from is inclusive while the \e to is exclusive.
 */
template <class MV>
void __ChrMoveWithGravity(std::vector<Molecule> &chrDotList, 
								  const size_t from,
								  const size_t to,
								  const float step,
								  i3d::Image3d<MV> const &mask, 
								  i3d::Image3d<float>* &dmOfBackground,
								  const MV value,
								  const Dot& chrCentre)
{
	//time savers:
	const float xRes=mask.GetResolution().GetX();
	const float yRes=mask.GetResolution().GetY();
	const float zRes=mask.GetResolution().GetZ();
	const float xOff=mask.GetOffset().x;
	const float yOff=mask.GetOffset().y;
	const float zOff=mask.GetOffset().z;

	//sweep over given portion of the chrDotList
	for (size_t i=from; i < to; ++i) 
	{
		//a temporary copy of the new coordinate
		const i3d::Vector3d<float> D(chrDotList[i].pos);

/*
 * ----
 * This part of code if commented as we found out that we do not need to
 * compute the local neighbourhood of each molecule precisely. 
 * The global neighbourhood (without local weights) is also a good 
 * and sufficiently precie approximation. In detail, the difference between
 * the precisely compute angles and the approximate ones is 
 * at most 5 degrees.
 * 
 * The complexity of local nbh method: O(n^2)
 * The complexity of global nbh method:  O(n)
 * ----
 *
		//gravity vector
		i3d::Vector3d<float> V(0.f,0.f,0.f);

		//TODO VLADO: TRY IF IT CAN BE FASTER WITH ITERATORS...

		//sweep again over the given portion of the chrDotList
		for (size_t j=from; j < to; ++j) {
			//move over the same dot
			if (i == j) continue;

			//vector from the evaluated one towards the other
			const float dx=chrDotList[j].pos.x - D.x;
			const float dy=chrDotList[j].pos.y - D.y;
			const float dz=chrDotList[j].pos.z - D.z;
		
			//size of this vector (distance between the dots, in fact) and its square
			const float s2=dx*dx + dy*dy + dz*dz; 
			//const float s=sqrtf(s2+0.0001); //to prevent from sqrtf(0)

			
			//the "Gravity" vector is: step * (dx,dy,dz)/s * 1/s2
			//           [step times normalized direction] * [inverse proportional square of distance]
			// float W=(s2 > 0)?  step / (s * s2) : 0.f;
			//
			//if dots are too close, the W would catapult them against each other
			// if (W > 1.f) W=1.f;
			//
			//ALTERNATIVE:
			//the "Gravity" vector is: step * (dx,dy,dz)/s * s/(1+s2)
			//           [step times normalized direction] * [some harmonic 1/x2-like function]
			float W=step / (1+s2);

			//movement due to mutual gravity between the dots "i" and "j"
			V += i3d::Vector3d<float>(W*dx,W*dy,W*dz);
		}*/

		// find the vector heading to the centre
		i3d::Vector3d<float> V = step*(chrCentre.pos - D);

		//nearest neighbor mask image pixel coordinate
		const int x=(int)roundf( (D.x+V.x-xOff) * xRes );
		const int y=(int)roundf( (D.y+V.y-yOff) * yRes );
		const int z=(int)roundf( (D.z+V.z-zOff) * zRes );

		//move the point, if its new position is still within the mask
		if (mask.Include(x,y,z))
		{
			 if (mask.GetVoxel(x,y,z) == value) // is within mask
				  chrDotList[i].pos = D+V;
			 else // escaped from the mask -> correct
			 {
				  chrDotList[i].pos = 
							 FindNearestMaskVoxel(D+V, mask, value, dmOfBackground);
			 }
		}
		else
		{
			// throw ERROR_REPORT("The movement of dots is too fast.");
		}
	}
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrMoveWithGravity(const size_t chrID,
												  const float step,
												  i3d::Image3d<MV> const &mask,
												  i3d::Image3d<float>* &dmOfBackground,
												  const MV value)
{
	//sanitary checks...
	if (chrDots * chrCount != chrDotList.size()) {
		std::ostringstream err;
		err << "Cell ID=" << ID << " has bad number (" << chrDotList.size()
		    << ") of chrDotList items, should be " << chrDots*chrCount;
		throw ERROR_REPORT(err.str());
	}
	if (chrID >= chrCount) {
		std::ostringstream err;
		err << "Cannot work with the asked chromosome no. " << chrID
		    << ", I have only " << chrCount;
		throw ERROR_REPORT(err.str());
	}

	//process the given portion of the chrDotList;
	//in order to keep the strength of the 'step' constant rather the same,
	//it must be reduced by the number of dots as they all contribute additively
	__ChrMoveWithGravity(chrDotList,
								chrDots * chrID,
								chrDots * (chrID+1), 
								step,
								mask,
								dmOfBackground,
								value,
								chrCentres[chrID]);

}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrMoveWithGravityBM(const size_t chrID,
													 const float step,
													 i3d::Image3d<bool> const &mask,
													 i3d::Image3d<float>* &dmOfBackground,
													 const bool value)
{
	//sanitary checks...
	if (chrDots * chrCount != chrDotList.size()) {
		std::ostringstream err;
		err << "Cell ID=" << ID << " has bad number (" << chrDotList.size()
		    << ") of chrDotList items, should be " << chrDots*chrCount;
		throw ERROR_REPORT(err.str());
	}
	if (chrID >= chrCount) {
		std::ostringstream err;
		err << "Cannot work with the asked chromosome no. " << chrID
		    << ", I have only " << chrCount;
		throw ERROR_REPORT(err.str());
	}

	//process the given portion of the chrDotList
	//in order to keep the strength of the 'step' constant rather the same,
	//it must be reduced by the number of dots as they all contribute additively
	__ChrMoveWithGravity(chrDotList,
								chrDots * chrID,
								chrDots * (chrID+1), 
								step,
								mask,
								dmOfBackground,
								value,
								chrCentres[chrID]);
}


//-----------------------------------------------------------------------------
/**
 * Internal helper function that actually does what Cell::ChrMoveByFlow()
 * and Cell::ChrMoveByFlowBM() are supposed to do. The goal is not to duplicate
 * the same code. The parameter \e from is inclusive while the \e to is exclusive.
 */
template <class MV>
void __ChrMoveByFlow(std::vector<Molecule> &chrDotList,
							const size_t from,
							const size_t to,
							FlowField<float> const &FF,
							i3d::Image3d<MV> const &mask, 
							i3d::Image3d<float>* &dmOfBackground,
							const MV value)
{
	//time savers:
	const float xRes=mask.GetResolution().GetX();
	const float yRes=mask.GetResolution().GetY();
	const float zRes=mask.GetResolution().GetZ();
	const float xOff=mask.GetOffset().x;
	const float yOff=mask.GetOffset().y;
	const float zOff=mask.GetOffset().z;

	const float xResFF=FF.x->GetResolution().GetX();
	const float yResFF=FF.x->GetResolution().GetY();
	const float zResFF=FF.x->GetResolution().GetZ();
	const float xOffFF=FF.x->GetOffset().x;
	const float yOffFF=FF.x->GetOffset().y;
	const float zOffFF=FF.x->GetOffset().z;

	//move dot by dot...
	for (size_t i=from; i < to; ++i) 
	{
		const float X=chrDotList[i].pos.x;
		const float Y=chrDotList[i].pos.y;
		const float Z=chrDotList[i].pos.z;

		//the position in pixels of the flow field
		const float Xp=(X -xOffFF) *xResFF;
		const float Yp=(Y -yOffFF) *yResFF;
		const float Zp=(Z -zOffFF) *zResFF;

		//new molecule position after moving along the flow field
		//note: GetPixel() returns 0 in case we ask for value outside the image molecule position
		//(both the position and vectors in the flow field are in microns)
		const float nX=X + GetPixel(*FF.x, Xp,Yp,Zp);
		const float nY=Y + GetPixel(*FF.y, Xp,Yp,Zp);
		const float nZ=Z + GetPixel(*FF.z, Xp,Yp,Zp);

		//new position in the pixels of the mask image, using nearest neighbor
		const int nXp=(int)roundf( (nX-xOff) *xRes );
		const int nYp=(int)roundf( (nY-yOff) *yRes );
		const int nZp=(int)roundf( (nZ-zOff) *zRes );

		if (mask.Include(nXp,nYp,nZp))
		{
			 if (mask.GetVoxel(nXp,nYp,nZp)==value) 
			 {
				  //new position fits into the image and even into this cell mask,
				  // update the dot then (with the real unrounded position)
				  chrDotList[i].pos.x=nX;
				  chrDotList[i].pos.y=nY;
				  chrDotList[i].pos.z=nZ;
			 }
			 else
			 {
				  chrDotList[i].pos = 
							 FindNearestMaskVoxel(i3d::Vector3d<float>(nX, nY, nZ),
														 mask,
														 value,
														 dmOfBackground);
			 }
		}
		else
		{
			 // throw ERROR_REPORT("The movement of dots is too fast.");
		}
	}
}


//-----------------------------------------------------------------------------
/**
 * Internal helper function that actually does what Cell::ChrMoveByFlow()
 * and Cell::ChrMoveByFlowBM() are supposed to do. The goal is not to duplicate
 * the same code.
 */
template <class MV>
void __ChrMoveByFlow(std::vector<Molecule> &chrDotList,
							FlowField<float> const &FF,
							i3d::Image3d<MV> const &mask, 
							i3d::Image3d<float>* &dmOfBackground,
							const MV value)
{
	 __ChrMoveByFlow(chrDotList,
						  0, chrDotList.size(),
						  FF, mask, dmOfBackground, value);
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrMoveByFlow(FlowField<float> const &FF,
											i3d::Image3d<MV> const &mask,
											i3d::Image3d<float>* &dmOfBackground,
											const MV value)
{
	//sanitary checks...
	if (!FF.isConsistent())
		throw ERROR_REPORT("Flow field is not consistent.");
	if (!FF.z)
		throw ERROR_REPORT("The input flow field is not 3D.");

	//process the whole chrDotList
	__ChrMoveByFlow(chrDotList, FF,mask,dmOfBackground,value);
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrMoveByFlow(const size_t chrID,
											FlowField<float> const &FF,
											i3d::Image3d<MV> const &mask,
											i3d::Image3d<float>* &dmOfBackground,
											const MV value)
{
	//sanitary checks...
	if (!FF.isConsistent())
		throw ERROR_REPORT("Flow field is not consistent.");
	if (!FF.z)
		throw ERROR_REPORT("The input flow field is not 3D.");

	//process the whole chrDotList
	__ChrMoveByFlow(chrDotList, 
						 chrDots * chrID,
						 chrDots * (chrID+1),
						 FF,
						 mask,
						 dmOfBackground,
						 value);
}

//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrMoveByFlowBM(FlowField<float> const &FF,
											  i3d::Image3d<bool> const &mask,
											  i3d::Image3d<float>* &dmOfBackground,
											  const bool value)
{
	//sanitary checks...
	if (!FF.isConsistent())
		throw ERROR_REPORT("Flow field is not consistent.");
	if (!FF.z)
		throw ERROR_REPORT("The input flow field is not 3D.");

	//process the whole chrDotList
	__ChrMoveByFlow(chrDotList, FF,mask,dmOfBackground, value);
}


//-----------------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrRenderIntoPhantoms(i3d::Image3d<PV> &phantoms,
													  FlowField<float> const &FF)
{
	if (!FF.isConsistent())
		throw ERROR_REPORT("Flow field is not consistent.");
	if (!FF.z)
		throw ERROR_REPORT("The input flow field is not 3D.");

	DEBUG_REPORT("going to render " << chrDotList.size() << " 'chr' points, ID="
		     << ID << " (WITH FLOW FIELD)")

	//flow field related time savers:
	const float xResFF=FF.x->GetResolution().GetX();
	const float yResFF=FF.x->GetResolution().GetY();
	const float zResFF=FF.x->GetResolution().GetZ();
	const float xOffFF=FF.x->GetOffset().x;
	const float yOffFF=FF.x->GetOffset().y;
	const float zOffFF=FF.x->GetOffset().z;

	//phantom image related time savers:
	const float xRes=phantoms.GetResolution().GetX();
	const float yRes=phantoms.GetResolution().GetY();
	const float zRes=phantoms.GetResolution().GetZ();
	const float xOff=phantoms.GetOffset().x;
	const float yOff=phantoms.GetOffset().y;
	const float zOff=phantoms.GetOffset().z;

#ifdef GTGEN_DEBUG
	//time-measurement
	struct timeval t1,t2;
	float T1,T2;
	gettimeofday(&t1,NULL);
#endif

	// keep active voxels in the buffer
	// initially, all the voxels are marked as 'false'
	i3d::Image3d<bool> activeVoxels;
	activeVoxels.CopyMetaData(phantoms);
	activeVoxels.GetVoxelData() = false;

	for (size_t i=0; i < chrDotList.size(); ++i) 
	{
		//working copy of the chrDot vector, in microns
		float x=chrDotList[i].pos.x;
		float y=chrDotList[i].pos.y;
		float z=chrDotList[i].pos.z;

		//turn micron position into flow field pixel one
		const float X=(x -xOffFF) *xResFF;
		const float Y=(y -yOffFF) *yResFF;
		const float Z=(z -zOffFF) *zResFF;

		//move the working copy micron position of the chrDot
		//note: GetPixel() returns 0 in case we ask for value outside the image
		x += GetPixel(*FF.x, X,Y,Z);
		y += GetPixel(*FF.y, X,Y,Z);
		z += GetPixel(*FF.z, X,Y,Z);

		//now, turn the micron position back to phantom pixel one
		const int nX=(int)roundf( (x-xOff) *xRes);
		const int nY=(int)roundf( (y-yOff) *yRes);
		const int nZ=(int)roundf( (z-zOff) *zRes);

		if (phantoms.Include(nX,nY,nZ)) 
		{
			 // mark the active voxels as 'true'
			 activeVoxels.SetVoxel(nX, nY, nZ, true);

			 // render phantom voxels
			 PV *p=phantoms.GetVoxelAddr(nX,nY,nZ);
			 ++(*p);
		} 
		else
		{
			DEBUG_REPORT("ups, dot " << chrDotList[i].pos << " is outside the cell");
		}
		//
		//this was nearest neighbor insertion,
		//uncomment following to get tri-linear insertion (but slower)
		/*
		const float nX=(x-xOff) *xRes;
		const float nY=(y-yOff) *yRes;
		const float nZ=(z-zOff) *zRes;
		PutPixel(phantoms,nX,nY,nZ);
		*/
	}
#ifdef GTGEN_DEBUG
	gettimeofday(&t2,NULL);
	t2.tv_sec-=t1.tv_sec;
	T1=((float)t1.tv_usec / 1000000.0f);
	T2=(float)t2.tv_sec + ((float)t2.tv_usec / 1000000.0f);
	REPORT("rendering chr points altered by FF took " << T2-T1 << " seconds")
#endif

#ifdef GTGEN_WITH_PHOTOBLEACHING
	ApplyPhotobleaching(phantoms, activeVoxels);
#endif

#ifdef GTGEN_WITH_CHRCENTRESINPHANTHOMS
	//ok, also draw Cell::chrCentres with this "colour"
	const PV centreColour=std::numeric_limits<PV>::max()/2;

	for (size_t i=0; i < chrCentres.size(); ++i) {
		//working copy of the chrDot vector, in microns
		float x=chrCentres[i].pos.x;
		float y=chrCentres[i].pos.y;
		float z=chrCentres[i].pos.z;

		//turn micron position into flow field pixel one
		const float X=(x -xOffFF) *xResFF;
		const float Y=(y -yOffFF) *yResFF;
		const float Z=(z -zOffFF) *zResFF;

		//move the working copy micron position of the chrDot
		//note: GetPixel() returns 0 in case we ask for value outside the image
		x += GetPixel(*FF.x, X,Y,Z);
		y += GetPixel(*FF.y, X,Y,Z);
		z += GetPixel(*FF.z, X,Y,Z);

		//now, turn the micron position back to phantom pixel one
		const int nX=(int)roundf( (x-xOff) *xRes);
		const int nY=(int)roundf( (y-yOff) *yRes);
		const int nZ=(int)roundf( (z-zOff) *zRes);
		if (phantoms.Include(nX,nY,nZ)) {
			PV *p=phantoms.GetVoxelAddr(nX,nY,nZ);
			*p+=centreColour;
			//note: let it overflow if needed so that
			//subtraction later can restore to the correct value
		}
	}
#endif
}


//------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrRenderIntoPhantoms(i3d::Image3d<PV> &phantoms)
{
	DEBUG_REPORT("going to render " << chrDotList.size() << " 'chr' points, ID=" << ID)

	//phantom image related time savers:
	const float xRes=phantoms.GetResolution().GetX();
	const float yRes=phantoms.GetResolution().GetY();
	const float zRes=phantoms.GetResolution().GetZ();
	const float xOff=phantoms.GetOffset().x;
	const float yOff=phantoms.GetOffset().y;
	const float zOff=phantoms.GetOffset().z;

#ifdef GTGEN_DEBUG
	//time-measurement
	struct timeval t1,t2;
	float T1,T2;
	gettimeofday(&t1,NULL);
#endif

	// keep active voxels in the buffer
	// initially, all the voxels are marked as 'false'
	i3d::Image3d<bool> activeVoxels;
	activeVoxels.CopyMetaData(phantoms);
	activeVoxels.GetVoxelData() = false;

	for (size_t i=0; i < chrDotList.size(); ++i) 
	{
		// turn micron position to phantom pixel one
		const int nX=(int)roundf( (chrDotList[i].pos.x-xOff) *xRes);
		const int nY=(int)roundf( (chrDotList[i].pos.y-yOff) *yRes);
		const int nZ=(int)roundf( (chrDotList[i].pos.z-zOff) *zRes);

		if (phantoms.Include(nX,nY,nZ)) 
		{
			 // mark the active voxels as 'true'
			 activeVoxels.SetVoxel(nX, nY, nZ, true);

			 // render phantom voxels
			 PV *p=phantoms.GetVoxelAddr(nX,nY,nZ);
			 ++(*p);

		} 
		else
		{
			DEBUG_REPORT("ups, dot " << chrDotList[i].pos << " is outside the cell");
		}
		//
		//this was nearest neighbor insertion,
		//uncomment following to get tri-linear insertion (but slower)
		/*
		const float nX=(x-xOff) *xRes;
		const float nY=(y-yOff) *yRes;
		const float nZ=(z-zOff) *zRes;
		PutPixel(phantoms,nX,nY,nZ);
		*/
	}
#ifdef GTGEN_DEBUG
	gettimeofday(&t2,NULL);
	t2.tv_sec-=t1.tv_sec;
	T1=((float)t1.tv_usec / 1000000.0f);
	T2=(float)t2.tv_sec + ((float)t2.tv_usec / 1000000.0f);
	REPORT("direct rendering chr points took " << T2-T1 << " seconds")
#endif

#ifdef GTGEN_WITH_PHOTOBLEACHING
	ApplyPhotobleaching(phantoms, activeVoxels);
#endif

#ifdef GTGEN_WITH_CHRCENTRESINPHANTHOMS
	//ok, also draw Cell::chrCentres with this "colour"
	const PV centreColour=std::numeric_limits<PV>::max()/2;

	for (size_t i=0; i < chrCentres.size(); ++i) {
		//turn micron position to phantom pixel one
		const int nX=(int)roundf( (chrCentres[i].pos.x-xOff) *xRes);
		const int nY=(int)roundf( (chrCentres[i].pos.y-yOff) *yRes);
		const int nZ=(int)roundf( (chrCentres[i].pos.z-zOff) *zRes);
		if (phantoms.Include(nX,nY,nZ)) {
			PV *p=phantoms.GetVoxelAddr(nX,nY,nZ);
			*p+=centreColour;
			//note: let it overflow if needed so that
			//subtraction later can restore to the correct value
		}
	}
#endif
}


//------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV, PV>::ChrRenderIntoTerritories(i3d::Image3d<PV> &territories,
														  FlowField<float> const &FF)
{
	if (!FF.isConsistent())
		throw ERROR_REPORT("Flow field is not consistent.");
	if (!FF.z)
		throw ERROR_REPORT("The input flow field is not 3D.");

	DEBUG_REPORT("going to render " << chrDotList.size() << " 'chr' points, ID="
		     << ID << " (WITH FLOW FIELD)")

	//flow field related time savers:
	const float xResFF=FF.x->GetResolution().GetX();
	const float yResFF=FF.x->GetResolution().GetY();
	const float zResFF=FF.x->GetResolution().GetZ();
	const float xOffFF=FF.x->GetOffset().x;
	const float yOffFF=FF.x->GetOffset().y;
	const float zOffFF=FF.x->GetOffset().z;

	//phantom image related time savers:
	const float xRes=territories.GetResolution().GetX();
	const float yRes=territories.GetResolution().GetY();
	const float zRes=territories.GetResolution().GetZ();
	const float xOff=territories.GetOffset().x;
	const float yOff=territories.GetOffset().y;
	const float zOff=territories.GetOffset().z;

#ifdef GTGEN_DEBUG
	//time-measurement
	struct timeval t1,t2;
	float T1,T2;
	gettimeofday(&t1,NULL);
#endif
	for (size_t i=0; i < chrDotList.size(); ++i) {
		//working copy of the chrDot vector, in microns
		float x=chrDotList[i].pos.x;
		float y=chrDotList[i].pos.y;
		float z=chrDotList[i].pos.z;

		//turn micron position into flow field pixel one
		const float X=(x -xOffFF) *xResFF;
		const float Y=(y -yOffFF) *yResFF;
		const float Z=(z -zOffFF) *zResFF;

		//move the working copy micron position of the chrDot
		//note: GetPixel() returns 0 in case we ask for value outside the image
		x += GetPixel(*FF.x, X,Y,Z);
		y += GetPixel(*FF.y, X,Y,Z);
		z += GetPixel(*FF.z, X,Y,Z);

		//now, turn the micron position back to phantom pixel one
		const int nX=(int)roundf( (x-xOff) *xRes);
		const int nY=(int)roundf( (y-yOff) *yRes);
		const int nZ=(int)roundf( (z-zOff) *zRes);

		if (territories.Include(nX,nY,nZ))
			territories.SetVoxel(nX,nY,nZ, (PV)floorf((float)i/(float)chrDots));
		else
			DEBUG_REPORT("ups, dot " << chrDotList[i].pos << " is outside the cell");
		//
		//this was nearest neighbor insertion,
		//uncomment following to get tri-linear insertion (but slower)
		/*
		const float nX=(x-xOff) *xRes;
		const float nY=(y-yOff) *yRes;
		const float nZ=(z-zOff) *zRes;
		PutPixel(territories,nX,nY,nZ);
		*/
	}
#ifdef GTGEN_DEBUG
	gettimeofday(&t2,NULL);
	t2.tv_sec-=t1.tv_sec;
	T1=((float)t1.tv_usec / 1000000.0f);
	T2=(float)t2.tv_sec + ((float)t2.tv_usec / 1000000.0f);
	REPORT("rendering chr points altered by FF took " << T2-T1 << " seconds")
#endif
}


template <class MV, class PV>
void Cell<MV, PV>::ChrRenderIntoTerritories(i3d::Image3d<PV> &territories)
{
	DEBUG_REPORT("going to render " << chrDotList.size() << " 'chr' points, ID=" << ID)

	//phantom image related time savers:
	const float xRes=territories.GetResolution().GetX();
	const float yRes=territories.GetResolution().GetY();
	const float zRes=territories.GetResolution().GetZ();
	const float xOff=territories.GetOffset().x;
	const float yOff=territories.GetOffset().y;
	const float zOff=territories.GetOffset().z;

#ifdef GTGEN_DEBUG
	//time-measurement
	struct timeval t1,t2;
	float T1,T2;
	gettimeofday(&t1,NULL);
#endif
	for (size_t i=0; i < chrDotList.size(); ++i) {
		//turn micron position to phantom pixel one
		const int nX=(int)roundf( (chrDotList[i].pos.x-xOff) *xRes);
		const int nY=(int)roundf( (chrDotList[i].pos.y-yOff) *yRes);
		const int nZ=(int)roundf( (chrDotList[i].pos.z-zOff) *zRes);

		if (territories.Include(nX,nY,nZ))
			territories.SetVoxel(nX,nY,nZ,(PV)floorf((float)i/(float)chrDots));
		else
			DEBUG_REPORT("ups, dot " << chrDotList[i].pos << " is outside the cell");
		//
		//this was nearest neighbor insertion,
		//uncomment following to get tri-linear insertion (but slower)
		/*
		const float nX=(x-xOff) *xRes;
		const float nY=(y-yOff) *yRes;
		const float nZ=(z-zOff) *zRes;
		PutPixel(territories,nX,nY,nZ);
		*/
	}
#ifdef GTGEN_DEBUG
	gettimeofday(&t2,NULL);
	t2.tv_sec-=t1.tv_sec;
	T1=((float)t1.tv_usec / 1000000.0f);
	T2=(float)t2.tv_sec + ((float)t2.tv_usec / 1000000.0f);
	REPORT("direct rendering chr points took " << T2-T1 << " seconds")
#endif
}


//------------------------------------------------------------------
template <class MV, class PV>
void Cell<MV,PV>::ChrInitialDistribution(const i3d::Image3d<bool> &mask,
													  const float density)
{
	size_t sizeOfMask=0;	//how many pixels form the mask 

	const bool *m=mask.GetFirstVoxelAddr(); //start address
	bool const *mL=mask.GetFirstVoxelAddr()+mask.GetImageSize(); //stop address

	// counting...
	while (m != mL) 
	{
		sizeOfMask += (*m == true) ? 1 : 0;
		++m;
	}
	DEBUG_REPORT(sizeOfMask << " pixels were found in the mask")

	//how many dots?
	size_t numberOfDots=static_cast<size_t>((float)sizeOfMask * density / 100.0f);

	//this is what is desired, now round it to some multiple of chromosomeCount
	//and to be even, and divisible by four (because of S-phase)
	numberOfDots=ceilf((float)numberOfDots / (float)(4*chrCount)) * (4*chrCount);

	//the number of dots forming one chromosome
	chrDots = numberOfDots/chrCount;
	DEBUG_REPORT("going to use " << chrDots << " molecules for a chromosome, as " << numberOfDots << " is required total")

	//resize the vector in advance to avoid its incremental increasing,
	//which copies the early dots over and over again...
	chrCentres.reserve(chrCount);

	// this way we create continuos ascending sequence of unique
	// IDs
	for (size_t i=0; i<chrCount; i++)
	{
		 chrCentres.push_back(Dot());
	}

	//resize the vector in advance to avoid its incremental increasing,
	//which copies the early dots over and over again...
	chrDotList.reserve(numberOfDots);

	// this way we create continuos ascending sequence of unique IDs
	for (size_t i=0; i<numberOfDots; i++)
	{
		 chrDotList.push_back(Molecule());
	}

	//time savers: resolution [px/um]
	const i3d::Vector3d<float> res = mask.GetResolution().GetRes();

	//get randomness started
	gsl_rng *randState=gsl_rng_alloc(gsl_rng_default);
	unsigned long s=-1 * (int) time(NULL);
	DEBUG_REPORT("randomness started with seed " << s)
	gsl_rng_set(randState,s);

	//finally, generate the demanded amount of dots
	for (size_t i=0; i < chrCount; ++i) 
	{
		//returns some number in the interval <1,sumOverMask> under uniform distribution
		int f=(int)floorf( gsl_ran_flat(randState,1.0,sizeOfMask) );

		//init iteration and find the position given by chance...
		m=mask.GetFirstVoxelAddr();
		while ((m != mL) && (f > 0)) 
		{
			 // 'm' must be incremented here otherwise we could get the
			 // position where *m==false, which is unexpected behaviour
			++m;

			if (*m) --f;
		}

		if (f > 0.0) 
		{
			 throw ERROR_REPORT("Could not find any position for dots. Very strange.");
		} 
		else 
		{
			//we found some legal position within the mask, this is its index/offset
			const size_t index = m - mask.GetFirstVoxelAddr(); //not really nice..... :-(

			//add this dot to the list (no parent)
			i3d::Vector3d<float> fpos;
			
			fpos = i3d::PixelsToMicrons(mask.GetPos(index), res) + mask.GetOffset();

			// store chromosome centre position
			chrCentres[i].pos = fpos;
			chrSpreads[i]=0.f;

			// store all molecules belonging to one chromosome
			for (size_t j=0; j < chrDots; ++j)
			{
				 chrDotList[i*chrDots+j].pos = fpos;
			}
		}
	} //cycle over number of chromosomes

	//release the random generator instance as we don't need it anymore
	gsl_rng_free(randState);

	/*
	 * TODO: remove
	 * just to check the IDs of Dots and Molecules
	for (size_t i=0; i<chrDotList.size(); i++)
	{
		 std::cout << chrDotList[i].ID << " : " << chrDotList[i].pos << std::endl;
	}

	std::cout << "--------" << std::endl;

	for (size_t i=0; i<chrCentres.size(); i++)
	{
		 std::cout << chrCentres[i].ID << " : " << chrCentres[i].pos << std::endl;
	}
	*/
}
//------------------------------------------------------------------



// explicit instantiations to force explicit build of the functions in this file
// because otherwise the linker couldn't find them
template class Cell<i3d::GRAY8,  i3d::GRAY16>;
template class Cell<i3d::GRAY16, i3d::GRAY16>;
