#include "Molecule_impl.h"

#include "Atom_kit.h"
#include "Element.h"
#include "Residue.h"
#include "Point_3D_impl.h"

#include <map>
#include <set>
#include <string>

namespace MM
{

Molecule_impl::
Molecule_impl ()
:
    local_id_("-"),
    mm_type_(0)
{
}

void Molecule_impl::
set_local_id (Text const & id) const
{
    local_id_= id;
}

void Molecule_impl::
add_atom (Atom & ref)
{
    Molecule & old_mol = ref.kit().in_molecule ();

    REQUIRE ("Atom without molecule or atom in the same molecule.",
        &old_mol == &Molecule::none() || &old_mol == (Molecule*)this);

    if (&old_mol == (Molecule*)this)
        return;

    atoms_.push_back (ref);
    ref.kit().set_molecule (*this);
    mm_type_ = 0; //fix
}

void Molecule_impl::
remove_atom (Atom & ref)
{
    atoms_.remove(ref);
    ref.kit().set_molecule (Molecule::none());
    mm_type_ = 0;  //fix
}
/*
void Molecule_impl::
add_bond (Bond & ref)
{
    bonds_.push_back (bond);
}

void Molecule_impl::
remove_bond (Bond & ref)
{
    bonds_.remove (bond);
}//*/

double Molecule_impl::
mass () const
{
    double result = 0.;

    for (int i=0;  i<atom_count();  ++i)
        result += atom(i).mass();
    return result;
}

Text Molecule_impl::
molecular_formula (Format format) const
{
    using namespace std;
    map <string, int> count;

    for (int i=0;  i<atoms_.size();  ++i)
        ++count [atoms_[i].element().c_str()];

    Text result;

    for (map <string, int>::iterator it = count.begin(); 
         it != count.end(); 
         ++it)
    {
        result += it->first.c_str();

        if (it->second > 1)
        {
            if (format == HTML)
                result += "<sub>";

            result += it->second;

            if (format == HTML)
                result += "</sub>";
        }
    }

    return result;
}

double Molecule_impl::
charge () const
{
    double sum = 0.;
    for (int i=0;  i<atoms_.size();  ++i)
        sum += atoms_[i].charge();

    return sum;
}

void Molecule_impl::
reset_residues ()
{
    using namespace std;
    residues_.clear();
    int count = atoms_.size();
    set <Residue*>  res_set;

    //residues_.clear();

    for (int i=0;  i<count;  ++i)
    {
        Atom &    atom = atoms_[i];
        Residue & res  = atom.kit().in_residue();

        if (&res != &Residue::none())
        {
            if (res_set.find (&res) == res_set.end())
            {
                res_set.insert (&res);
                residues_.push_back (res);
            }
        }
    }

    /*
    for (int i=0;  i<count;  ++i)
    {
        Atom &    atom = atoms_[i];
        Residue & res  = atom.kit().in_residue();

        if (&res != &Residue::none())
            res_set.insert (&res);
    }

    residues_.clear();

    for (set <Residue*>::iterator it = res_set.begin();  
         it != res_set.end();  ++it)
    {
        residues_.push_back (**it);
    }
      //*/
}

void Molecule_impl::
clear_local_ids ()
{
    local_id_ = "";

    for (int i=0;  i<residues_.size();  ++i)
        residues_[i].set_local_id ("");//*/
}

void Molecule_impl::
move (Vector_3D const & movement)
{
    for (int i=0;  i<atom_count();  ++i)
        atom(i).move (movement);
}

void Molecule_impl::
rotate (Vector_3D const & around, double teta)
{
    for (int i=0;  i<atom_count();  ++i)
        atom(i).rotate (around, Point_3D_impl(0,0,0), teta);
}

}//MM



