#include "Xyz_file.h"

#include "Fine_type.h"
#include "Atom.h"
#include "Atom_kit.h"
#include "Bond.h"
#include "Model.h"
#include "Bond_detector.h"
#include "User.h"
#include "Create.h"

#include <iomanip>
#include <fstream>
#include <sstream>
#include <string>

namespace MM
{
Xyz_file Xyz_file::prototype_(it_is_a_prototype);//fix

Xyz_file::
Xyz_file (Prototype const &)
:
    Model_file (Prototype())
{
    add_extension ("xyz");
    add_extension ("xmol");
}

Xyz_file::
Xyz_file (Model & model)
:
    Model_file (model)
{
    add_extension ("xyz");
    add_extension ("xmol");
}

Model_file * Xyz_file::
clone (Model & model) const
{
    Xyz_file *result = new Xyz_file (model);
    
    //result->extension_ = extension_;   //fix Array += should work
    //for (int i=0;  i<extension_.size();  ++i)
    //    result->extension_.push_back (extension_[i]);
    
    return result;
}

/*Xyz_file::Xyz_file( Model_accessor_protocol & accessor_protocol ) :
   Model_file( accessor_protocol )
{
}//*/

void Xyz_file::
add (Text const & file_name)
{
    using namespace std;

    int     atom_count = 0;
    double  charge,  x, y, z,  fx, fy, fz;
    string  element;
    int     broken_line = -1;

    ifstream    file (file_name.c_str());
    string      line;

    if (file.fail())
    {
        to_user(). error (Text("Cannot open file " + file_name));
        return;
    }

    getline (file, line);
    istringstream in (line);
    in >> atom_count;

    getline (file, line);
//    to_user(). status (line.c_str());

    for (int i=0;  i<atom_count;  ++i)
    {
        if (getline (file, line))
        {
            istringstream in (line);
            in >> element >> x >> y >> z;
            if (in.fail())
            {
                broken_line = i;
                break;
            }
            in >> charge;
            if (in.good())
            {
                in >> fy >> fz;

                if (in.good())
                {
                    fx = charge;
                    charge  = 1000000000.;
                }
                else 
                    fx = 1000000000.;
            }
            else 
                charge  = 1000000000.;


            string current_element = element;
            if (element.length() > 2)
            {
                current_element  = element[0];
                current_element += element[1];
            }

            if (!Element::is (current_element.c_str()))
            {
                current_element = current_element[0];

                if (!Element::is (current_element.c_str()))
                {
                    broken_line = i;
                    break;
                }
            }

            //Atom *current_atom = 
            //    create_atom (Element (current_element.c_str ()));
            Atom & current_atom = new_atom (Element (current_element.c_str()));

            current_atom.set_x (x);
            current_atom.set_y (y);
            current_atom.set_z (z);

            //if (in.good())
            //    current_atom.set_charge (charge);

            if (fx != 1000000000.)
                current_atom.kit().set_velocity (fx, fy, fz);

            else if (charge != 1000000000.) 
                current_atom.set_charge (charge);

            //model(). add_atom (current_atom);
        }
        else
        {
            broken_line = i;
            break;
        }
    }

    if (broken_line != -1)
        to_user().error (Text() + 
            "File " + file_name + " is broken at line " + 
            (broken_line + 3) + ".");

    //derive_bonds_from_distances();    //fix
    //Bond_detector bond_detector(model());
    //bond_detector.execute();
    //check_integrity();
}

void Xyz_file::check_file_name()
{
    std::string filename = name().c_str();
    if (filename.find (".xyz" ) == std::string::npos && 
        filename.find (".xmol") == std::string::npos)

        FLAW (Text(name()) + 
              " is a wrong file name.\n"
              "Check file name extension.");
}

void Xyz_file::
save (bool to_comment)
{
    using namespace std;
    check_file_name();

    ofstream out( name().c_str() );

    out << model().atom_count() << std::endl;

    if (to_comment)
        out 
            << fixed
            <<             "<Element>" << " "
            <<             "<X>"       << " "
            << setw(12) << "<Y>"       << " "
            << setw(12) << "<Z>"       << " "
            << setw(14) << "[Charge]"  << " "
            << setw(8)  << "[Comment]" << " "
            ;
    out << std::endl;

    for (int i=0;  i<model().atom_count();  ++i)
    {
        Atom const& atom = model().atom(i);

        out 
            << fixed << setprecision(6)
            << setw(5)  << atom.element().c_str() << " "
            << setw(12) << atom.x()               << " "
            << setw(12) << atom.y()               << " "
            << setw(12) << atom.z()               << " ";

        Vector_3D const & velocity = atom.kit().velocity();

        if (velocity.length_2() != 0)
        {
            out << fixed << setprecision(8) 
                << setw(15) << velocity.x() << " " 
                << setw(15) << velocity.y() << " " 
                << setw(15) << velocity.z() << " "; 
        }
        else if (atom.charge() != 0.)
            out << setw(8) << setprecision(5) << atom.charge() << " ";

        if (atom.kit().comment_line().is_empty())
        {
            if (to_comment)
            {
                if (atom.kit().has_mm_type())
                    out << atom.kit().mm_type_c_str();

                else if (atom.kit().has_fine_type ())
                    out << atom.kit().fine_type_name();
            }
        }
        else
            out << atom.kit().comment_line().c_str();

        out << endl;
    }
}

}//MM




