#ifndef MEASURE_GEOMETRY_IMPL_H
#define MEASURE_GEOMETRY_IMPL_H

#ifndef MEASURE_GEOMETRY_H
#include "Measure_geometry.h"
#endif

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

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

#ifndef POINT_3D_IMPL_H
#include "Point_3D_impl.h"
#endif

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

#include "Length.h"
#include "Angle_unit.h"
#include "Length_unit.h"

#include <deque>

namespace MM
{

class Measure_geometry_impl 
: 
    public    Measure_geometry,
    protected DbC
{
    class Point
    {
        int                 number_;
        Point_3D_impl       space_position_;
        Text                type_;
        bool                is_active_;

    public:
        Point (int number, Text const& type, bool is_active = true)
            :
            number_         (number),
            space_position_ (0,0,0),
            type_           (type),
            is_active_      (is_active)
        {
        }

        Point (Point const& r)//fix
        :
            number_         (r.number_),
            space_position_ (r.space_position_),
            type_           (r.type_),
            is_active_      (r.is_active_)
        {
        }

        int                 number         () const {return number_;}
        Point_3D const &    space_position () const {return space_position_;}
        Text const &        type           () const {return type_;}
        bool                is_active      () const {return is_active_;}

        void                set_number         (int number)                {number_ = number;}
        void                set_space_position (Point_3D const & position) {space_position_.affine(position, 1);}
        void                set_type           (Text const& type)          {type_ = type;}
        void                set_active         (bool on)                   {is_active_ = on;}
    };

    std::deque <Point>      four_points_;
    
    //mutable Point_3D_impl   last_point_;
    mutable Length_unit     last_length_;
    mutable Angle_unit      last_angle_;
    mutable Angle_unit      last_dihedral_angle_;

    Vector_3D_impl          last_movement_;

public:
    //enum  Point_type  {Atom, Mass_center, Space_position};
    explicit                Measure_geometry_impl ();

    void                    prepend_point ();
    void                    append_point  ();
    
    bool                    is_active  (int point) const;
    void                    set_active (int point, bool on);
    int                     active_count ();

    Text const &            type (int point) const;
    //void                  set_type (Point_type new_type) {}
    void                    set_atom_type          (int point, int atom_number);
    void                    set_mass_center_type   (int point, int mol_number);
    void                    set_space_position_type(int point, Point_3D const&);

    void                    get_space_position (int point, Point_3D &) const;
    void                    set_space_position     (int pnt, Point_3D const&);

    int                     number             (int point) const;
    void                    set_number         (int point, int number);

    void                    get_info (Text & result);
    void                    get_points_info (Text & result);

    Text const &            parameter_type_name () const;
    Unit const &            parameter () const;
    void                    set_parameter (Unit const &);   //fix remove
    void                    add_parameter (Unit const &);   //fix remove
    void                    set_parameter (double);
    void                    add_parameter (double);

    Length_unit const &     last_length         () const {return last_length_;}
    Angle_unit  const &     last_angle          () const {return last_angle_;}
    Angle_unit  const &     last_dihedral_angle () const {return last_dihedral_angle_;}
    bool                    support_restraint   () const;
    void                    new_distance_restraint (double R_eqv,
                                                    double K_r) const;

protected:
    Array <Point const*>    active_points () const;

    void                    calc_space_positions ();
    void                    calc_space_position  (Point & point);
    const char *            element            (Point const* point) const;
    const char *            mm_type_c_str      (Point const* point) const;

    //void    clear_space_positions ();
    //void    clear_space_position  (Point const& point);

    virtual bool invariant() const
    {
        bool result = true;

        //result &= check_point (four_points_[0]);
        //result &= check_point (four_points_[1]);
        //result &= check_point (four_points_[2]);
        //result &= check_point (four_points_[3]);

        result &= (four_points_.size() == 4);
        return result;
    }

    /*bool check_point (Point const& point) const
    {
        bool result = true;

        if (point.number() < 0 )
            result &= //point.space_position_ != 0 && 
                        (point.type() == "Space position");
        else
            result &= //point.space_position_ == 0 && 
                        (point.type() == "Atom" || 
                         point.type() == "Mass center");
        return result;
    }//*/
};

}//MM

#endif //MEASURE_GEOMETRY_IMPL_H
