#ifndef PHYCPP_TREE_EDGE_HPP
#define PHYCPP_TREE_EDGE_HPP

#include "../utility/valuedobject.hpp"
#include "iterator.hpp"

namespace PhyCpp {

template <typename TaxonT, typename NodeT, typename EdgeT>
class BasicNode;

template <typename TaxonT, typename NodeT, typename EdgeT>
class BasicEdge : public ValuedObject<EdgeT> {

	friend class BasicNode<TaxonT, NodeT, EdgeT>;

public:

	typedef EdgeT value_type;

	typedef BasicTree<TaxonT, NodeT, EdgeT> Tree;
	typedef BasicNode<TaxonT, NodeT, EdgeT> Node;

	typedef Detail::BasicTreeIterator<BasicEdge, Node, false, false> iterator;
	typedef Detail::BasicTreeIterator<BasicEdge, Node, true, false> const_iterator;
	typedef Detail::BasicTreeIterator<BasicEdge, Node, false, true> reverse_iterator;
	typedef Detail::BasicTreeIterator<BasicEdge, Node, true, true> const_reverse_iterator;

	/** @name Destruction */
	//@{
	inline ~BasicEdge() {}
	//@}

	/** @name Topology access */
	//@{
	inline double length() const {return len;}

	inline Node * startNode() {return nodeEnd->parent();}
	inline const Node * startNode() const {return nodeEnd->parent();}

	inline Node * endNode() {return nodeEnd;}
	inline const Node * endNode() const {return nodeEnd;}

	inline Tree * tree() {return nodeEnd->tree();}
	inline const Tree * tree() const {return nodeEnd->tree();}
	//@}

	/** @name Topology modification */
	//@{
	inline void setLength(double d) {len = d;}
	Node * insertNode(double location);
	//@}

private:

	inline BasicEdge(Node * terminus, double length)
	: ValuedObject<EdgeT>(),
	  len(length),
	  nodeEnd(terminus) {}

	double len;
	Node * nodeEnd;
};

}

template <typename TaxonT, typename NodeT, typename EdgeT>
PhyCpp::BasicNode<TaxonT, NodeT, EdgeT> * PhyCpp::BasicEdge<TaxonT, NodeT, EdgeT>::insertNode(double location) {

	if (location <= len) {
		double len1 = (location >= 0 && length() >= 0) ? location : -1;
		double len2 = (len1 >= 0) ? length() - len1 : length();
		setLength(len2);
		Node * leftsib = endNode()->leftSibling();
		Node * rightsib = endNode()->rightsibling;
		Node * n = new Node(tree(), len1);
		n->parentnode = startNode();
		if (n->parentnode != 0) {
			if (n->parentnode->leftchild == endNode()) {
				n->parentnode->leftchild = n;
				Node::setPreorderRelation(n->parentnode, n);
			} else {
				leftsib->rightsibling = n;
				n->rightsibling = rightsib;
				Node::setPreorderRelation(leftsib->rightSubtreeExtent(), n);
			}
		} else {
			Node::setPreorderRelation(0, n);
		}
		Node::setPreorderRelation(n, endNode());
		endNode()->parentnode = n;
		n->leftchild = endNode();
		n->rightsibling = rightsib;
		endNode()->rightsibling = 0;
		return n;
	}
	return 0;
}

#endif // PHYCPP_TREE_EDGE_HPP
