#pragma once

#include "volumeshop.h"

#include "Environment.h"
#include "Exporter.h"
#include "Volume.h"
#include "DataVoxel.h"
#include "Element.h"
#include "Attribute.h"
#include <fstream>

class ExporterSelectionVolumeBrk : public Exporter
{
public:

	ExporterSelectionVolumeBrk(Environment & envEnvironment) : m_envEnvironment(envEnvironment), m_fProgress(0.0f)
	{
	};

	virtual ~ExporterSelectionVolumeBrk()
	{
	};

	Environment & GetEnvironment()
	{
		return m_envEnvironment;
	};

	virtual const bool IsAccepted(const std::string & strFilename)
	{		
		std::string strLower(strFilename);
		std::transform(strFilename.begin(), strFilename.end(), strLower.begin(), tolower);

		std::vector<std::string> vecExtensions;
		vecExtensions.push_back("selectionvolume.brk");

		for (unsigned int i=0;i<vecExtensions.size();i++)
			if (strLower.substr(strLower.size()-vecExtensions[i].size()) == vecExtensions[i])
				return true;

		return false;
	};

	virtual void save(const std::string & strFilename)
	{
		m_fProgress = 0.0f;

		std::cout << "Saving file: " << strFilename << " ... " << std::endl;
		std::cout << "Volume dimensions: (" << GetEnvironment().GetSelectionVolume().GetSizeX() << "," << GetEnvironment().GetSelectionVolume().GetSizeY() << "," << GetEnvironment().GetSelectionVolume().GetSizeZ() << ")" << std::endl;

		std::ofstream oz(strFilename.c_str(),std::ios::out | std::ios::binary);

		unsigned int uBlocksX = GetEnvironment().GetSelectionVolume().GetBlocksX()*BLOCKDIMENSION;
		unsigned int uBlocksY = GetEnvironment().GetSelectionVolume().GetBlocksY()*BLOCKDIMENSION;
		unsigned int uBlocksZ = GetEnvironment().GetSelectionVolume().GetBlocksZ()*BLOCKDIMENSION;

		unsigned int uCount = 0;

		for (unsigned int uZ = 0; uZ < uBlocksZ; uZ += BLOCKDIMENSION)
		{
			for (unsigned int uY = 0; uY < uBlocksY; uY += BLOCKDIMENSION)
			{
				for (unsigned int uX = 0; uX < uBlocksX; uX += BLOCKDIMENSION)
				{
					std::cout << "  " << (100 * uZ) / uBlocksZ << " %" << "\r";
					m_fProgress = float(uZ) / float(uBlocksZ);

					const Volume<SelectionVoxel>::Block & bloBlock = GetEnvironment().GetSelectionVolume().GetBlock(uX,uY,uZ);

					if (!bloBlock.GetBounds().IsEmpty())
					{
						oz.write((char*)&uX,sizeof(unsigned int));
						oz.write((char*)&uY,sizeof(unsigned int));
						oz.write((char*)&uZ,sizeof(unsigned int));
						oz.write((char*)bloBlock.Get(),BLOCKSIZE*sizeof(SelectionVoxel));
						uCount++;
					}
				}
			}
		}

		size_t uIndex = std::string::npos;
		std::string strRelativeFilename;
		uIndex = strFilename.find_last_of("\\/");		
		strRelativeFilename = (uIndex != std::string::npos ? strFilename.substr(uIndex+1,std::string::npos) : strFilename);

		std::string strAdditionalFilename;
		uIndex = strFilename.find_last_of('.');
		strAdditionalFilename = (uIndex != std::string::npos ? strFilename.substr(0,uIndex) : strFilename);
		strAdditionalFilename += std::string(".xml");

		Element eleRoot("volume");

		eleRoot[ Element("size") ][ Attribute("x") ] = GetEnvironment().GetSelectionVolume().GetSizeX();
		eleRoot[ Element("size") ][ Attribute("y") ] = GetEnvironment().GetSelectionVolume().GetSizeY();
		eleRoot[ Element("size") ][ Attribute("z") ] = GetEnvironment().GetSelectionVolume().GetSizeZ();

		eleRoot[ Element("scale") ][ Attribute("x") ] = GetEnvironment().GetSelectionVolume().GetScale().GetX();
		eleRoot[ Element("scale") ][ Attribute("y") ] = GetEnvironment().GetSelectionVolume().GetScale().GetY();
		eleRoot[ Element("scale") ][ Attribute("z") ] = GetEnvironment().GetSelectionVolume().GetScale().GetZ();

		eleRoot[ Element("blocks") = uCount];
		eleRoot[ Element("filename") = strRelativeFilename ];

		std::ofstream of(strAdditionalFilename.c_str());
		of << eleRoot;

		std::cout << "Success saving file." << std::endl << std::endl;	
		m_fProgress = 1.0f;
	};

	virtual const float GetProgress()
	{
		return m_fProgress;
	};

private:

	Environment & m_envEnvironment;
	float m_fProgress;
};