#include "Simulation_stage.h"

#include "Simulator_factory.h"
#include "Project.h"
#include "Protocol.h"
#include "Model_proxy.h"
#include "User.h"
#include "System_of_Units.h"

#include <sstream>

namespace MM
{

Simulation_stage::
Simulation_stage (Protocol &protocol, Text const & init)
:
    Protocol_stage_frame (protocol)
{
    using namespace std;
    stringstream str(init.c_str());
    string intention, method, length, T, P, comment_first_word, comment_end;
    str >> intention >> method >> length >> T >> P >> comment_first_word;

//  title =  destination; Protocol_stage_intention; purpose

    simulator_.adopt (Simulator_factory::create (method.c_str()));

    //title_ =            title.c_str();
    length_.from_text (length.c_str());

    temperature_.from_text (T.c_str());
    pressure_.   from_text (P.c_str());

    getline (str, comment_end);
    comment_ = (comment_first_word + comment_end).c_str();
    simulator_().add_comment (comment_);
}

void Simulation_stage::
execute ()
{
    tune  ();
    start ();
}

void Simulation_stage::
stop ()
{
    if (simulator_.was_initialized())
        simulator_().stop ();
}

void Simulation_stage::
tune ()
{
    if (simulator_.was_initialized())//fix
    {
        Simulator & simulator = simulator_();

        simulator.set_model (protocol_.model ());

        if (simulator.support_duration() &&
            option ("Length") != "")
        {
            /*Duration_unit length;
            length.set_current_type ("ps");
            length.set_step_length  (simulator.step_length () * 1e-15);
            Text text = option ("Length");
            length.from_text        (text);
            int steps = int(length.steps ());
            simulator.set_steps     (steps);//*/
            //Duration_unit length = simulator.step_length ();
            Duration_unit length;
            Text text = option ("Length");
            length.from_text        (text);
            text = option ("Step length");
            length.set_step_length_ps  (text.to_double());
            simulator.set_duration (length);//*/
        }

        if (option ("T") != "")
        {
            if (simulator.support_temperature())
            {
                Temperature_unit temperature;
                //temperature.set_current_type ("K");
                temperature.from_text       (option ("T"));

                simulator.setup_velocities (temperature);
                //simulator.set_starting_temperature (temperature);//fix
                simulator.set_desired_temperature (temperature);//fix
            }

            if (simulator.support_thermostat ())
                simulator.set_thermostat (true);
        }
        else
        {
            if (simulator.support_thermostat ())
                simulator.set_thermostat (false);
        }

        if (option ("P") != "")
        {
            if (simulator.support_barostat ())
            {
                Pressure_unit unit;
                unit.from_text       (option ("P"));
				double pressure = System_of_Units::singleton().pressure (unit);
                simulator.set_desired_pressure (pressure);
                simulator.set_barostat (true);
            }
        }
        else
        {
            if (simulator.support_barostat ())
                simulator.set_barostat (false);
        }


        simulator.tune();
    }
}

void Simulation_stage::
start ()
{
    if (simulator_.was_initialized())
    {
        Simulator & simulator = simulator_(); 
        simulator.start();
    }
}

void Simulation_stage::
at_every_iteration (Command *adoptee)
{
    if (simulator_.was_initialized())
        simulator_().after_each_step (adoptee);
}

/*Text Simulation_stage::
title () const
{
    if (title_ == "Initial_conditions" || title_ == "Setup_initial_conditions")
        return "Initial conditions";

    return title_;
}//*/

Text Simulation_stage::
option (Text const & key) const
{
    if      (key == "Method")       return simulator_().title ();
    else if (key == "Length")       return length_.text ();
    else if (key == "Step length")  return length_.step_length_ps ();
    else if (key == "T")            return temperature_.text ();
    else if (key == "P")            return pressure_.text ();
    else if (key == "Comment")      return comment_;
    return "";
}

void Simulation_stage::
set_option (Text const & key, Text const & value)//fix
{
    if (key=="Method")
        simulator_.adopt (Simulator_factory::create (value));

    else if (key=="Length")
        length_.from_text (value);

    else if (key=="Step length")
        length_.set_step_length_ps (value.to_double());

    else if (key=="T")
        temperature_.from_text (value);

    else if (key=="P")
        pressure_.from_text (value);

    else if (key=="Comment")
        comment_ = value;
    else
        to_user().status (Text("'") + key + "' - unknown key.");
}

void Simulation_stage::
get_option (int i, Text & key, Text & value) const//fix
{
    switch (i)
    {
    case 0: key = "T";          value = "298 K";        return;
    case 1: key = "P";          value = "1 atm";        return;
    case 2: key = "Comment";    value = "No comments";  return;
    default:
        FLAW (Text(i) + " is out of range. Options count is " 
                      + option_count() + ".");
    }
}

void Simulation_stage::
update ()
{
    if (simulator_.was_initialized() && 
        Project::singleton().model_count() != 0)
    {
        Simulator & simulator = simulator_();
        simulator.set_model (protocol_.model());
        simulator.update();
    }
}

void Simulation_stage::
edit ()
{
    if (simulator_.was_initialized())
        simulator_().edit_options();
}

}//MM
