#ifndef GELIB_IMPL_INDEXEDNODE_H_
#define GELIB_IMPL_INDEXEDNODE_H_

//=================================================================================================================
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// This class proides a generic means of creating a list of 1-dimensional problems using n-dimensional input/output, 
// in particular, it can be contructed to populate a list of IndexedObjects, which indexes each 1-dimensional vector in the
// n-dimensional data which is produced when the data is fixed in n - 1 dimensions.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//=================================================================================================================

#include <vector>
#include <memory>
#include <array>
#include <algorithm>
#include "IndexedData.h"
#include "Indexed.h"
#include "IndexedObject.h"
#include "../generic_classes/Containers.h"

namespace gelib_impl
{

	//=================================================================================================================
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Declaration:  0 < current_depth < max_depth
	//
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//=================================================================================================================

	template <const size_t max_depth, const size_t current_depth>
	class IndexedNode : public Indexed<current_depth>
	{

		///////////////////////////////////////////////////////////////////////////////
		// children of this spline node, one for each grid point of this dimension
		///////////////////////////////////////////////////////////////////////////////
		std::vector<IndexedNode<max_depth, current_depth + 1>*> m_children;

		IndexedNode();

	protected:

		IndexedNode(const IndexedNode<max_depth, 0>* master_node, std::array<int, current_depth>& indices);

		const IndexedNode<max_depth, 0>* m_master_node;

		void create_children(
			const IndexedNode<max_depth, 0>* master_node,
			std::vector<const double*>& input_start,
			std::vector<double*>& output_start);

	public:

		IndexedNode(
			const IndexedNode<max_depth, 0>* master_node,

			std::vector<const double*> input_start,

			std::vector<double*> output_start,

			std::array<int, current_depth>& indices
		);

		virtual void update_starts(std::vector<double*>& output_start, std::vector<const double*>& input_start);

		const IndexedNode<max_depth, 0>* get_master() const
		{
			return m_master_node;
		}

		virtual int get_start() const
		{
			return get_master()->get_start(current_depth);
		}

		virtual int get_stop() const
		{
			return get_master()->get_stop(current_depth);
		}

		virtual bool is_fixed() const
		{
			return false;
		}

		virtual IndexedNode<max_depth, current_depth + 1>* make_child(
			const IndexedNode<max_depth, 0>* master_node,
			std::vector<const double*>& input_start,
			std::vector<double*>& output_start,
			std::array<int, current_depth + 1> new_indices) const;

		~IndexedNode();

	};

	template <const size_t max_depth, const size_t current_depth>
	class HeadlessIndexedNode : public IndexedNode<max_depth, current_depth>
	{

		size_t m_fixed_depth;

	public:
		HeadlessIndexedNode(
			const IndexedNode<max_depth, 0>* master_node,
			std::vector<const double*> input_start,
			std::vector<double*> output_start,
			std::array<int, current_depth>& indices,
			const size_t depth
		);

		const IndexedNode<max_depth, 0>* get_master() const
		{
			return IndexedNode<max_depth, current_depth>::get_master();
		}

		void update_starts(std::vector<double*>& output_start, std::vector<const double*>& input_start) override;

		int get_start() const override
		{
			return 0;
		}

		int get_stop() const override
		{
			return (int)(*get_master()->m_output_data)[m_fixed_depth]->get_dimension_size(get_master()->m_ordering[current_depth]);
		}

		size_t get_fixed_depth() const
		{
			return m_fixed_depth;
		}

		bool is_fixed() const override
		{
			return true;
		}

		static IndexedNode<max_depth, current_depth + 1>* make_child(
			const IndexedNode<max_depth, 0>* master_node,
			std::vector<const double*>& input_start,
			std::vector<double*>& output_start,
			std::array<int, current_depth + 1> new_indices,
			size_t fixed_depth);

		IndexedNode<max_depth, current_depth + 1>* make_child(
			const IndexedNode<max_depth, 0>* master_node,
			std::vector<const double*>& input_start,
			std::vector<double*>& output_start,
			std::array<int, current_depth + 1> new_indices) const override
		{
			return HeadlessIndexedNode<max_depth, current_depth>::make_child(
				master_node,
				input_start,
				output_start,
				new_indices,
				get_fixed_depth()
			);
		}

	};


	//=================================================================================================================
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Declaration: current_depth = 0
	//
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//=================================================================================================================

