/*
  ==============================================================================

    LayerArray.hpp
    Created: 21 Sep 2014 1:55:15pm
    Author:  jens

  ==============================================================================
*/

#ifndef LAYERARRAY_HPP
#define LAYERARRAY_HPP
#include <stdint.h>
#include <iostream>
#include <Eigen/Dense>

using namespace std;
using namespace Eigen;

class LayerArray;

class LayerArrayListener
{
public:
	LayerArrayListener() {}
	virtual~LayerArrayListener() {}
	
	virtual void onChanged(const LayerArray &obj) = 0;
};

class LayerArray
{
public:
	LayerArray(LayerArrayListener *pListener = nullptr)
	: m_pListener(pListener)
	{
		m_data.resize(0, 0);
	}

	virtual ~LayerArray()
	{
		m_pListener = nullptr;
		clear();
	}

	void add(const RowVectorXd &pData, uint32_t size)
	{
		MatrixXd C(m_data.rows()+pData.rows(), pData.cols());
		if (m_data.rows())
			C << m_data, pData;
		else
			C << pData;
			
		m_data = C;
		if (m_pListener)
		{
			m_pListener->onChanged(*this);
		}
	}

	void clear()
	{
		m_data.resize(0,0);
		if (m_pListener)
			m_pListener->onChanged(*this);
	}

	const MatrixXd& data() const
	{
		return m_data;
	}

	RowVectorXd getAt(uint32_t index) const
	{
		return m_data.row(index);
	}

	RowVectorXd operator[](uint32_t index) const
	{
		return getAt(index);
	}

	void removeAt(uint32_t index)
	{
		if (m_pListener)
			m_pListener->onChanged(*this);
	}

	uint32_t getSize() const
	{
		return m_data.rows();
	}

	void save(const char *pFilename)
	{
		FILE *pFile;

		pFile = fopen(pFilename,"w");

		if (!pFile)
			return;


		fprintf(pFile, "%u\n", (uint32_t)m_data.rows());
		fprintf(pFile, "%u\n", (uint32_t)m_data.cols());

		uint32_t i, j;

		for (i=0; i < m_data.rows(); i++)
		{
			for (j=0; j < m_data.cols(); j++)
			{
				fprintf(pFile, "%3.6f\n", m_data.row(i)(j));
			}
		}

		fclose(pFile);
	}

	void load(const char *pFilename)
	{
		uint32_t size = 0;
		uint32_t numUnits = 0;
		FILE *pFile;

		pFile = fopen(pFilename,"r");

		if (!pFile)
			return;

		int result = fscanf(pFile, "%d\n", &size);
		if (result < 0)
		{
			return;
		}
		result = fscanf(pFile, "%d\n", &numUnits);
		if (result < 0)
		{
			return;
		}
		m_data.resize(size, numUnits);
		RowVectorXd data(numUnits);

		uint32_t i, j;
		for (i=0; i < size; i++)
		{
			for (j=0; j < data.cols(); j++)
			{
				float v;
				int result = fscanf(pFile, "%f", &v);
				if (result > 0)
				{
					data(j) = v;
				}
			}
//			fscanf(pFile, "%d", &numUnits);
			m_data.row(i) = data;
			if (!(i%100) || (i == (size-1)))
				printf("Loaded training sample %u of %u\n", i, size);
		}
		fclose(pFile);
		if (m_pListener)
		{
			m_pListener->onChanged(*this);
		}
	}

private:
	LayerArrayListener *m_pListener;
	MatrixXd m_data;
};

#endif  // LAYERARRAY_HPP
