#include "HyperChem_like_builder.h"

#include "Atom.h"
#include "Bond.h"
#include "Model.h"
#include "Default_bond.h"
#include "Create.h"
//#include "MM_energy_calculation.h"
//#include "Atom_cartesian_coordinates.h"
//#include "Polak_Ribiere.h"
//#include "Optimization.h"

namespace MM
{

const ID & HyperChem_like_builder::
create_atom( const Element & element )
{
    Atom * new_atom = dynamic_cast <Atom*> (prototype <Atom> ().clone());
    CHECK("Prototype is MM_atom", new_atom !=0 );
    new_atom->set_element( element );
    const ID & id = new_atom->id();
    model_.add_atom( new_atom );

    //notify();
    return id;
}

const ID & HyperChem_like_builder::
set_bond( const ID & atom1_id, const ID & atom2_id, Order order )
{
       Atom & atom1 = model_.atom( atom1_id );
       Atom & atom2 = model_.atom( atom2_id );
//       atom1.add_bound( atom2 );
//       atom2.add_bound( atom1 );

///////////// Idea for future /////////////////
//       Association_of_atoms atoms = factory().make_association_of_atoms();
//       atoms->add_atom( atom1 );
//       atoms->add_atom( atom2 );
//       Bond * new_bond = factory().make_bond( atoms, order );

//       Bond     * new_bond = factory().make_bond( atom1, atom2, order );
//       Bond     * new_bond = new Default_bond( atom1, atom2, order ); 
//       Bond     * new_bond = create<Bond>( atom1, atom2, order );
       Bond     * new_bond = prototype <Bond>(). clone (atom1, atom2, order);

       const ID & id = new_bond->id();

       model_.add_bond( new_bond );

       //notify();
       return id;
}

/*HyperChem_like_builder::
HyperChem_like_builder (Subject & subject, Model & model)
:   
    Controller (subject),
    model_     (model)
{
}//*/
HyperChem_like_builder::
HyperChem_like_builder (Model & model)
:   
    model_     (model)
{
}

void HyperChem_like_builder::
setup_3d_geometry()
{
    /*// Create energy model
    Collection_of< MM_atom > &     atoms = model_.atoms();
    Collection_of< Bond > &     bonds = model_.bonds();
//    Test_MM_energy              energy;

//    MM_calculation              energy_calculation( atoms, bonds, energy );
    MM_energy_calculation       energy_calculation( atoms, bonds );

    // Create optimizer
    Atom_cartesian_coordinates  parameters( atoms );
//    Function                    & function = energy;
    Function                    & function = energy_calculation;
    Polak_Ribiere               optimization_method;

    Optimization                optimization( parameters, function,
                                              optimization_method );
    // Optimize
    optimization.run();//*/
}

}//MM
