// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//

BALL_INLINE
void Bond::clear_()
{
	first_ = BALL_BOND_DEFAULT_FIRST_ATOM;
	second_ = BALL_BOND_DEFAULT_SECOND_ATOM;
	name_ = BALL_BOND_DEFAULT_NAME;
	bond_order_ = BALL_BOND_DEFAULT_ORDER;
	bond_type_ = BALL_BOND_DEFAULT_TYPE;
}

BALL_INLINE
void Bond::clear()
{
	PropertyManager::clear();
	
	arrangeBonds_();
	clear_();
}

BALL_INLINE
void Bond::destroy()
{
	PropertyManager::destroy();
	arrangeBonds_();
	clear_();
}

BALL_INLINE
void Bond::finalize()
{
	if (*first_ > *second_)
	{
		Atom* tmp = first_;
		first_ = second_;
		second_ = tmp;
	}
}

BALL_INLINE
void Bond::setFirstAtom(Atom* atom)
{
	first_ = atom;
}

BALL_INLINE	 
const Atom* Bond::getFirstAtom() const
{
	return first_;
}

BALL_INLINE	 
Atom* Bond::getFirstAtom()
{
	return first_;
}

BALL_INLINE	 
Atom* Bond::getPartner(const Atom& atom) const
{
	Atom* partner = 0;
	if (&atom == first_)
	{
		partner = second_;
	} 
	else 
	{
		if (&atom == second_)
		{
			partner = first_;
		}
	}		
	return partner;
}

BALL_INLINE
void Bond::setSecondAtom(Atom* atom)
{
	second_ = atom;
}

BALL_INLINE	 
const Atom* Bond::getSecondAtom() const
{
	return second_;
}

BALL_INLINE	 
Atom* Bond::getSecondAtom()
{
	return second_;
}

BALL_INLINE
void Bond::setName(const String& name)
{
	name_ = name;
}

BALL_INLINE
const String& Bond::getName() const
{
	return name_;
}

BALL_INLINE
void Bond::setOrder(Bond::Order bond_order)
{
	bond_order_ = bond_order;
}
	
BALL_INLINE	
Bond::Order Bond::getOrder() const
{
	return bond_order_;
}
	
BALL_INLINE
bool Bond::isAromatic() const
{
	return (hasProperty(IS_AROMATIC) || (bond_order_ == ORDER__AROMATIC));
}

BALL_INLINE
void Bond::setType(Type bond_type)
{
	bond_type_ = bond_type;
}
	
BALL_INLINE
Bond::Type Bond::getType() const
{
	return bond_type_;
}

BALL_INLINE
Real Bond::getLength() const
{
	if (first_ == 0 || second_ == 0)
	{
		throw NotBound(__FILE__, __LINE__);
	}
	
	return first_->getDistance(*second_);
}

BALL_INLINE
const Atom* Bond::getBoundAtom(const Atom& atom) const
{
	if (first_ == &atom)
	{
		return second_;
	}
	else
	{
		if (second_ == &atom)
		{
			return first_;
		}
	}

	return 0;
}

BALL_INLINE
Atom* Bond::getBoundAtom(const Atom& atom)
{
	if (first_ == &atom)
	{
		return second_;
	}
	else
	{
		if (second_ == &atom)
		{
			return first_;
		}
	}

	return 0;
}

BALL_INLINE
bool Bond::isBondOf(const Atom& atom) const
{
	return atom.hasBond(*this);
}

BALL_INLINE
bool Bond::isBound() const
{
	return (first_ != 0);
}

BALL_INLINE
bool Bond::isInterBond() const
{
	// the two atoms have to be inside the same (non-NULL) composite
	return (isBound() && (first_->Composite::getRoot() != second_->Composite::getRoot())
					&& (&first_->Composite::getRoot() != first_));
}

BALL_INLINE
bool Bond::isInterBondOf(const AtomContainer& atom_container) const
{
	if (isBound())
	{
		bool first_atom_is_descendant  = first_->Composite::isDescendantOf(atom_container);
		bool second_atom_is_descendant = second_->Composite::isDescendantOf(atom_container);

		return (( first_atom_is_descendant && !second_atom_is_descendant) ||
						(!first_atom_is_descendant &&  second_atom_is_descendant));
	} 

	return false;
}

BALL_INLINE
bool Bond::isIntraBond() const
{	
	// the two atoms have to be inside two different (non-NULL) composite
	return (isBound() && (first_->Composite::getRoot() == second_->Composite::getRoot()) 
					&& (&first_->Composite::getRoot() != first_) && (&second_->Composite::getRoot() != second_));
}

BALL_INLINE
bool Bond::isIntraBondOf(const AtomContainer &atom_container) const
{
	return (isBound() &&  first_->Composite::isDescendantOf(atom_container)
										&& second_->Composite::isDescendantOf(atom_container));
}

BALL_INLINE
bool Bond::isValid () const
{
	return (PropertyManager::isValid()
								&& first_  != 0
								&& second_ != 0
								&& first_  != second_
								&& first_->hasBond(*this)
								&& second_->hasBond(*this));
}

BALL_INLINE
bool Bond::operator == (const Bond& bond) const
{
	return (this == &bond);
}

BALL_INLINE
bool Bond::operator != (const Bond& bond) const
{
	return (this != &bond);
}

