namespace dk {
	namespace implem {
		template <uint32_t D>
		inline size_t get_index_from_pos (const Vector<D>& parPos, const Vector<D>& parSize) {
			size_t index = 0;
			for (size_t d = 0; d < D; ++d) {
				size_t pos = static_cast<size_t>(parPos[D - 1 - d]);
				for (size_t p = 0; p < D - 1 - d; ++p) {
					pos *= static_cast<size_t>(parSize[p]);
				}

				index += pos;
			}
			return index;
		}

#if defined(NDEBUG)
		template <>
		inline size_t get_index_from_pos<2> (const Vector<2>& parPos, const Vector<2>& parSize) {
			return parPos.y() * parSize.x() + parPos.x();
		}
#endif

		template <uint32_t D>
		inline Vector<D> buildPastEndCoordinate (const Vector<D>& parFrom, const Vector<D>& parTo) {
			Vector<D> retval;
			for (size_t d = 0; d < D - 1; ++d) {
				retval[d] = parFrom[d];
			}
			retval[D - 1] = parTo[D - 1];
			return retval;
		}

		template <typename T, uint32_t D, typename T1>
		inline const Vector<D>& get_from_from_iterator (const TileIterator<T, D, T1>& parIterator) {
			return parIterator.m_from;
		}
	} //namespace implem

	template <typename T, uint32_t D, typename T1>
	TileIterator<T, D, T1>::TileIterator() :
		m_pos(CoordinateScalarType()),
		m_from(CoordinateScalarType()),
		m_to(CoordinateScalarType()),
		m_subdivareasize(CoordinateScalarType()),
		m_data(nullptr),
		m_subindex(0),
		m_maxsubindex(0)
	{
	}

	template <typename T, uint32_t D, typename T1>
	TileIterator<T, D, T1>::TileIterator (qualif_vector_type* parData, const coords& parFrom, const coords& parTo) :
		m_pos(parFrom),
		m_from(parFrom),
		m_to(parTo),
		m_subdivareasize(parTo - parFrom),
		m_data(parData),
		m_subindex(0),
		m_maxsubindex(0)
	{
		DK_ASSERT(parData);
	}

	template <typename T, uint32_t D, typename T1>
	TileIterator<T, D, T1>::TileIterator (qualif_vector_type* parData, const coords& parFrom, const coords& parTo, const coords& parAreaFrom, const coords& parAreaTo) :
		m_pos(parFrom),
		m_from(parFrom),
		m_to(parTo),
		m_subdivareasize(parAreaTo - parAreaFrom),
		m_data(parData),
		m_subindex(0),
		m_maxsubindex(0)
	{
		DK_ASSERT(parData);
	}

	template <typename T, uint32_t D, typename T1>
	TileIterator<T, D, T1>::TileIterator (qualif_vector_type* parData, const coords& parFrom, const coords& parTo, const coords& parAreaFrom, const coords& parAreaTo, const coords& parSubdiv) :
		m_pos(parFrom),
		m_from(parFrom),
		m_to(parTo),
		m_subdivareasize((parAreaTo - parAreaFrom) * parSubdiv),
		m_data(parData),
		m_subindex(0),
		m_maxsubindex(implem::area(parSubdiv) - 1)
	{
		DK_ASSERT(parData);
	}

	template <typename T, uint32_t D, typename T1>
	void TileIterator<T, D, T1>::increment() {
		if (m_subindex < m_maxsubindex) {
			++m_subindex;
			return;
		}

		m_subindex = 0;
		for (size_t d = 0; d < D - 1; ++d) {
			++m_pos[d];
			if (m_pos[d] >= m_to[d])
				m_pos[d] = m_from[d];
			else
				return;
		}
		++m_pos[D - 1];
	}

	template <typename T, uint32_t D, typename T1>
	void TileIterator<T, D, T1>::decrement() {
		if (m_maxsubindex > 0 and m_subindex == 0) {
			--m_subindex;
		}

		m_subindex = m_maxsubindex;
		for (size_t d = 0; d < D; ++d) {
			if (m_pos[d] > m_from[d]) {
				--m_pos[d];
				return;
			}
			else {
				m_pos[d] = m_to[d];
			}
		}
		++m_pos[D - 1];
	}

	template <typename T, uint32_t D, typename T1>
	void TileIterator<T, D, T1>::advance (size_t /*parAdvance*/) {
		//TODO: implement
	}

	template <typename T, uint32_t D, typename T1>
	ptrdiff_t TileIterator<T, D, T1>::distance_to (const TileIterator& parOther) {
		return std::distance(this->get_current_index(), parOther.get_current_index());
	}

	template <typename T, uint32_t D, typename T1>
	bool TileIterator<T, D, T1>::equal (const TileIterator& parOther) const {
		return m_data == parOther.m_data and m_pos == parOther.m_pos;
	}

	template <typename T, uint32_t D, typename T1>
	T& TileIterator<T, D, T1>::dereference() const {
		const auto index = this->get_current_index();
		DK_ASSERT(m_data);
		DK_ASSERT(index < m_data->size());
		return (*m_data)[index];
	}
} //namespace dk