	template <const size_t max_depth>
	class IndexedNode<max_depth, 0> : public Indexed<0>
	{
		///////////////////////////////////////////////////////////////////////////////
		// children of this spline node, one for each grid point of this dimension
		///////////////////////////////////////////////////////////////////////////////
		std::vector<IndexedNode<max_depth, 1>*> m_children;

		void master_create_children();

		///////////////////////////////////////////////////////////////////////////////
		// instructs nodes with m_start_stop[current_depth]
		// how many children to make
		///////////////////////////////////////////////////////////////////////////////
		std::array<std::array<int, 2>, max_depth> m_start_stop;

		void construct(
			// n-dimensional grid values
			std::vector<d_vector>& grid_data,

			// n-dimensional function value at each grid value combination
			std::vector<const IndexedData<max_depth>*> const& input_data,

			// output data, which may vary in sizing from function data in up to 1 dimension
			std::vector<IndexedData<max_depth>*>& output_data,

			// A reference to the vector where object pointers are contiguously stored,
			// one for each base node
			std::vector<std::unique_ptr<IndexedObject<max_depth>>>& objects,

			std::array<size_t, max_depth> ordering
		);

		std::vector<const IndexedData<max_depth>*> m_input_data_ref;
		std::vector<IndexedData<max_depth>*> m_output_data_ref;

	public:

		virtual IndexedNode<max_depth, 1>* make_child(
			const IndexedNode<max_depth, 0>* master_node,
			std::vector<const double*>& input_start,
			std::vector<double*>& output_start,
			std::array<int, 1> new_indices) const;


		virtual void update_starts(std::vector<double*>& output_start, std::vector<const double*>& input_start);

		const IndexedNode<max_depth, 0>* get_master() const
		{
			return this;
		}

		const std::vector<IndexedData<max_depth>*>& get_out_ref() const
		{
			return m_output_data_ref;
		}

		const std::vector<const IndexedData<max_depth>*>& get_in_ref() const
		{
			return m_input_data_ref;
		}

		virtual bool is_fixed() const
		{
			return false;
		}

		virtual int get_start() const
		{
			return get_start(0);
		}

		virtual int get_stop() const
		{
			return get_stop(0);
		}

		int get_start(size_t depth) const
		{
			return m_start_stop[depth][0];
		}

		int get_stop(size_t depth) const
		{
			return m_start_stop[depth][1];
		}


		///////////////////////////////////////////////////////////////////////////////
		// grid data associated with the input data, i.e dimensions matching
		///////////////////////////////////////////////////////////////////////////////
		const std::vector<d_vector>* m_grid_data;

		const std::vector<const IndexedData<max_depth>*>* m_input_data;

		const std::vector<IndexedData<max_depth>*>* m_output_data;

		std::array<size_t, max_depth> m_ordering;

		///////////////////////////////////////////////////////////////////////////////
		// Objects are filled up at the base nodes (current_depth = max_depth)
		///////////////////////////////////////////////////////////////////////////////
		std::vector<std::unique_ptr<IndexedObject<max_depth>>>* m_objects;

		IndexedNode(
			// n-dimensional grid values
			std::vector<d_vector>& grid_data,

			// n-dimensional function value at each grid value combination
			std::vector<const IndexedData<max_depth>*> const& input_data,

			// output data, which may vary in sizing from function data in up to 1 dimension
			std::vector<IndexedData<max_depth>*>& output_data,

			// A reference to the vector where object pointers are contiguously stored,
			// one for each base node
			std::vector<std::unique_ptr<IndexedObject<max_depth>>>& objects

		);

		IndexedNode(
			// n-dimensional grid values
			std::vector<d_vector>& grid_data,

			// n-dimensional function value at each grid value combination
			std::vector<const IndexedData<max_depth>*> const& input_data,

			// output data, which may vary in sizing from function data in up to 1 dimension
			std::vector<IndexedData<max_depth>*>& output_data,

			// A reference to the vector where object pointers are contiguously stored,
			// one for each base node
			std::vector<std::unique_ptr<IndexedObject<max_depth>>>& objects,

			std::array<size_t, max_depth> ordering

		);

	};

	//=================================================================================================================
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Declaration: current_depth = max_depth 
	// All IndexedNode at max_depth should be HeadlessIndexedNode
	//
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//=================================================================================================================


	template <const size_t max_depth>
	class IndexedNode<max_depth, max_depth> : public Indexed<max_depth>
	{

	protected:

		///////////////////////////////////////////////////////////////////////////////
		// pointer to start of fitting data for this Nodes children
		// i.e for a dimension of length d, m_input_start+i gives data start (function values)
		// with each integer 0 <= i <= d
		///////////////////////////////////////////////////////////////////////////////
		std::vector<const double*> m_input_start;

