#ifndef VECTOR_3D_IMPL_H
#define VECTOR_3D_IMPL_H

#ifndef VECTOR_3D_H
#include "Vector_3D.h"
#endif

namespace MM
{

class Vector_3D_impl : public Vector_3D
{
     double x_, y_, z_;

public:
    friend class Point_3D_impl;

    Vector_3D_impl (double x, double y, double z) : x_(x), y_(y), z_(z) { }
    explicit Vector_3D_impl (Vector_3D const& v)
        : x_(v.x()), y_(v.y()), z_(v.z()) { }

    /*// Vector protocol {
    virtual int         size () const                   {return 3;}
    virtual void        get (double * values) const;
    virtual void        set (double const* new_values);
    virtual void        add (double const* values);
    virtual void        add_scaled (double scale, double const* values);
    virtual void        multiply (double value);
    virtual Linear_combination_handler
                        linear_combination (double a);
    // Vector protocol }//*/

    double  x() const               {return x_;}
    double  y() const               {return y_;}
    double  z() const               {return z_;}

    void    set_x(double x )        {x_ = x;}
    void    set_y(double y )        {y_ = y;}
    void    set_z(double z )        {z_ = z;}
    void    clear ()                {x_ = 0.; y_ = 0.; z_ = 0.;}

    Vector_3D & negate ()           {x_= -x_; y_= -y_; z_= -z_; return *this;}

    Vector_3D & norm()      {double k=1./length(); x_*=k; y_*=k; z_*=k; return *this;}
    //void    operator =  (Vector_3D const & v)       {x_= v.x(); y_=v. y(); z_=v. z();}
    void    operator += (Vector_3D const & v)       {x_+=v.x(); y_+=v.y(); z_+=v.z();}
    void    operator -= (Vector_3D const & v)       {x_-=v.x(); y_-=v.y(); z_-=v.z();}
    void    operator += (Vector_3D_impl const & v)  {x_+=v.x(); y_+=v.y(); z_+=v.z();}
    void    operator -= (Vector_3D_impl const & v)  {x_-=v.x(); y_-=v.y(); z_-=v.z();}
    void    operator *= (double v)                  {x_ *= v; y_ *= v; z_ *= v;}
    void    add_scaled (double scale, Vector_3D const& v) ;

    double  length  () const;
    double  length_2() const                        {return x_*x_+y_*y_+z_*z_;}
    double  dot   (Vector_3D const & v) const;
    void    cross (Vector_3D const & v);
    void    cross (Vector_3D const & v, Vector_3D * result) const;
    double  dot   (Vector_3D_impl const & v) const {return x_*v.x_+y_*v.y_+z_*v.z_;}
    void    cross (Vector_3D_impl const & v);
    void    cross (Vector_3D_impl const & v, Vector_3D_impl * result) const;

    void    affine (Vector_3D const & p, double t);
    void    affine (Vector_3D_impl const & p, double t);

    int     dimensions () const {return 3;}

private:
    //Vector_3D_impl (Vector_3D_impl const &);
    void operator = (Vector_3D_impl const &);
};

inline void Vector_3D_impl::
cross (Vector_3D_impl const & v)
{
    double x_tmp = y_ * v.z_ - z_ * v.y_;
    double y_tmp = z_ * v.x_ - x_ * v.z_;
    z_ = x_ * v.y_ - y_ * v.x_;
    x_ = x_tmp;
    y_ = y_tmp;
}

inline void Vector_3D_impl::
cross (Vector_3D_impl const & v, Vector_3D_impl * result) const
{
    result->x_ = y_ * v.z_ - z_ * v.y_;
    result->y_ = z_ * v.x_ - x_ * v.z_;
    result->z_ = x_ * v.y_ - y_ * v.x_;
}

inline void Vector_3D_impl::
affine (Vector_3D_impl const & v, double t)
{
    x_ = (1 - t) * x_ + t * v.x_;
    y_ = (1 - t) * y_ + t * v.y_;
    z_ = (1 - t) * z_ + t * v.z_;
}

}//MM

#endif //VECTOR_3D_IMPL_H
