#ifndef PULL_ON_BUILDER_H
#define PULL_ON_BUILDER_H

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

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

#include "Atom.h"
#include "Bond.h"
#include "Molecule.h"
#include "Residue.h"
#include "Joint.h"
#include "Model.h"
#include "Flaw.h"
#include "User.h"
#include "Create.h"

namespace MM
{

class Pull_on_builder : public Builder, protected DbC
{
    mutable int             atom_n_;
    mutable int             mol_n_;
    mutable int             res_n_;
    mutable int             joint_n_;
   // Molecule                stub_molecule_;

public:
    Pull_on_builder () : atom_n_(0), mol_n_(0), res_n_(0) { }

    virtual Atom &          new_atom (Model & model, Element element) const 
    {
        Atom * result=0;

        if (model.atom_count () <= atom_n_)
            throw Text ("Pull on more atoms "
                        "than number of atoms in model.");

        if (model.kit().has_ordered_atoms())
            result = &model.kit().ordered_atoms().atom(atom_n_);
        else
            result = &model.atom (atom_n_);

        if (result->element() != element)
            throw Text ("Pull on diffetent elements.");

        ++atom_n_;

        return *result;
    }

    virtual Bond &          new_bond (Model &       model,
                                      Atom &        atom1,
                                      Atom &        atom2,
                                      Order const & order) const
    {
        //fix to model

        Bond * bond = 0;

        for (int i=0;  i<atom1.bound_count ();  ++i)
        {
            if (&atom1.bound (i) == &atom2)
            {
                if (bond != 0)
                {
                    Text text;
                    text += "Atoms ";
                    text += atom1.kit().number();
                    text += " and ";
                    text += atom2.kit().number();
                    text += " were bound more than one time.";
                    to_user ().error (text);      //fix to log?
                }
                bond = &atom1.bond (i);
            }
        }

        if (bond == 0)
        {
            Bond * bond = prototype <Bond> (). clone (atom1, atom2, order);
            model.add_bond (bond);
        }
        else
        {
            bond->set_order (order);
        }

        return *bond;
    }

    virtual Distance_restraint & new_distance_restraint
        (Model & , Atom & , Atom & , Text const & ,
         double       /*R_eqv*/,
         double       /*K_r*/) const
    {
        FIX;
        return nil <Distance_restraint> ();
    }

    virtual Molecule &      new_molecule (Model & model) const
    {
        //fix to model         No!!! here! 
        Molecule * molecule =0;

        if (model.molecule_count () > mol_n_)
        {
            molecule = &model.molecule (mol_n_);
        }
        else
        {
            molecule = prototype <Molecule> (). clone();
            model.add_molecule (molecule);
        }
        ++mol_n_;
        return *molecule;
    }

    virtual Residue  &      new_residue  (Model & model) const
    {
        Residue *result = 0;

        if (model.residue_count () > res_n_)
            result = &model.residue (res_n_);
        else
        {
            result = prototype <Residue> (). clone ();
            model.add_residue (result);
        }

        ++res_n_;
        return *result;
    }

    virtual Joint    &      new_joint  (Model & model, 
                                        Atom & stub_atom,
                                        Atom & terminal_atom,
                                        Atom & directional_atom) const
    {
        Joint *result = 0;

        if (model.joint_count () > joint_n_)
            result = &model.joint (joint_n_);
        else
        {
            result = prototype <Joint> (). 
                clone (stub_atom, terminal_atom, directional_atom);

            model.add_joint (result);
        }

        ++joint_n_;
        return *result;
    }
};

}//MM

#endif //PULL_ON_BUILDER_H
