#include <iostream>
#include <i3d/image3d.h>
#include <cytopacq/optigen.h>
#include <ini/iniparser.h>

using std::cout;
using std::endl;
using std::cerr;

using namespace i3d;

//---------------------------------------------------------------------------
// the function describing the use of this console application
// it is called whenever the program is called without parameters
// or with bad combination of parameters
//----------------------------------------------------------------------------
void usage(const char *name)
{
	 cerr << "APPLICATION NAME" << endl <<
				"\t" << name << " ... application first blurs the given image respecting the provided mask and then writes max. intensity value " <<
				endl << endl;
	 cerr << "SYNTAX" << endl << "\t" << name << " <phantom image> <mask image> <config_file>" << endl << endl;
}

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

template <class T> T GetMaxValue(const char *imgPhantomName, 
											const char *imgMaskName,
											const char *configFile)
{
	 IniHandler 
				iniParams(configFile);

	 Image3d<T> 
				imgPhantom(imgPhantomName), 
				imgMask(imgMaskName);

	 int cytoLevel = iniParams["cell"]["intensity of nonspecific staining"];

	 cout << "cyto level: " << cytoLevel << endl;

	 for (size_t i=0; i<imgPhantom.GetImageSize(); i++)
	 {
		  if (imgMask.GetVoxel(i))
		  {
				T *value = imgPhantom.GetVoxelAddr(i);
				*value += cytoLevel;
		  }
	 }

	 CallOptigen(iniParams, imgPhantom);

	 return imgPhantom.GetMaxValue();
}

//-----------------------------------------------------------------------------
int main(int argc, char *argv[])
{
	 if (argc < 4)
	 {
		  usage(argv[0]);
		  exit(-1);
	 }

	 try {
		  ImgVoxelType vt = ReadImageType(argv[1]);

		  switch (vt)
		  {
				case Gray16Voxel:
						  {
								cout << GetMaxValue<GRAY16>(argv[1],
																	 argv[2],
																	 argv[3]) << endl;
								break;
						  }
				case Gray8Voxel:
						  {
								cout << GetMaxValue<GRAY8>(argv[1],
																	argv[2],
																	argv[3]) << endl;
								break;
						  }
				default:
						  cerr << "Other voxel types not supported" << endl;
		  }
	 }
	 catch (const char *e)
	 {
		cout << e << endl;
	 }
	 catch (std::string &e)
	 {
		cout << e << endl;
	 }
	 catch (i3d::IOException& e)
	 {
		cout << e << endl;
	 }
	 catch (i3d::InternalException& e)
	 {
		cout << e << endl;
	 }
	 catch (std::bad_alloc&)
	 {
		cout << "Not enough memory." << endl;
	 }
	 catch (...)
	 {
		cout << "System exception." << endl;
	 }

	 return 0;
}
