#include "Model_kit.h"

#include "Cleaner.h"
#include "User.h"
#include "Atom_kit.h"
#include "Model_view_composite.h"
#include "Model.h"
#include "Rigid_body_impl.h"
#include "Model_as_md_subject.h"
#include "No_interaction.h"
#include "Box_impl.h"
#include "Molecular_sequence_impl.h"
#include "Common_interactions.h"
#include "Rough_hydrophobic_interactions.h"
#include "MD_simulator_impl.h"

#ifdef M_DYNAMIX
#include "M_DynaMix_simulator.h"
#endif

#include "Create.h"

#ifdef MM_WIN32
#pragma warning (disable : 4355)
#endif

namespace MM
{

Model_kit::
Model_kit (Model &model)
:
	file_name_				("New.mlm"),
    model_                  (model),
    replica_                (*this),
    file_                   (model),
    visual_                 (model),
    //interaction_            (new No_interaction),
    //interaction_            (Common_interactions::create (model, model, Force_field::singleton())),
    interaction_            (new Composite_interaction),
    selector_               (model),
    MD_                     (new MD_simulator_impl(model)),
    MC_                     (new MD_simulator_impl(model)),
#ifdef M_DYNAMIX
    MDynaMix_               (new M_DynaMix_simulator),
#endif
    current_simulator_      (&MD_()),
    boundary_conditions_    (*this),
    rigid_body_             (new Rigid_body_impl),
    lock_count_             (0)
{
    //view_.adopt (new Model_view_composite());

    //interaction_().adopt (Common_interactions::
    //    create (model, model, Force_field::singleton()));

    interaction_().adopt_common (Common_interactions::
        //create (model, Force_field::singleton()));
        create (model/*, force_field_()*/));

    Monte_Carlo().set_method ("HMC");
    //Monte_Carlo().set_model (model_);

    //MD_().set_model (model_);
#ifdef M_DYNAMIX
    MDynaMix_().set_model (model_);
#endif
}

Model_kit::
Model_kit (Prototype &, Model & model)
:
    model_(model),
    replica_            (*this),
    file_               (model),
    visual_             (model),
    selector_           (model),
    boundary_conditions_(*this)//,
    //crystal_builder_(model)
{
}

void Model_kit::set_alias         (Text const & v)  {alias_       = v;}
void Model_kit::set_short_alias   (Text const & v)  {short_alias_ = v;}
//void Model_kit::set_model_name    (Text const & v)  {model_name_  = v;}
void Model_kit::set_comment_line  (Text const & v)  {comment_line_= v;}

void Model_kit::
strip (bool silent)
{
    Cleaner cleaner (model_);
    const Text zero_type = "0";
    int i;

    for (i=0;  i<model_.atom_count();  ++i)
    {
        Atom & atom = model_.atom (i);

        if (atom.kit().has_mm_type() 
            && zero_type == atom.kit().mm_type_c_str())
            cleaner.add (atom);
    }

    for (i=0;  i<model_.bond_count();  ++i)
    {
        Bond & bond = model_.bond (i);

        if (bond.order() == Order::Dummy) 
            cleaner.add (bond);
    }

    if (cleaner.is_empty() && !silent)
        to_user().info ("There is nothing to strip.");
}

void Model_kit::
set_force_field (Text const & v)
{
    replica().set_force_field (v);
}


void Model_kit::
add_visual (Model_view *adoptee)
{
    //REQUIRE ("",  !has_view());
    //view_.adopt (adoptee);
    //ENSURE  ("",  has_view());

    //dynamic_cast<Model_view_composite&>(view_()).adopt (adoptee);
//    set_ownership (*adoptee, *this);
    visual_.adopt (adoptee);
}

/*void Model_kit::
remove_view()
{
    REQUIRE ("",  has_view());
    delete view_.orphan();
    ENSURE  ("",  !has_view());
}//*/

Crystal_builder & Model_kit::
crystal_builder ()
{
    if (crystal_builder_.is_not_valid())
        crystal_builder_.adopt (prototype <Crystal_builder> (). clone(model()));
    return crystal_builder_();
}

Sequence_editor & Model_kit::
sequence_editor ()
{
    if (sequence_editor_.is_not_valid())
        sequence_editor_.adopt (new Sequence_editor (model()));
    return sequence_editor_();
}

Add_builder & Model_kit::
add_builder ()
{
    if (add_builder_.is_not_valid())
        add_builder_.adopt (prototype <Add_builder>().clone (model()));
    return add_builder_();
}

void Model_kit::
set_MDynaMix_file (Text const& formula, Text const& path)
{
    MDynaMix_file_[formula] = path;
}

Text Model_kit::
MDynaMix_file (Text const& formula)
{
    return MDynaMix_file_[formula];
}

Box & Model_kit::
crystal_cell ()
{
    if (!has_crystal_cell ())
        crystal_cell_.adopt (new Box_impl());
    return crystal_cell_();
}

Box const & Model_kit::
crystal_cell () const
{
    if (!has_crystal_cell ())
        crystal_cell_.adopt (new Box_impl());
    return crystal_cell_();
}

void Model_kit::
erase (Model_view &adoptee)
{
    delete visual().orphan (&adoptee);
    if (visual().count() == 0)
        model().erase();
}

MD_subject * Model_kit::
create_md_interface ()
{
    //return new Model_as_md_subject (model_, interaction());
    return new Model_as_md_subject (model_);
}


Arbitrary_atom_group & Model_kit::
ordered_atoms ()
{
    if(!has_ordered_atoms())
        ordered_atoms_.adopt (new Arbitrary_atom_group);
    return ordered_atoms_();
}

}//MM
