/*---------------------------------------------------------------------------*\

    geophase: A C++ template library for geometrical operations on non-convex
    polyhedra with non-planar faces
     
    Copyright (C) 2019 Tomislav Maric, TU Darmstadt 

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.


Description
    N-dimensional vector using STL arrays. 

Author
    Tomislav Maric maric@mma.tu-darmstadt.de

\*---------------------------------------------------------------------------*/

#ifndef Vector_HPP
#define Vector_HPP

#include "tag.hpp"
#include "constants.hpp"
#include "VectorArithmetic.hpp"
#include <array>
#include <iostream>

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

namespace geophase 
{

/*---------------------------------------------------------------------------*\
                         Class Vector Declaration
\*---------------------------------------------------------------------------*/


template<typename AT, auto D, typename Enable=void> 
class Vector; 

template<typename AT, auto D> 
class Vector<AT, D, enable_if_type_arithmetic_t<AT>> final
: 
    public std::array<AT, D> 
{

public: 

    using container_type = std::array<AT,D>; 
    using container_type::container_type; 

    template<typename ... Args>
    constexpr Vector(Args&& ... args)
        : 
            container_type{std::forward<Args>(args)...}
    {}

    // Delete new operator to prevent undefined behavior for
    // std::array*= new Vector; delete array; std::array has 
    // no virtual destructors.
    template<typename ...Args>
    void* operator new (size_t, Args...) = delete;

    // Arithmetic
    
    void operator=(AT const& s)
    {
        equals(*this, s);
    }
   
    template<typename OtherVector>
    void operator+=(OtherVector const& other)
    {
        plus_equals(*this, other);
    }

    template<typename OtherVector>
    void operator-=(OtherVector const& other)
    {
        minus_equals(*this, other);
    }

    void operator*=(AT const& s)
    {
        times_equals(*this, s);
    }

    void operator/=(AT const& s)
    {
        div_equals(*this, s);
    }


};

template<typename AT, auto D>
struct tag<Vector<AT, D>>
{
    using type = vector_tag;
};

// Common vectors.
using vector1Dd = Vector<double, 1>; 
using vector2Dd = Vector<double, 2>; 
using vector = Vector<double, 3>; 
using point = vector;

// WKT format std::ostream operator 
template<typename Vector> 
std::enable_if_t<type_tagged<Vector, vector_tag>(), std::ostream&> 
operator<<(std::ostream& os, Vector const& vec)
{
    // https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry
    
    os << "POINT("; 
    auto vecIt = vec.begin(); 
    for (std::size_t pI = 0; pI < std::size(vec) - 1; ++pI)
    {
        os << *vecIt << " ";  
        ++vecIt;
    }
    os << *vecIt << ")";

    return os; 
}

} // End namespace geophase 

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

#endif

// ************************************************************************* //
