#pragma once

#include <vector>
#include <memory>
#include "ConnectedObject.h"

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// General way to store a list of adjacently connected (by reference) objects
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

template <typename T>
class ConsecutiveObjects
{

	std::vector<std::unique_ptr<ConnectedObject<T>>> m_objects;

protected:

	ConsecutiveObjects(size_t number_of_objects);

public:

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Call this after initial array is ready to connect the objects
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	void connect();

	const T* operator[] (size_t i) const;

	size_t size();

	T* get(size_t i);

	// transfer owenship of the pointer provided to within
	void claim(size_t i, T* obj);
	void claim(size_t i, std::unique_ptr<T> obj);
};

template <typename T>
ConsecutiveObjects<T>::ConsecutiveObjects(size_t number_of_objects)
{
	m_objects.resize(number_of_objects);
}

template<typename T>
void ConsecutiveObjects<T>::connect()
{
	m_objects[0]->connect(nullptr, m_objects[1].get());

	for (size_t i = 1; i < m_objects.size() - 1; ++i)
		m_objects[i]->connect(m_objects[i - 1].get(), m_objects[i + 1].get());

	m_objects[m_objects.size() - 1]->connect(m_objects[m_objects.size() - 2].get(), nullptr);
}

template<typename T>
const T* ConsecutiveObjects<T>::operator[](size_t i) const
{
	return static_cast<const T*>(m_objects[i].get());
}

template<typename T>
size_t ConsecutiveObjects<T>::size()
{
	return m_objects.size();
}

template <typename T>
T* ConsecutiveObjects<T>::get(size_t i)
{
	return static_cast<T*>(m_objects[i].get());
}

template<typename T>
void ConsecutiveObjects<T>::claim(size_t i, T* obj)
{
	claim(i, std::move(std::unique_ptr<T>(obj)));
}

template<typename T>
void ConsecutiveObjects<T>::claim(size_t i, std::unique_ptr<T> obj)
{
	m_objects[i] = std::move(obj);
}