		///////////////////////////////////////////////////////////////////////////////
		// pointer to output to for this dimension
		// i.e for a dimension of length d, m_ouput_start+i gives start of where output array should be
		// with each integer 0 <= i <= d
		///////////////////////////////////////////////////////////////////////////////
		std::vector<double*> m_output_start;
		//TODO remove??
		std::vector<size_t> m_input_data_gaps;

	public:

		virtual std::vector<size_t> const& get_input_data_gaps() const;

		virtual const std::vector<const double*>& get_input_start() const;

		virtual double* get_output_start();

		IndexedNode(
			const IndexedNode<max_depth, 0>* master_node,

			std::vector<const double*> input_start,

			std::vector<double*> output_start,

			std::array<int, max_depth>& indices
		);

	};

	template <const size_t max_depth>
	class HeadlessIndexedNode<max_depth, max_depth> : public IndexedNode<max_depth, max_depth>, public IndexedObject<max_depth>
	{
		std::vector<size_t> m_input_data_gaps;

		///////////////////////////////////////////////////////////////////////////////
		// pointer to (contiguous) grid points for this node
		///////////////////////////////////////////////////////////////////////////////
		const double* m_grid_points;

		///////////////////////////////////////////////////////////////////////////////
		// number of elements in m_grid_points
		///////////////////////////////////////////////////////////////////////////////
		size_t m_no_grid_points;

		///////////////////////////////////////////////////////////////////////////////
		// if m_fixed_index is true, then this is the fixing depth
		///////////////////////////////////////////////////////////////////////////////
		size_t m_fixed_depth;


	public:

		~HeadlessIndexedNode() = default;

		HeadlessIndexedNode(
			const IndexedNode<max_depth, 0>* master_node,

			std::vector<const double*> input_start,

			std::vector<double*> output_start,

			std::array<int, max_depth>& indices,

			const size_t depth
		);

		///////////////////////////////////////////////////////////////////////////////
		// Overrides to abstract class IndexedObject
		///////////////////////////////////////////////////////////////////////////////

		std::array<int, max_depth>& get_indices() const override;

		const double* get_grid_start() const override;

		size_t no_grid_points() const override;

		size_t get_fixed_depth() const override;

		std::vector<size_t> const& get_input_data_gaps() const override;

		const double* get_input_start(size_t which) const override;

		double* get_output_start() override;

	};

	//=================================================================================================================
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Alises: For convenience in exterior classes
	//
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//=================================================================================================================

	template<const size_t max_depth>
	using DataIndexerBase = HeadlessIndexedNode<max_depth, max_depth>;

	template<const size_t max_depth>
	using DataIndexerRoot = IndexedNode<max_depth, 0>;


	//=================================================================================================================
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Implementation: 
	// 0 <= current_depth <= max_depth
	//
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//=================================================================================================================

	template <const size_t max_depth, const size_t current_depth>
	void create_children_helper(
		IndexedNode<max_depth, current_depth>* this_node,
		std::vector<const double*>& input_start,
		std::vector<double*>& output_start,
		std::vector<IndexedNode<max_depth, current_depth + 1>*> children)
	{
		const IndexedNode<max_depth, 0>* master_node = this_node->get_master();
		const size_t new_depth = current_depth + 1;
		int i;
		IndexedNode<max_depth, new_depth>* new_node;
		std::array<int, new_depth> new_indices;
		std::copy(this_node->get_indices().begin(), this_node->get_indices().end(), new_indices.begin());

		int start = this_node->get_start();
		int stop = this_node->get_stop();

		///////////////////////////////////////////
		// if last set of children to be created
		//////////////////////////////////////////
		auto constexpr reached_max = new_depth == max_depth;

		if constexpr (reached_max)
		{
			if (!this_node->is_fixed())
				stop = 0;
		}

		i = start;
		children.reserve(((size_t)stop) - start);

		///////////////////////////////////////////////////////////////////////////////
		// First child should always be headless node instance
		///////////////////////////////////////////////////////////////////////////////
		if (i == -1)
		{
			new_indices[current_depth] = i;

			new_node = HeadlessIndexedNode<max_depth, current_depth>::make_child(
				master_node,
				input_start,
				output_start,
				new_indices,
				current_depth
			);

			children.push_back(new_node);
			++i;
		}


		///////////////////////////////////////////////////////////////////////////////
		// loop to create children
		///////////////////////////////////////////////////////////////////////////////
		for (; i < stop; ++i)
		{
			new_indices[current_depth] = i;

			new_node = this_node->make_child(
				master_node,
				input_start,
				output_start,
				new_indices
			);

			children.push_back(new_node);

			// incremement data pointers in output_start and input_start
			this_node->update_starts(output_start, input_start);

		}
	}

