#include "Panel_MDynaMix.h"

//#include "Timer.h"
#include "User.h"
#include "Path.h"
#include "Boundary_conditions.h"
#include "Model.h"
#include "Model_kit.h"
#include "MD_simulator.h"
#include "Temperature_unit.h"
#include "Pressure_unit.h"
#include "System_of_Units.h"

#include <fstream>
#include <iomanip>


namespace MM
{   

Panel_MDynaMix::
Panel_MDynaMix ()
:
    Panel ("MDynaMix", "right"),
    ewald_timer_(this)
{
    setupUi (this);
    
    label_Constrain ->hide();
    label_Bind_atoms->hide();

    connect(Auto_Ewald, SIGNAL(toggled(bool)),
            this,       SLOT(auto_ewald(bool)));
    connect(&ewald_timer_, SIGNAL(timeout()),
            this,       SLOT(calc_auto_ewald()));
    
    auto_ewald (true);

    //renew ();
}

void Panel_MDynaMix::
auto_ewald (bool on)
{
    if (on)
    {
        ewald_timer_.start (500);
        Electrostatics_A->setEnabled (false);
        Electrostatics_B->setEnabled (false);
        R_cutoff        ->setEnabled (false);
    }
    else
    {
        ewald_timer_.stop ();
        Electrostatics_A->setEnabled (true);
        Electrostatics_B->setEnabled (true);
        R_cutoff        ->setEnabled (true);
    }
}

void Panel_MDynaMix::
calc_auto_ewald ()
{
    //Model & model = model();
    Boundary_conditions & boundary = model().kit().boundary_conditions ();

    if (boundary.type_name() == "Box")
    {
        double L = boundary.box().a_mod_rectangle();
        
// Nat        Lbox           alpha*R         exp (m/s**2 это шутка)     Rcut
// 800        20             2.9             9.                         10
// 6000       40             2.8             8.5                        12
// 20000      60             2.7             8.                         14
// 50000      80             2.6             7.5                        16

        if (L <= 20)
        {
            Electrostatics_A->setValue (2.9);
            Electrostatics_B->setValue (9.);
            R_cutoff        ->setValue (10);
        }
        else if (L <= 40)
        {
            Electrostatics_A->setValue (2.8);
            Electrostatics_B->setValue (8.5);
            R_cutoff        ->setValue (12);
        }
        else if (L <= 60)
        {
            Electrostatics_A->setValue (2.7);
            Electrostatics_B->setValue (8.);
            R_cutoff        ->setValue (14);
        }
        else
        {
            Electrostatics_A->setValue (2.6);
            Electrostatics_B->setValue (7.5);
            R_cutoff        ->setValue (16);
        }

    }
    else
    {
    }
}

void Panel_MDynaMix::
prepare_input (Text const & filename, M_DynaMix_input const & input)
{
    using namespace std;
    ofstream out (filename.c_str());

    int i,j;
    M_DynaMix_simulator const& simulator = model().kit().MDynaMix ();

    to_user(). status ("Prepare MDynaMix input file");

    out << "# Input file for MDynaMix generated by Ascalaph"           << endl;
    out << "#______________________________________________"           << endl;
    out << ""                                                          << endl;
    out << "#"                                                         << endl;
    out << "# Basic setup"                                             << endl;
    out << "#"                                                         << endl;
    out << ""                                                          << endl;
    out << "Visual  yes"                                               << endl;
    out << ""                                                          << endl;
    out << "Main_filename     " << Main_filename->text().toStdString() << endl;
    out << "Verbose_level     " << Verbose_level->value ()             << endl;
    out << "Path_DB           " << Path::MDynaMix ().c_str() 
                                << Path_DB->text().toStdString()       << endl;
    out << ""                                                          << endl;
    out << "#"                                                         << endl;
    out << "# Restart control"                                         << endl;
    out << "#"                                                         << endl;
    out << ""                                                          << endl;
    out << "Read_restart       " << is_checked (Read_restart);
        if (ASCII->isChecked()) out << " ASCII";
        out << endl;
    
    out << "Dump_restart       "  << Dump_restart->value();
        if (ASCII->isChecked()) out << " ASCII";
        out << endl;

    out << "Change_T           " << is_checked (Change_T)              << endl;
    out << "Change_V           " << is_checked (Change_V)              << endl;
    out << "Check_only         " << is_checked (Check_only)            << endl;
    out << "Zero_CPU           " << is_checked (Zero_CPU)              << endl;
    out << "Zero_vel           " << is_checked (Zero_vel)              << endl;
    out << "Zero_average       " << is_checked (Zero_average)          << endl;
    out << ""                                                          << endl;
    out << "#"                                                         << endl;
    out << "# System"                                                  << endl;
    out << "#"                                                         << endl;
    out << ""                                                          << endl;
    out << "Molecule_types         " << input.molecular_types_.size()  << endl;
    for (i=0;  i<input.molecular_types_.size();  ++i)
    {
        out << input.molecular_types_[i].name_.c_str();
        for (j=input.molecular_types_[i].name_.length();  j<22;  ++j)
            out << " ";
        out << " ";
        out << input.molecular_types_[i].number_of_molecules_          << endl;
    }
    out << ""                                                          << endl;
    
    if (input.model().kit().boundary_conditions().type_name() != "Vacuum")
    {
        out << "PBC                ";
        if (PBC->currentText () == "rectangular")           out << "rect";
        if (PBC->currentText () == "hexagonal")             out << "hexa";
        if (PBC->currentText () == "truncated octahedron")  out << "octa";
        out << endl;
    }

    if (model().kit().boundary_conditions().type_name() == "Box") //fix
    {
        out << "Box                " 
            << input.model().kit().boundary_conditions().box().a_mod_rectangle() << "  "
            << input.model().kit().boundary_conditions().box().b_mod_rectangle() << "  "
            << input.model().kit().boundary_conditions().box().c_mod_rectangle() << endl;
    }
    else
    {
        out << "Density                " << Density->value ()          << endl;
    }

    if (El_field->isChecked())
        out << "El_field           " 
            << El_field_ampl->value() << "  "
            << El_field_freq->value() << endl;

    out << ""                                                          << endl;
    out << "#"                                                         << endl;
    out << "# Ensemble"                                                << endl;
    out << "#"                                                         << endl;
    out << ""                                                          << endl;

    if (simulator.has_thermostat ())
    {
        if (Nose_thermostat->isChecked())
        {
            out << "Nose_thermostat        " 
                << simulator.desired_temperature ().K()  << "  "
                << Relaxation_time_T->value()                          << endl;
        }
        else if (Velocity_scaling->isChecked())
        {
            out << "Velocity_scaling   " 
                << simulator.desired_temperature ().K()  << "  "
                << Admissible_deviation->value()                       << endl;
        }
        else
            FLAW ("Unknown thermostat.");

        out << "Separate_thermostating " 
            << is_checked (Separate_thermostating)                     << endl;
    }

    out << "COM_check              " << is_checked (COM_check) << "  "
        << COM_check_num->value()                                      << endl;

    if (simulator.has_barostat ())
    {
        Pressure_unit unit;
        System_of_Units::singleton().
            set_pressure (unit, simulator.desired_pressure ());

        out << "Barostate_NH           "
            << unit.atm()  << "  "
            << Relaxation_time_P->value ()                             << endl;
    
        out << "Barostate_anisotropic  " 
            << Barostate_anisotropic->currentText().toStdString()      << endl;
    }

    out << ""                                                          << endl;
    out << "#"                                                         << endl;
    out << "# Molecular Dynamics"                                      << endl;
    out << "#"                                                         << endl;
    out << ""                                                          << endl;

    out << "Time_step             " 
        << simulator.duration().step_length_ps() * 1000                << endl;
    out << "Number_steps          " << (int)simulator.duration().steps()    << endl;
    out << "Double_timestep       " << Double_timestep->value()        << endl;
    out << "R_cutoff              " << R_cutoff->value()               << endl;
    out << "R_short               " << R_short->value()                << endl;
    out << "Neighbour_list        " << Neighbour_list->value()         << endl;

    out << "Electrostatics        ";
    if (Ewald->isChecked())
    {
        out << "Ewald  " 
            << Electrostatics_A->value() << " " << Electrostatics_B->value();
    }
    else if (Reaction_field->isChecked())
    {
        out << "RF  " 
            << Dielectric_permittivity->value() << " " 
            << Debye_screening_length->value();
    }
    else if (Cutoff->isChecked())
    {
        out << "Cutoff" ;
    }
    else
        FLAW("");
    out << endl;

    if (Cut_large_forces->isChecked())
    {
        out << "Cut_forces             " 
            << Cut_large_forces_value->value()                         << endl;
    }

    if (Combination_rule->currentText () == "geometrical average")
        out << "Combination_rule        Sigma_geom" << endl;
    else if (Combination_rule->currentText () == "Kong ")
        out << "Combination_rule        Kong " << endl;

    out << ""                                                          << endl;
    out << "#"                                                         << endl;
    out << "# Startup"                                                 << endl;
    out << "#"                                                         << endl;
    out << ""                                                          << endl;

    if (Gather->isChecked())
        out << "Gather"                                                << endl;

    out << ""                                                          << endl;
    out << "#"                                                         << endl;
    out << "# Properties"                                              << endl;
    out << "#"                                                         << endl;
    out << ""                                                          << endl;

    out << "Output                " << Output->value()                 << endl;
    out << "Serie_average         " << Serie_average->value()          << endl;
    out << "Average_from          " << Average_from->value()           << endl;
    out << "Average_internal      " << is_checked (Average_internal)   << endl;
    out << "Dump_XMOL             " << is_checked (Dump_XMOL)          << endl;

    out << "Trajectory            ";
    switch (Trajectory->currentIndex())
    {
    case 0: out << "bincrd"; break;
    case 1: out << "binvel"; break;
    case 2: out << "asccrd"; break;
    case 3: out << "ascvel"; break;
    default: FLAW ("");
    }
    out << " " << Step->value() 
        << " " << Configurations->value() 
        << " all" << endl;

    out << "Bond_list             " << is_checked (Bond_list)          << endl;

    out << ""          << endl;

    out << "end" << endl;
    to_user(). status ("Input file prepared");
}

}//MM
