#include "M_DynaMix_pipe_process.h"

#include "Path.h"
#include "Atom.h"
#include "Atom_group.h"
#include "M_DynaMix_simulator.h"
#include "User.h"
#include "Text.h"
#include "Collect_potential_from_mDynaMix.h"
#include "Collect_temperature_from_mDynaMix.h"
#include "Collect_pressure_from_mDynaMix.h"
#include "Collect_density_from_mDynaMix.h"

#include <errno.h>

#include <fstream>
#include <sstream>

#include <qapplication.h>//fix remove (to event)
#include <qeventloop.h>

namespace MM
{

M_DynaMix_pipe_process::
M_DynaMix_pipe_process (Interface_for_M_DynaMix_process & simulator)
:
    M_DynaMix_process (simulator),
    output_(0)
{
}

void M_DynaMix_pipe_process::
start (Atom_group * ordered_atoms)
{
    to_user(). status ("Launch M.DynaMix.");

    bool success = init_process ();
    if (!success)
        return;

    //try
    //{
        read_mDynaMix_output (ordered_atoms);
    //}
    //catch(...)
    //{
    //    to_user().error ("m.DynaMix problem.");
    //}

    close_process ();
}

bool M_DynaMix_pipe_process::
init_process ()
{
    #ifdef MM_WIN32
    Text command = Path::MDynaMix();
    command += "MDynaMix.exe < ";
    command += Path::MDynaMix();
    command += "MDynaMix.input";

    output_ = _popen (command.c_str(), "rt");
    #endif
    #ifdef MM_UNIX
    FLAW ("Does not work in UNIX.");
    //output_ = popen ("md < md.input", "rt");
    #endif

    if (output_ == NULL)
    {
    	Text err;
    	switch (errno)
    	{
        	case EINVAL: err = "EINVAL";
        	case EAGAIN: err = "EAGAIN";
        	case ENOMEM: err = "ENOMEM";
    	}
        to_user().error (Text("Could not start m.DynaMix. ErrNo = ") + err);
        return false;
    }
    return true;
}

void M_DynaMix_pipe_process::
close_process ()
{
    #ifdef MM_WIN32
    _pclose (output_);//fix to Pipe_ptr
    #endif
    #ifdef MM_UNIX
    FLAW ("Does not work in UNIX.");
    pclose (output_);//fix to Pipe_ptr
    #endif

    output_ = 0;
}

void M_DynaMix_pipe_process::
stop ()
{
}

void M_DynaMix_pipe_process::
read_mDynaMix_output (Atom_group * ordered_atoms)
{
    static bool reinter_flag = false;//fix to lock
    if (reinter_flag)
    {
        //log() << "# reinter #";
        return;
    }//*/
    reinter_flag = true;

    using namespace std;
    const int   bufsize = 1024;
    char        buffer [bufsize];
    bool        mDynaMix_success = false;
    bool        has_warnings     = false;
    bool        read_coords      = false;
    //ofstream    out (simulator().output_file_name().c_str());
    ofstream    out ((Path::MDynaMix() + simulator().output_file_name()).c_str());
    int         current_atom_number =0; //fix
    Text        report;

    while (!feof (output_))
    {
        if (fgets (buffer, bufsize, output_) != 0)
        {
            string          line (buffer);
            stringstream    in   (line);

            if (line.find ("main MD loop finished") != string::npos)
                mDynaMix_success = true;

            string prefix;
            in >> prefix;

            if (prefix == "@mm")
            {
                if (line.find ("coord.start") != string::npos)
                {
                    read_coords = true;
                    current_atom_number = 0;
                    continue;
                }

                if (line.find ("coord.end") != string::npos)
                {
                    read_coords = false;
                    continue;
                }

                if (read_coords)
                {
                    double x, y, z;
                    in >> x >> y >> z;
            
                    //fix ???
                    /*if (in.fail())
                    {
                        stop();

                        to_user (). error (Text () + 
                            "Can not read coords from '" + buffer + "'.");
                        break;
                    }//*/
        
                    if (in.good())
                    {
                        Atom &current_atom = 
                            ordered_atoms->atom (current_atom_number);
                        current_atom.set_x (x);
                        current_atom.set_y (y);
                        current_atom.set_z (z);
                        //fix to model().set_coords;
                    }
        
                    ++current_atom_number;
                    continue;
                }

                string second_word;
                in >> second_word;
                if (second_word != "E") //fix !!!
                {
                        //qApp->processEvents (100);//fix
                        //qApp->processOneEvent ();
                        
                        //3 QApplication::eventLoop ()->
                        qApp->
                            processEvents (QEventLoop::ExcludeSocketNotifiers);

                        continue;

                    //stop();
                    //to_user (). error 
                    //    (Text("Unexpected string: ") + buffer + "'.");
                    //break;
                }

                Text text;
                double value;
                int number;
                
                in >> number;   text += "step=";                text += number;

                in >> value;    text += "   E.pot=";        text += value;
                simulator().potential_monitor().set_current_value (value);
                
                in >> value;    text += "   E.bonded=";   text += value;
                in >> value;    text += "   E.el.st=";      text += value;
                in >> value;    text += "   E.full=";       text += value;

                in >> value;    text += "   T=";            text += value;
                simulator().temperature_monitor().set_current_value (value);
                
                in >> value;    text += "   P=";            text += value;
                simulator().pressure_monitor().set_current_value (value);
                
                in >> value;    text += "   d=";            text += value;
                simulator().density_monitor().set_current_value (value);

                /*if (in.fail())
                {
                    stop();
                    to_user (). error (Text () + 
                        "Can not read E from: '" + buffer + "'.");
                    break;
                }//*/
                if (in.fail())
                {
                    text = buffer;
                }

                to_user().status (text);
                //step_finished_.publish();
                simulator().publish_step_finish ();
                //qApp->processEvents (1);
                report = text;

                //out << buffer;//fix remove
            }
            else
            {
                if (line.find ("!!!") != string::npos) //fix like M_DynaMix_QProcess::read_from_stdout()
                {
                    to_user().status (buffer);
                    has_warnings = true;
                }

                out << buffer << flush;
                printf (buffer);
            }

        }
        //else
        //{
        //    //to_user().error ("Could not read m.DynaMix output.");
        //    continue;
        //}
    }

    if (has_warnings)
        report += "   Warnings!!!";

    if (mDynaMix_success)
        report += "   Success.";
    else
    {
        report += "   Fail!!!";  
        reinter_flag = false;
        FLAW (report);
    }

    to_user().status (report);

    reinter_flag = false;
}

}//MM