	template<size_t max_depth, size_t current_depth>
	IndexedNode<max_depth, current_depth>::IndexedNode(const IndexedNode<max_depth, 0>* master_node, std::array<int, current_depth>& indices)
		:
		Indexed<current_depth>(indices),
		m_master_node(master_node)
	{}

	template <const size_t max_depth, const size_t current_depth>
	void IndexedNode<max_depth, current_depth>::create_children(
		const IndexedNode<max_depth, 0>* master_node,
		std::vector<const double*>& input_start,
		std::vector<double*>& output_start)
	{
		create_children_helper<max_depth, current_depth>(
			this,
			input_start,
			output_start,
			m_children);
	}

	template<size_t max_depth, size_t current_depth>
	IndexedNode<max_depth, current_depth>::IndexedNode(
		const IndexedNode<max_depth, 0>* master_node,
		std::vector<const double*> input_start,
		std::vector<double*> output_start,
		std::array<int, current_depth>& indices)
		:
		Indexed<current_depth>(indices),
		m_master_node(master_node)
	{
		create_children(master_node, input_start, output_start);
	}

	template<size_t max_depth, size_t current_depth>
	void IndexedNode<max_depth, current_depth>::update_starts(std::vector<double*>& output_start, std::vector<const double*>& input_start)
	{
		for (size_t j = 0; j < input_start.size(); ++j)
			input_start[j] += (*get_master()->m_input_data)[j]->get_data_gap(get_master()->m_ordering[current_depth]);

		for (size_t j = 0; j < output_start.size(); ++j)
			output_start[j] += (*get_master()->m_output_data)[j]->get_data_gap(get_master()->m_ordering[current_depth]);

	}

	template<size_t max_depth>
	void IndexedNode<max_depth, 0>::update_starts(std::vector<double*>& output_start, std::vector<const double*>& input_start)
	{
		for (size_t j = 0; j < input_start.size(); ++j)
			input_start[j] += (*m_input_data)[j]->get_data_gap(m_ordering[0]);

		for (size_t j = 0; j < output_start.size(); ++j)
			output_start[j] += (*m_output_data)[j]->get_data_gap(m_ordering[0]);

	}

	template<size_t max_depth, size_t current_depth>
	IndexedNode<max_depth, current_depth + 1>* IndexedNode<max_depth, current_depth>::make_child(
		const IndexedNode<max_depth, 0>* master_node,
		std::vector<const double*>& input_start,
		std::vector<double*>& output_start,
		std::array<int, current_depth + 1> new_indices) const
	{
		return new IndexedNode<max_depth, current_depth + 1>(
			master_node,
			input_start,
			output_start,
			new_indices
			);
	}

	template<size_t max_depth>
	IndexedNode<max_depth, 1>* IndexedNode<max_depth, 0>::make_child(
		const IndexedNode<max_depth, 0>* master_node,
		std::vector<const double*>& input_start,
		std::vector<double*>& output_start,
		std::array<int, 1> new_indices) const
	{
		return new IndexedNode<max_depth, 1>(
			master_node,
			input_start,
			output_start,
			new_indices
			);
	}

	template <const size_t max_depth, const size_t current_depth>
	IndexedNode<max_depth, current_depth>::~IndexedNode()
	{
		Containers::delete_vector(m_children);
	}

	template<size_t max_depth, size_t current_depth>
	HeadlessIndexedNode<max_depth, current_depth>::HeadlessIndexedNode(
		const IndexedNode<max_depth, 0>* master_node,
		std::vector<const double*> input_start,
		std::vector<double*> output_start,
		std::array<int, current_depth>& indices,
		const size_t depth)
		:
		IndexedNode<max_depth, current_depth>(master_node, indices),
		m_fixed_depth(depth)
	{
		create_children(master_node, input_start, output_start);
	}

