#ifndef DATADICTIONARYITERATOR_H__
#define DATADICTIONARYITERATOR_H__

#include "maxon/datatype.h"

namespace maxon
{

/// @addtogroup DATATYPE
/// @{

//----------------------------------------------------------------------------------------
/// DataDictionaryIteratorInterface is used internally by DataDictionary::Iterator.
/// It should not be used directly.
//----------------------------------------------------------------------------------------
class DataDictionaryIteratorInterface
{
	MAXON_INTERFACE_NONVIRTUAL(DataDictionaryIteratorInterface, MAXON_REFERENCE_NONE, "net.maxon.interface.datadictionaryiterator");

public:
	MAXON_METHOD void Destruct();

	MAXON_METHOD void MoveConstruct(DataDictionaryIteratorInterface* src);

	MAXON_METHOD Bool HasValue() const;

	MAXON_METHOD Bool IsEqual(const DataDictionaryIteratorInterface* other) const;

	MAXON_METHOD void MoveToNext();

	//----------------------------------------------------------------------------------------
	/// @param[out] res								DataDictionary to compare for equality.
	//----------------------------------------------------------------------------------------
	MAXON_METHOD void GetKeyAndData(Tuple<const Data&, const Data&>& res) const;

//	MAXON_METHOD HashInt GetHashCode() const;
};


// include autogenerated headerfile here
#include "datadictionaryiterator1.hxx"

class DataDictionaryInterface;
class DataDictionaryObjectInterface;

//----------------------------------------------------------------------------------------
/// Iterator to iterate through all elements of a DataDictionary
//----------------------------------------------------------------------------------------
class DataDictionaryIterator : public ForEachIterator<DataDictionaryIterator>
{
public:
	DataDictionaryIterator() : _hasIterator(false), _pair(NullValue<const Data&>(), NullValue<const Data&>())
	{
	}

	inline DataDictionaryIterator(const DataDictionaryInterface* dict, Bool end);

	inline DataDictionaryIterator(const DataDictionaryObjectInterface* dict, Bool end);

	DataDictionaryIterator(DataDictionaryIterator&& src) : _hasIterator(src._hasIterator), _pair(std::move(src._pair))
	{
		if (src._hasIterator)
			GetIterator()->MoveConstruct(src.GetIterator());
	}

	MAXON_OPERATOR_MOVE_ASSIGNMENT(DataDictionaryIterator);

	~DataDictionaryIterator()
	{
		if (_hasIterator)
			GetIterator()->Destruct();
	}

	DataDictionaryIterator& operator ++()
	{
		GetIterator()->MoveToNext();
		if (GetIterator()->HasValue())
			GetIterator()->GetKeyAndData(_pair);
		return *this;
	}

	void operator ++(int)
	{
		this->operator ++();
	}

	Bool operator ==(const DataDictionaryIterator& other) const
	{
		return _hasIterator ? other._hasIterator && GetIterator()->IsEqual(other.GetIterator()) : !other._hasIterator;
	}

	Bool operator !=(const DataDictionaryIterator& other) const
	{
		return !this->operator ==(other);
	}

	explicit operator Bool() const
	{
		return Bool(_hasIterator && GetIterator()->HasValue());
	}

	const Tuple<const Data&, const Data&>* operator ->() const
	{
		return &_pair;
	}

	const Tuple<const Data&, const Data&>& operator *() const
	{
		return _pair;
	}

	//----------------------------------------------------------------------------------------
	/// returns the id of the current element
	//----------------------------------------------------------------------------------------
	const Data& GetKey() const
	{
		return _pair.GetKey();
	}

	//----------------------------------------------------------------------------------------
	/// returns the data of the current element. this is a template. e.g. write Get<Int32>() if you expect Int32 data.
	//----------------------------------------------------------------------------------------
	template <typename T> Result<typename std::conditional<STD_IS_REPLACEMENT(void, T), void, typename ByValueParam<T>::type>::type> Get() const
	{
		return _pair.GetValue().template Get<T>();
	}

	//----------------------------------------------------------------------------------------
	/// returns the Data of the current element.
	//----------------------------------------------------------------------------------------
	const Data& Get() const
	{
		return _pair.GetValue();
	}

	using IteratorMemory = Int[10];

private:
	DataDictionaryIteratorInterface* GetIterator()
	{
		DebugAssert(_hasIterator);
		return (DataDictionaryIteratorInterface*) _iteratorMemory;
	}

	const DataDictionaryIteratorInterface* GetIterator() const
	{
		DebugAssert(_hasIterator);
		return (const DataDictionaryIteratorInterface*) _iteratorMemory;
	}

	IteratorMemory _iteratorMemory;
	const Bool _hasIterator;
	Tuple<const Data&, const Data&> _pair;
};


// include autogenerated headerfile here
#include "datadictionaryiterator2.hxx"

/// @}

} // namespace maxon

#endif // DATADICTIONARYITERATOR_H__
