#ifndef DEFAULT_BUILDER_H
#define DEFAULT_BUILDER_H

#ifndef BUILDER_H
#include "Builder.h"
#endif

#ifndef DBC_H
#include "DbC.h"
#endif

#include "Atom.h"
#include "Bond.h"
#include "Model.h"
#include "Model_kit.h"
#include "Molecule.h"
#include "Residue.h"
#include "Joint.h"
#include "Distance_restraint.h"
#include "Create.h"

namespace MM
{

class Default_builder : public Builder, protected DbC
{
public:
    virtual Atom &          new_atom (Model & model, Element element) const
    {
        //fix dynamic_cast
        Atom * new_atom =
            dynamic_cast <Atom*> (model.atom_prototype ().clone (element));
        CHECK("Prototype is MM_atom", new_atom !=0 );

        //new_atom->set_element (element);
        model.add_atom (new_atom);
        return *new_atom;
    }

    virtual Bond &          new_bond (Model &       model,
                                      Atom &        atom1,
                                      Atom &        atom2,
                                      Order const & order) const
    {
        //fix to model or to Default_bond
        //Bond * bond = prototype <Bond>(). clone (atom1, atom2, order);
        Bond * bond = model.bond_prototype (). clone (atom1, atom2, order);
        model.add_bond (bond);
        return *bond;
    }

    virtual Distance_restraint &
    new_distance_restraint (Model & model,
                            Atom & atom1,
                            Atom & atom2,
                            Text const & type,
                            double       R_eqv,
                            double       K_r) const
    {
        Distance_restraint * restraint = prototype <Distance_restraint> ()
            .clone (atom1, atom2, type, R_eqv, K_r);

        model.kit().adopt_interaction (restraint);
        return *restraint;
    }

    virtual Molecule &      new_molecule (Model & model) const
    {
        //fix to model
        Molecule * molecule = prototype <Molecule>(). clone();
        model.add_molecule (molecule);
        return *molecule;
    }

    virtual Residue  &      new_residue  (Model & model) const
    {
        Residue *residue = prototype <Residue>(). clone();
        model.add_residue (residue);
        return *residue;
    }

    virtual Joint    &      new_joint (Model & model, 
                                        Atom & stub_atom,
                                        Atom & terminal_atom,
                                        Atom & directional_atom) const
    {
        Joint *joint = prototype <Joint>(). 
            clone (stub_atom, terminal_atom, directional_atom);

        model.add_joint (joint);
        return *joint;
    }
};

}//MM

#endif //DEFAULT_BUILDER_H
