//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------		
#include <Render/PPMImage.hpp>
#include <cstdio>
#include <limits>
#include <algorithm>
#include <cstring>
#include <fstream>
#include <iostream>
#include <typeinfo>

using std::ofstream;
using std::endl;

namespace Render
{

	//-----------------------------------------------------------------
	// C/D-Tor
	//-----------------------------------------------------------------
	PPMImage::PPMImage(int _width, int _height):
	Film(_width, _height)
	{
		pixels = new PixelComponent[Width*Height*4];
		std::memset(pixels, 0x0, Width*Height*4*sizeof(PixelComponent));

		values = new ValueComponent[Width*Height*4];
		std::memset(values, 0x0, Width*Height*4*sizeof(ValueComponent));		
	}
	//-----------------------------------------------------------------
	PPMImage::~PPMImage()
	{
		delete[] values;
		delete[] pixels;
	}
	//-----------------------------------------------------------------
	void PPMImage::AccumulateRadiance(const Math::ivec2& _pixel, const Math::vec4& _color)
	{
		int index = (_pixel.x + ((Width-1)-_pixel.y)*Width) * 4;
		values[index+0] += _color.r;
		values[index+1] += _color.g;
		values[index+2] += _color.b;
		values[index+3] += _color.a;
	}
	//-----------------------------------------------------------------
	void PPMImage::ToneMapScale(float* _src, unsigned char* _dst, int _nPixels)
	{
		float maxValue = std::numeric_limits<float>::min();
		for(int p=0;p<_nPixels;++p)
		{
			int index = p*4;
			maxValue = std::max(maxValue,_src[index+0]);
			maxValue = std::max(maxValue,_src[index+1]);
			maxValue = std::max(maxValue,_src[index+2]);
		}

		float invMaxValue = 1.f / maxValue;
		for(int p=0;p<_nPixels;++p)
		{
			int index = p*4;
			_dst[index+0] = 255 * _src[index+0] * invMaxValue;
			_dst[index+1] = 255 * _src[index+1] * invMaxValue;
			_dst[index+2] = 255 * _src[index+2] * invMaxValue;
			_dst[index+3] = 255 * _src[index+3];
		}
	}
	//-----------------------------------------------------------------
	void PPMImage::SaveToFile(const std::string& _filename)
	{
	  ofstream file;
	  file.open(_filename.c_str());
	  if (!file)
	    abort();

	  //	  file << "PPM" << endl;
	  file << "P3" << endl;
	  file << Width << endl;
	  file << Height << endl;
	  file << "255" << endl;

	  
	  // Apply tone mapping
	  ToneMapScale(values, pixels, Width * Height);

	  // Copy pixel
	  unsigned long int dataSize = Width * Height;
	  for(unsigned int p=0;p<dataSize;++p)
	    {
	      int index = p*4;
	      file << static_cast<unsigned int>(pixels[index]) << " ";
	      file << static_cast<unsigned int>(pixels[index+1]) << " " ;
	      file << static_cast<unsigned int>(pixels[index+2]) << endl ;
	    }
	}
  
}
