#ifndef MODEL_FILE_H
#define MODEL_FILE_H

#ifndef DBC_H
#include "DbC.h"
#endif

#ifndef ELEMENT_H
#include "Element.h"
#endif

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

#ifndef OWN_H
#include "Own.h"
#endif

#ifndef BUILDER_H
#include "Builder.h"
#endif

#ifndef ARRAY_H
#include "Array.h"
#endif

namespace MM
{
class Model;
class Atom;
class Bond;
class Distance_restraint;
class Order;
class Molecule;
class Prototype;

class Model_file : protected DbC
{
    Model               *model_;
    //Text                file_name_;
    Own <Builder>       builder_;

protected:
    Array <Text>        extension_;

public:
    explicit                    Model_file ();
    explicit                    Model_file (Model & model);
    explicit                    Model_file (Prototype const &);
    virtual Model_file *        clone (Model & model) const =0;
    void                        set_model (Model &); //fix ???

    static Model_file const &   prototype       (Text const & file_type);
    static int                  prototype_count ();
    static Model_file const &   prototype       (int n);
    virtual Text const &        type_name       ()      const =0;   //fix like next?
    virtual int                 extension_count ()      const                   {return extension_.size();}
    virtual Text const &        extension       (int n) const                   {return extension_[n];}
    virtual void                add_extension   (Text const & ext)              {extension_.push_back(ext);}

    virtual bool                support_input     () const =0;
    virtual bool                support_output    () const =0;
    virtual bool                support_bonds     () const =0;
    virtual bool                support_molecules () const =0;

    //Model_file( MM_model & model ); //fix ???
    virtual void                save (bool to_comment) = 0;
    virtual void                add (Text const & file_name) = 0;
    //virtual void                clear();

    Text const &                name() const;
    void                        set_name( const Text & file_name );
    Model &                     model();
    Model const &               model() const;

    bool                        has_bulider () const    {return builder_.is_valid();}
    Builder const &             builder () const {return builder_();}
    void                        adopt_builder (Builder * adoptee);
    Builder *                   orphan_builder ();


    class           Accept_new_fine_types;
    friend class    Accept_new_fine_types;
    
    class Accept_new_fine_types
    {
        friend class Model_file;
        Model_file * file_;

        explicit Accept_new_fine_types (Model_file * file) : file_(file) 
        {file_->accept_new_fine_types_ = Ask;
         file_->accept_new_fine_types_lock_ = this;}

    public:
        enum {Ask, Yes, No, Tmp};

        ~Accept_new_fine_types () 
        {file_->accept_new_fine_types_ = No;
         file_->accept_new_fine_types_lock_ = 0;}

        void set (int on)
        {file_->accept_new_fine_types_ = on;}
    };

    Accept_new_fine_types *     accept_new_fine_types () 
    {
        if (accept_new_fine_types_lock_ == 0)
            return new Accept_new_fine_types (this);
        else
            return 0;
    }

protected:
    Accept_new_fine_types *     accept_new_fine_types_lock_;
    int                         accept_new_fine_types_;

protected:
    virtual void                check_file_name() = 0;
    virtual Atom &              new_atom (Element element);
    virtual Bond &              new_bond (Atom & atom1,
                                          Atom & atom2,
                                          const Order & order);

    virtual Distance_restraint & new_distance_restraint
                                         (Atom & atom1,
                                          Atom & atom2,
                                          Text const & type,
                                          double       R_eqv,
                                          double       K_r);

    virtual Molecule &          new_molecule ();
    virtual Residue  &          new_residue  ();
    virtual Joint    &          new_joint (Atom  & stub_atom,
                                           Atom  & terminal_atom,
                                           Atom  & directional_atom);

private:
    static Array <Model_file*> &    type_list ();
    static void                     register_type (Model_file &file_type);
};

}//MM

#endif //MODEL_FILE_H
