#include "Molecular_detector.h"

#include "Molecular_width_iterator.h"
#include "Atom.h"
#include "Atom_kit.h"
#include "Molecule.h"
#include "Model.h"
#include "Model_kit.h"
#include "Flaw.h"
#include "Create.h"

namespace MM
{

void Molecular_detector::   //fix check rearranging of existing molecules
execute ()
{
    bool changes = false;
    int i, atoms_in_model = model_->atom_count();

    for (i=0;  i<atoms_in_model;  ++i)
    {
        Atom & atom = model_->atom(i);
        atom.kit().flag().clear (Atom_kit::molecular_mark);//fix remove
        //atom.kit().set_molecule (Molecule::none());
    }

    for (i=0;  i<atoms_in_model;  ++i)
    {
        Atom & root_atom = model_->atom(i);
        
        if (root_atom.kit().flag().is (Atom_kit::molecular_mark))
            continue;

        Molecule *current_molecule = &root_atom.kit().in_molecule();
        
        if (current_molecule == &Molecule::none())  // Create new molecule
        {
            Molecule *new_molecule = prototype <Molecule> (). clone ();
            new_molecule->add_atom (root_atom);
            model_->add_molecule (new_molecule);
            current_molecule = new_molecule;
            changes = true;
        }
        
        int atom_count=0;
        for (Molecular_width_iterator it (root_atom); 
             it.is_valid();  
             it.next(), ++atom_count)
        {
            Atom     & bound_atom = it.current ();
            bound_atom.kit().flag().set (Atom_kit::molecular_mark);
            ///Molecule * bound_atom_molecule = bound_atom.kit().in_molecule();
            Molecule & bound_atom_molecule = bound_atom.kit().in_molecule();

            if (current_molecule == &bound_atom_molecule)    // the same molecule
            {
                // Do nothing.
            }
            else if (&bound_atom_molecule == &Molecule::none()) // no molecule
            {
                current_molecule->add_atom (bound_atom);    //fix same
                changes = true;
            }
            else                                            // other molecule
            {
                bound_atom_molecule.remove_atom (bound_atom);//fix no need
                current_molecule->add_atom (bound_atom);    //fix same
                changes = true;
            }
        }

        if (atom_count < current_molecule->atom_count())
        {
            int atoms_in_mol = current_molecule->atom_count();
            Array<Atom*> list;

            for (int j=0;  j<atoms_in_mol;  ++j)
            {
                if (current_molecule->atom(j).kit().flag()
                    .is_not (Atom_kit::molecular_mark))
                {
                    list.push_back (&current_molecule->atom(j));
                    changes = true;
                }
            }
            for (int k=0;  k<list.size();  ++k)
                current_molecule->remove_atom (*list[k]);

        }
        else if (atom_count > current_molecule->atom_count()) 
            FLAW ("Number of atom in molecule are less then were added.");
    }

    for (i=0;  i<model_->molecule_count();  ++i)
    {
        if (model_->molecule(i).atom_count() == 0)
        {
            delete model_->orphan_molecule (model_->molecule(i));
            changes = true;
        }
        else
            model_->molecule(i).reset_residues ();
    }

    for (i=0;  i<atoms_in_model;  ++i)
        model_->atom(i).kit().flag().clear (Atom_kit::molecular_mark);

    if (changes)
        model_->kit().event().structure_changed();
}

}//MM
