#include <iostream>
#include <i3d/image3d.h>

#include "randWalk.h"

///define whether to produce data for MSD calculation
#define MSD_OUTPUT
const int TimeDeltaMinutes=29; //simulations - cell cycle = 50 frames

#define HISTOGRAM_OUTPUT
#define INDIVIDUAL_PATHS_OUTPUT
#define COMBINED_PATHS_OUTPUT


int main(int argc,char **argv)
{
	i3d::Image3d<i3d::GRAY16> pathsI,pathsC,histogram;

#ifdef INDIVIDUAL_PATHS_OUTPUT
	pathsI.MakeRoom(1000,1000,1); //individual paths
#endif
#ifdef COMBINED_PATHS_OUTPUT
	pathsC.MakeRoom(1000,1000,1); //combined paths
	pathsC.GetVoxelData()=0;
#endif
#ifdef HISTOGRAM_OUTPUT
	histogram.MakeRoom(1000,1000,1);
	histogram.GetVoxelData()=0;
#endif

	//init this walk
	RandomWalk<float> rw;
	//rw.UseWrappedCauchyDistribution(0.5);
	//rw.UseWrappedNormalDistribution(0.4);
	//rw.UseUniformDistribution();
	rw.UseCorrectedUniformDistribution();
	//My own testing 3-peaks distribution:
	/*
	rw.turningAngleDistribution[-1.0]=0.;
	rw.turningAngleDistribution[-0.8]=1.;
	rw.turningAngleDistribution[-0.6]=0.;
	rw.turningAngleDistribution[-0.2]=0.;
	rw.turningAngleDistribution[ 0.0]=1.;
	rw.turningAngleDistribution[+0.2]=0.;
	rw.turningAngleDistribution[+0.6]=0.;
	rw.turningAngleDistribution[+0.8]=1.;
	rw.turningAngleDistribution[+1.0]=0.;
	*/
	rw.PrepareRandomTurningField();

	//rw.UseFixedDisplacementStep(2.0f); //this is basically the speed
	rw.displacementStepSizeDistribution[0]=1979;
	rw.displacementStepSizeDistribution[0.33333]=607;
	rw.displacementStepSizeDistribution[0.66667]=533;
	rw.displacementStepSizeDistribution[1]=663;
	rw.displacementStepSizeDistribution[1.3333]=610;
	rw.displacementStepSizeDistribution[1.6667]=660;
	rw.displacementStepSizeDistribution[2]=573;
	rw.displacementStepSizeDistribution[2.3333]=510;
	rw.displacementStepSizeDistribution[2.6667]=361;
	rw.displacementStepSizeDistribution[3]=361;
	rw.displacementStepSizeDistribution[3.3333]=231;
	rw.displacementStepSizeDistribution[3.6667]=229;
	rw.displacementStepSizeDistribution[4]=173;
	rw.displacementStepSizeDistribution[4.3333]=157;
	rw.displacementStepSizeDistribution[4.6667]=87;
	rw.displacementStepSizeDistribution[5]=138;
	rw.displacementStepSizeDistribution[5.3333]=68;
	rw.displacementStepSizeDistribution[5.6667]=73;
	rw.displacementStepSizeDistribution[6]=39;
	rw.displacementStepSizeDistribution[6.3333]=64;
	rw.displacementStepSizeDistribution[6.6667]=44;
	rw.displacementStepSizeDistribution[7]=34;
	rw.displacementStepSizeDistribution[7.3333]=26;
	rw.displacementStepSizeDistribution[7.6667]=27;
	rw.displacementStepSizeDistribution[8]=20;
	rw.displacementStepSizeDistribution[8.3333]=15;
	rw.displacementStepSizeDistribution[8.6667]=5;
	rw.displacementStepSizeDistribution[9]=10;
	rw.displacementStepSizeDistribution[9.3333]=4;
	rw.displacementStepSizeDistribution[9.6667]=16;
	rw.PrepareRandomStepSizeField(0.1f);

	/*
	std::cout << "Ready for simulation? "
	          << ((rw.ReadyToStartSimulation())? "yes":"no")
				 << "\n";
	*/

	//several random walks...
	for (int attemptNo=0; attemptNo < 200; ++attemptNo)
	{
		//std::cout << "========== " << attemptNo << "==========\n";

		//name this walk
		char attemptName[50];
		sprintf(attemptName,"wALk%06d.tif",attemptNo);
		//if (!(attemptNo % 500)) std::cout << attemptName << "\n";

		//initial position
		float posX=500.f;
		float posY=500.f;
#ifdef INDIVIDUAL_PATHS_OUTPUT
		pathsI.GetVoxelData()=0;
		pathsI.SetVoxel(round(posX),round(posY),0, 100);
#endif
#ifdef COMBINED_PATHS_OUTPUT
		if (attemptNo < 10)
			pathsC.SetVoxel(round(posX),round(posY),0, attemptNo+1);
#endif

#ifdef MSD_OUTPUT
		char fn[100];
		//report...
		sprintf(fn,"T %05d",0*TimeDeltaMinutes);
		if (attemptNo < 300)
		std::cout << "ID " << attemptNo+1 << " " << fn << " POSX " << posX << " POSY " << posY << "\n";
#endif

		//reset initial direction
		// (would rather reset the whole RandomWalk object, but
		//  seeding is not working properly... rapid inits...)
		rw.ResetXYHeading(0.);

		//do the walk...
		for (int step=0; step < 40; ++step)
		{
			//update heading
			float dx,dy;
			rw.DoOneStep2D(dx,dy);

			//update current position
			posX += dx;
			posY += dy;
			
			//draw current position
#ifdef INDIVIDUAL_PATHS_OUTPUT
			pathsI.SetVoxel(round(posX),round(posY),0, 100+5*step);
#endif
#ifdef COMBINED_PATHS_OUTPUT
			if (attemptNo < 10)
				pathsC.SetVoxel(round(posX),round(posY),0, attemptNo+1);
#endif

#ifdef MSD_OUTPUT
			//report...
			sprintf(fn,"T %05d",(step+1)*TimeDeltaMinutes);
			if (attemptNo < 300)
			std::cout << "ID " << attemptNo+1 << " " << fn << " POSX " << posX << " POSY " << posY << "\n";
#endif
		}

#ifdef HISTOGRAM_OUTPUT
		//record the final position into the histogram of end-positions
		if (histogram.Include(round(posX),round(posY),0))
			histogram.SetVoxel(round(posX),round(posY),0,
			           histogram.GetVoxel(round(posX),round(posY),0)+1);
#endif

#ifdef INDIVIDUAL_PATHS_OUTPUT
		if (attemptNo < 50)
			pathsI.SaveImage(attemptName);
#endif
	}

#ifdef COMBINED_PATHS_OUTPUT
	pathsC.SaveImage("wALks_combined.tif");
#endif
#ifdef HISTOGRAM_OUTPUT
	histogram.SaveImage("histogram_endPositions.tif");
#endif

	return(0);
}