	template<size_t max_depth, size_t current_depth>
	void HeadlessIndexedNode<max_depth, current_depth>::update_starts(std::vector<double*>& output_start, std::vector<const double*>& input_start)
	{
		size_t which_output = std::min<size_t>(m_fixed_depth, get_master()->m_output_data->size() - 1);

		// in this case input_start[0] is referencing output_data[which_output - 1]
		if (which_output > 0)
		{
			input_start[0] += (*get_master()->m_output_data)[which_output - 1]->get_data_gap(get_master()->m_ordering[current_depth]);
		}
		else
		{
			input_start[0] += (*get_master()->m_input_data)[0]->get_data_gap(get_master()->m_ordering[current_depth]);
		}

		for (size_t j = 1; j < input_start.size(); ++j)
			input_start[j] += (*get_master()->m_input_data)[j]->get_data_gap(get_master()->m_ordering[current_depth]);


		for (size_t j = 0; j < output_start.size(); ++j)
			output_start[j] += (*get_master()->m_output_data)
			[which_output]->get_data_gap(get_master()->m_ordering[current_depth]);

	}

	template<size_t max_depth, size_t current_depth>
	IndexedNode<max_depth, current_depth + 1>* HeadlessIndexedNode<max_depth, current_depth>::make_child(
		const IndexedNode<max_depth, 0>* master_node,
		std::vector<const double*>& input_start,
		std::vector<double*>& output_start,
		std::array<int, current_depth + 1> new_indices,
		size_t fixed_depth)
	{

		size_t new_input_ind = current_depth;
		std::vector<const double*> input_start_new;
		input_start_new = input_start;

		// If more than one output array, Input[0] becomes output of previous step
		// for subsequent nodes
		if (output_start.size() > 1 && new_input_ind != 0)
			input_start_new[0] = output_start[new_input_ind - 1];

		std::vector<double*> output_start_new(
			{ output_start[std::min<size_t>(new_input_ind, output_start.size() - 1)] }
		);

		if constexpr (max_depth == current_depth + 1)
		{
			master_node->m_objects->push_back(
				std::unique_ptr<IndexedObject<max_depth>>
				(new HeadlessIndexedNode<max_depth, current_depth + 1>
				(
					master_node,
					input_start_new,
					output_start_new,
					new_indices,
					fixed_depth
					)
					)
			);
			return nullptr;
		}
		else
		{
			return new HeadlessIndexedNode<max_depth, current_depth + 1>(
				master_node,
				input_start_new,
				output_start_new,
				new_indices,
				fixed_depth
				);
		}
	}


	//=================================================================================================================
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Implementation: current_depth == 0
	//
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//=================================================================================================================

	template<size_t max_depth>
	void IndexedNode<max_depth, 0>::construct(
		std::vector<d_vector>& grid_data,
		std::vector<const IndexedData<max_depth>*> const& input_data,
		std::vector<IndexedData<max_depth>*>& output_data,
		std::vector<std::unique_ptr<IndexedObject<max_depth>>>& objects,
		std::array<size_t, max_depth> ordering)
	{

		m_input_data_ref = input_data;
		m_output_data_ref = output_data;

		std::copy(ordering.begin(), ordering.end(), m_ordering.begin());

		for (size_t i = 0; i < max_depth; ++i)
		{
			m_start_stop[i] = { -1, 0 };
		}

		for (size_t i = 0; i < output_data.size() - 1; ++i)
			m_start_stop[i][1] = (int)output_data[i]->get_dimension_size(m_ordering[i]);

		m_grid_data = &grid_data;
		m_input_data = &input_data;
		m_output_data = &output_data;
		m_objects = &objects;

		master_create_children();
	}

	template<const size_t max_depth>
	IndexedNode<max_depth, 0>::IndexedNode(
		std::vector<d_vector>& grid_data,
		std::vector<const IndexedData<max_depth>*> const& input_data,
		std::vector<IndexedData<max_depth>*>& output_data,
		std::vector<std::unique_ptr<IndexedObject<max_depth>>>& objects)
		:
		Indexed<0>()
	{
		construct(
			grid_data,
			input_data,
			output_data,
			objects,
			std::array<size_t, max_depth>({ 0, 1, 2 })); // TODO Note that last argument only works with 3 dimensions, should be easy to generalise 
	}

	template<size_t max_depth>
	IndexedNode<max_depth, 0>::IndexedNode(
		std::vector<d_vector>& grid_data,
		std::vector<const IndexedData<max_depth>*> const& input_data,
		std::vector<IndexedData<max_depth>*>& output_data,
		std::vector<std::unique_ptr<IndexedObject<max_depth>>>& objects,
		std::array<size_t, max_depth> ordering)
		:
		Indexed<0>()
	{
		construct(
			grid_data,
			input_data,
			output_data,
			objects,
			ordering);
	}

