// 
// This file is part of MolMeccano, a cross-platform C++ chemical library.
//
// Copyright (C) 2001-2007 Alexey Nikitin
//
#ifndef MODEL_IMPL_H
#define MODEL_IMPL_H

#ifndef MODEL_H
#include "Model.h"
#endif

#ifndef MODEL_KIT_H
#include "Model_kit.h"
#endif

#ifndef ARRAY_OF_OWN_H
#include "Array_of_own.h"
#endif

#ifndef TEXT_H
#include "Text.h"
#endif

#ifndef ARRAY_OF_REF_H
#include "Array_of_ref.h"
#endif

#ifndef ATOM_H
#include "Atom.h"
#endif

#ifndef BOND_H
#include "Bond.h"
#endif

#ifndef MOLECULE_H
#include "Molecule.h"
#endif

#ifndef RESIDUE_H
#include "Residue.h"
#endif

#ifndef JOINT_H
#include "Joint.h"
#endif

namespace MM
{
class ID;//fix to hin

class Associated;
class Presentation;
class None;

class Model_impl : public Model
{
    Model_kit                   kit_;

//    Text                        title_;
    Own <Atom>                  atom_prototype_;
    Own <Bond>                  bond_prototype_;

    Array_of_own <Atom>         atoms_;
    Array_of_own <Bond>         bonds_;
    Array_of_own <Molecule>     molecules_;
    Array_of_own <Residue>      residues_;
    Array_of_own <Joint>        joints_;

    mutable bool                clone_flag_;

    void                        orphan_all ();     //fix ???

public:       
    Model_impl ();
   ~Model_impl ();
    explicit            Model_impl (Prototype &);
    explicit            Model_impl (None & p);

    void                copy (int n, Expanded_atom_group * result =0);
    Model *             clone () const;
    void                clone (Model_impl * new_model, int n, 
                               Expanded_atom_group * result) const;
    void                erase ();         //kill
    void                clear ();
    void                remove_deads ();

//    Text const &        title () const                                  {INVARIANT; return title_;}
//    void                set_title (Text const &title)                   {INVARIANT; title_=title;}

    Model_kit &         kit ()                                          {INVARIANT; return kit_;}
    Model_kit const &   kit () const                                    {INVARIANT; return kit_;}

    void                merge_model (Model * adoptee);

    void                move   (Vector_3D const & movement);
    void                rotate (Vector_3D const & around, double teta);

    Atom &              atom_prototype ()                               {INVARIANT; return atom_prototype_();}
    void                set_atom_prototype (Atom * adoptee)             {INVARIANT; atom_prototype_.adopt(adoptee);}
    int                 atom_count() const                              {           return atoms_.size();}
    Atom &              atom (int i)                                    {INVARIANT; return atoms_[i]; kit_.event().conformation_changed();}
    Atom const &        atom (int i) const                              {INVARIANT; return atoms_[i];}
    void                add_atom (Atom * atom);
    void                erase (Atom & atom);

    Atom &              atom (const ID & id);        //fix to hin
    Atom const &        atom (const ID & id) const;

    Bond &              bond_prototype ()                               {INVARIANT; return bond_prototype_ ();}
    void                set_bond_prototype (Bond * adoptee)             {INVARIANT; bond_prototype_.adopt(adoptee);}
    int                 bond_count() const                              {           return bonds_.size();}
    Bond &              bond (int i)                                    {INVARIANT; return bonds_[i];}
    Bond const &        bond (int i) const                              {INVARIANT; return bonds_[i];}
    void                add_bond (Bond * bond);

    void                detect_molecules();
    int                 molecule_count()const                           {           return molecules_.size();}
    Molecule &          molecule   (int i)                              {INVARIANT; return molecules_[i];}
    Molecule const &    molecule   (int i) const                        {INVARIANT; return molecules_[i];}
    void                add_molecule  (Molecule * mol);
    Molecule *          orphan_molecule (Molecule & mol);
    void                reset_molecules ();

    int                 residue_count () const                          {           return residues_.size();}
    Residue &           residue (int n)                                 {INVARIANT; return residues_[n];}
    Residue const &     residue (int n) const                           {INVARIANT; return residues_[n];}
    void                add_residue (Residue *res);
    void                remove_dead_residues ()                         {INVARIANT; residues_.stable_kill_deads();}
    void                reset_residues ();

    int                 joint_count () const                            {           return joints_.size();}
    Joint &             joint (int n)                                   {INVARIANT; return joints_[n];}
    Joint const &       joint (int n) const                             {INVARIANT; return joints_[n];}
    Joint &             joint (Text const& local_id);
    void                add_joint (Joint *joint);

    bool    save    (bool to_comment);
    bool    save_as (Text const & file_name, Text const & file_type,
                     Text * name_saved, bool to_comment = false);
    void    load    (Text const & file_name, Text const & file_type = "auto detect");
    void    add     (Text const & file_name, Text const & file_type);
    void    pull_on (Text const & file_name, Text const & file_type);

    void    clear_local_ids ();

protected:
    virtual bool                invariant() const;
};

}//MM

#endif //MODEL_IMPL_H
