#ifndef MODEL_PROXY_H
#define MODEL_PROXY_H

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

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

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

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

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

namespace MM
{
//class Model_kit;
//class Atom;
//class Bond;
//class Molecule;

class Model_proxy : public Model
{
    Model *             impl_;

public:
    explicit            Model_proxy ()              : impl_(0)      {;}
//    explicit            Model_proxy (Model & model) : impl_(&model == &Model::none() ? 0 : &model) {;}
    explicit            Model_proxy (Model & model) : impl_(&model) {;}
    virtual            ~Model_proxy ()                                          {impl_= 0;}
    Model *             real_model ()                                           {return impl_;}
    Model const*        real_model () const                                     {return impl_;}
    void                set_model (Model * model)                               {impl_= model;}

    Model *             clone () const                                          {return new Model_proxy (*impl_);}
    void                copy (int n, Expanded_atom_group * result)              {impl_->copy (n, result);}
    void                erase ()                                                {INVARIANT;        impl_->erase ();}
    void                clear ()                                                {INVARIANT;        impl_->clear ();}
    void                orphan_all ()                                           {INVARIANT;        impl_->orphan_all ();}
    void                remove_deads ()                                         {INVARIANT;        impl_->remove_deads ();}

    Model_kit &         kit ()                                                  {INVARIANT; return impl_->kit ();}
    const Model_kit &   kit () const                                            {INVARIANT; return impl_->kit ();}

//    Text const &        title () const                                          {INVARIANT; return impl_->title();}
//    void                set_title (Text const &title)                           {INVARIANT; impl_->set_title (title);}

    void                merge_model (Model * adoptee)                           {INVARIANT;        impl_->merge_model (adoptee);}

    void                move   (Vector_3D const& movement)                      {INVARIANT;        impl_->move (movement);}
    void                rotate (Vector_3D const& around, double teta)           {INVARIANT;        impl_->rotate (around, teta);}

    Atom &              atom_prototype ()                                       {INVARIANT; return impl_->atom_prototype ();}
    void                set_atom_prototype (Atom * adoptee)                     {INVARIANT;        impl_->set_atom_prototype (adoptee);}
    int                 atom_count     () const                                 {INVARIANT; return impl_->atom_count ();}
    Atom &              atom           (int i)                                  {INVARIANT; return impl_->atom (i);}
    const Atom &        atom           (int i) const                            {INVARIANT; return impl_->atom (i);}
    void                add_atom       (Atom * atom)                            {INVARIANT;        impl_->add_atom (atom);}
    void                erase          (Atom & atom)                            {INVARIANT;        impl_->erase (atom);}

    Atom &              atom (const ID & id)                                    {INVARIANT; return impl_->atom (id);}
    const Atom &        atom (const ID & id) const                              {INVARIANT; return impl_->atom (id);}

    Bond &              bond_prototype ()                                       {INVARIANT; return impl_->bond_prototype ();}
    void                set_bond_prototype (Bond * adoptee)                     {INVARIANT;        impl_->set_bond_prototype (adoptee);}
    int                 bond_count  () const                                    {INVARIANT; return impl_->bond_count ();}
    Bond &              bond        (int i)                                     {INVARIANT; return impl_->bond (i);}
    const Bond &        bond        (int i) const                               {INVARIANT; return impl_->bond (i);}
    void                add_bond    (Bond * bond)                               {INVARIANT;        impl_->add_bond (bond);}

    void                detect_molecules()                                      {INVARIANT;        impl_->detect_molecules ();}
    int                 molecule_count  () const                                {INVARIANT; return impl_->molecule_count ();}
    Molecule &          molecule        (int i)                                 {INVARIANT; return impl_->molecule (i);}
    const Molecule &    molecule        (int i) const                           {INVARIANT; return impl_->molecule (i);}
    void                add_molecule    (Molecule * mol)                        {INVARIANT;        impl_->add_molecule (mol);}
    Molecule *          orphan_molecule (Molecule & mol)                        {INVARIANT; return impl_->orphan_molecule (mol);}
    void                reset_molecules ()                                      {INVARIANT;        impl_->reset_molecules ();}

    int                 residue_count () const                                  {INVARIANT; return impl_->residue_count ();}
    Residue &           residue (int n)                                         {INVARIANT; return impl_->residue (n);}
    Residue const &     residue (int n) const                                   {INVARIANT; return impl_->residue (n);}
    void                add_residue (Residue *res)                              {INVARIANT;        impl_->add_residue (res);}
    void                remove_dead_residues ()                                 {INVARIANT;        impl_->remove_deads();}
    void                reset_residues ()                                       {INVARIANT;        impl_->reset_residues ();}

    int                 joint_count () const                                    {INVARIANT; return impl_->joint_count ();}
    Joint &             joint (int n)                                           {INVARIANT; return impl_->joint (n);}
    Joint const &       joint (int n) const                                     {INVARIANT; return impl_->joint (n);}
    Joint &             joint (Text const& local_id)                            {INVARIANT; return impl_->joint (local_id);}
    void                add_joint (Joint *joint)                                {INVARIANT;        impl_->add_joint (joint);}

    bool    save    (bool to_comment = false)                                   {INVARIANT; return impl_->save (to_comment);}
    bool    save_as (Text const & file_name, Text const & file_type,
                     Text * name_saved, bool to_comment = false)                {INVARIANT; return impl_->save_as (file_name, file_type, name_saved, to_comment);}
    void    load    (Text const & file_name, Text const & file_type)            {INVARIANT; impl_->load    (file_name, file_type);}
    void    add     (Text const & file_name, Text const & file_type)            {INVARIANT; impl_->add     (file_name, file_type);}
    void    pull_on (Text const & file_name, Text const & file_type)            {INVARIANT; impl_->pull_on (file_name, file_type);}
    void    clear_local_ids ()                                                  {INVARIANT; impl_->clear_local_ids();}

protected:
    virtual bool invariant() const {return impl_ != 0;}

};

}//MM

#endif //MODEL_PROXY_H