	template <const size_t max_depth>
	void IndexedNode<max_depth, 0>::master_create_children()
	{
		///////////////////////////////////////////////////////////////////////////////
		// data pointers initally all point to the start of input/output arrays
		///////////////////////////////////////////////////////////////////////////////
		std::vector<const double*> input_start;
		std::vector<double*> output_start;

		input_start.resize(m_input_data->size());
		output_start.resize(m_output_data->size());

		for (size_t j = 0; j < input_start.size(); ++j)
			input_start[j] = &m_input_data->at(j)->at(0);

		for (size_t j = 0; j < output_start.size(); ++j)
			output_start[j] = &m_output_data->at(j)->at(0);

		create_children_helper<max_depth, 0>(
			this,
			input_start,
			output_start,
			m_children);
	}


	//=================================================================================================================
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Implementation: current_depth == max_depth
	//
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//=================================================================================================================


	template<size_t max_depth>
	IndexedNode<max_depth, max_depth>::IndexedNode(
		const IndexedNode<max_depth, 0>* master_node,
		std::vector<const double*> input_start,
		std::vector<double*> output_start,
		std::array<int, max_depth>& indices
	)
		:
		Indexed<max_depth>(indices),
		m_input_start(input_start),
		m_output_start(output_start)
	{}

	template<size_t max_depth>
	HeadlessIndexedNode<max_depth, max_depth>::HeadlessIndexedNode(
		const IndexedNode<max_depth, 0>* master_node,
		std::vector<const double*> input_start,
		std::vector<double*> output_start,
		std::array<int, max_depth>& indices,
		const size_t depth
	)
		: m_fixed_depth(depth),
		IndexedObject<max_depth>(master_node->get_in_ref(), master_node->get_out_ref()[depth]),
		IndexedNode<max_depth, max_depth>(master_node, input_start, output_start, indices)
	{

		m_input_data_gaps.resize(master_node->m_input_data->size());

		for (size_t i = 0; i < m_input_data_gaps.size(); ++i)
			m_input_data_gaps[i] = (*master_node->m_input_data)[i]->get_data_gap(master_node->m_ordering[m_fixed_depth]);

		m_grid_points = &((*master_node->m_grid_data)[master_node->m_ordering[m_fixed_depth]])[0];
		m_no_grid_points = (*master_node->m_grid_data)[master_node->m_ordering[m_fixed_depth]].size();

	}

	//=================================================================================================================
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Getters IndexedNode<max_depth, max_depth>
	//
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//=================================================================================================================

	template <const size_t max_depth>
	const std::vector<const double*>& IndexedNode<max_depth, max_depth>::get_input_start() const
	{
		return m_input_start;
	}

	template <const size_t max_depth>
	double* IndexedNode<max_depth, max_depth>::get_output_start()
	{
		return m_output_start[0];
	}

	template<size_t max_depth>
	std::vector<size_t> const& IndexedNode<max_depth, max_depth>::get_input_data_gaps() const
	{
		return m_input_data_gaps;
	}

	//=================================================================================================================
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//
	// Getters HeadlessIndexedNode<max_depth, max_depth>
	//
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	//=================================================================================================================

	template<size_t max_depth>
	std::array<int, max_depth>& HeadlessIndexedNode<max_depth, max_depth>::get_indices() const
	{
		return Indexed<max_depth>::get_indices();
	}

	template <const size_t max_depth>
	const double* HeadlessIndexedNode<max_depth, max_depth>::get_grid_start() const
	{
		return m_grid_points;
	}

	template <const size_t max_depth>
	size_t HeadlessIndexedNode<max_depth, max_depth>::no_grid_points() const
	{
		return m_no_grid_points;
	}

	template <const size_t max_depth>
	size_t HeadlessIndexedNode<max_depth, max_depth>::get_fixed_depth() const
	{
		return m_fixed_depth;
	}

	template<size_t max_depth>
	std::vector<size_t> const& HeadlessIndexedNode<max_depth, max_depth>::get_input_data_gaps() const
	{
		return IndexedNode<max_depth, max_depth>::get_input_data_gaps();
	}

	template<size_t max_depth>
	const double* HeadlessIndexedNode<max_depth, max_depth>::get_input_start(size_t which) const
	{
		return IndexedNode<max_depth, max_depth>::get_input_start()[which];
	}

	template<size_t max_depth>
	double* HeadlessIndexedNode<max_depth, max_depth>::get_output_start()
	{
		return IndexedNode<max_depth, max_depth>::get_output_start();
	}

}

#endif
