#ifndef PHYCPP_TREE_TAXA_HPP
#define PHYCPP_TREE_TAXA_HPP

#include "taxon.hpp"
#include "../utility/stringalgorithm.hpp"

namespace PhyCpp {

template <typename, typename, typename>
class BasicTree;

namespace Detail {
	template <typename TaxonT>
	class TreeBase;
}

template <typename T>
class BasicTaxa : private UniquelyLabelledObjectManager<std::string, BasicTaxon<T> >,
                  private SimpleLabelledObject<std::string> {

	friend class Detail::TreeBase<T>;
	template <typename, typename, typename> friend class BasicTree;

public:

	typedef typename UniquelyLabelledObjectManager<std::string, BasicTaxon<T> >::const_iterator const_iterator;
	typedef typename UniquelyLabelledObjectManager<std::string, BasicTaxon<T> >::const_iterator iterator;

	inline const_iterator begin() const {
		return UniquelyLabelledObjectManager<std::string, BasicTaxon<T> >::begin();
	}

	inline const_iterator end() const {
		return UniquelyLabelledObjectManager<std::string, BasicTaxon<T> >::end();
	}

	inline iterator begin()  {
		return UniquelyLabelledObjectManager<std::string, BasicTaxon<T> >::begin();
	}

	inline iterator end()  {
		return UniquelyLabelledObjectManager<std::string, BasicTaxon<T> >::end();
	}

	inline BasicTaxa()
	: UniquelyLabelledObjectManager<std::string, BasicTaxon<T> >(),
	  SimpleLabelledObject<std::string>() {
	}

	inline ~BasicTaxa() {
		size_t count = trees.size();
		for (size_t i = 0; i < count; ++i) {
			unlinkTree(trees[0]);
		}
	}

	inline unsigned int size() const {
		return UniquelyLabelledObjectManager<std::string, BasicTaxon<T> >::size();
	}

	inline BasicTaxon<T> * find(const std::string & label) {
		return UniquelyLabelledObjectManager<std::string, BasicTaxon<T> >::find(label);
	}

	inline const BasicTaxon<T> * find(const std::string & label) const {
		return UniquelyLabelledObjectManager<std::string, BasicTaxon<T> >::find(label);
	}

	inline BasicTaxon<T> * insert(const std::string & label) {
		if (isWhiteSpaceOnly(label))
			return 0;
		return UniquelyLabelledObjectManager<std::string, BasicTaxon<T> >::insert(label);
	}

	inline void setLabel(const std::string & label) {
		SimpleLabelledObject<std::string>::setLabel(label);
	}

	inline const std::string & label() const {
		return SimpleLabelledObject<std::string>::label();
	}

	inline unsigned int treeCount() const {
		return trees.size();
	}

	inline Detail::TreeBase<T> * tree(unsigned int i) const {
		return trees[i];
	}

	inline void linkTree(Detail::TreeBase<T> * t) {
		t->linkTaxa(this);
	}
	inline void unlinkTree(Detail::TreeBase<T> * t) {
		t->unlinkTaxa();
	}

	inline bool isLinkedTo(const Detail::TreeBase<T> * t) const {
		return (std::find(trees.begin(), trees.end(), const_cast<Detail::TreeBase<T>*>(t)) != trees.end());
	}

private:

	std::vector<Detail::TreeBase<T>*> trees;
};

}

#endif // PHYCPP_TREE_TAXA_HPP
