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

    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
    Polygon intersection that wrapps the resulting intersection and the 
    intersection points.  

    Used for collection based polygon intersections - polygons that store
    their own points, instead of using indices to refer to some global
    point list.   

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

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

#ifndef PolygonIntersection_HPP
#define PolygonIntersection_HPP

#include <vector>
#include "tag.hpp"
#include "Polygon.hpp"

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

namespace geophase { 

/*---------------------------------------------------------------------------*\
                         Class PolygonIntersection Declaration
\*---------------------------------------------------------------------------*/

template<typename Polygon>  
class PolygonIntersectionBase
{

public:

    const Polygon& polygon() const
    {
        return intersectionPolygon_; 
    }

    template<typename Point>
    void addPoint(Point const & p) 
    {
        intersectionPolygon_.push_back(p);  
    }

    template<typename Point>
    void addIntersectionPoint(Point const & p) 
    {
        intersectionPoints_.push_back(p); 
    }

    void reset()
    {
        intersectionPolygon_.resize(0);
        intersectionPoints_.resize(0);
    }

    const Polygon& intersectionPoints() const 
    {
        return intersectionPoints_; 
    }

    void clear() 
    {
        intersectionPolygon_.clear(); 
        intersectionPoints_.clear(); 
    }

    decltype(auto) polygon_begin() 
    {
        return intersectionPolygon_.begin(); 
    }

    decltype(auto) polygon_end()
    {
        return intersectionPolygon_.end(); 
    }

    decltype(auto) polygon_begin() const
    {
        return intersectionPolygon_.begin(); 
    }

    decltype(auto) polygon_end() const
    {
        return intersectionPolygon_.end(); 
    }

    auto polygon_size () const
    {
        return intersectionPolygon_.size(); 
    }

    decltype(auto) polygon_front() 
    {
        return intersectionPolygon_.front(); 
    }

    decltype(auto) polygon_front() const
    {
        return intersectionPolygon_.front(); 
    }

    decltype(auto) polygon_back() 
    {
        return intersectionPolygon_.back(); 
    }

    decltype(auto) polygon_back() const
    {
        return intersectionPolygon_.back(); 
    }

    auto intersection_points_begin() 
    {
        return intersectionPoints_.begin(); 
    }

    auto intersection_points_begin() const 
    {
        return intersectionPoints_.begin(); 
    }

    auto intersection_points_end() 
    {
        return intersectionPoints_.end(); 
    }

    auto intersection_points_end() const 
    {
        return intersectionPoints_.end(); 
    }

    decltype(auto) intersection_points_front() 
    {
        return intersectionPoints_.front(); 
    }

    decltype(auto) intersection_points_front() const 
    {
        return intersectionPoints_.front(); 
    }

    decltype(auto) intersection_points_back() 
    {
        return intersectionPoints_.back(); 
    }

    decltype(auto) intersection_points_back() const 
    {
        return intersectionPoints_.back(); 
    }

protected:

    Polygon intersectionPolygon_; 
    Polygon intersectionPoints_; 
};

template<typename Polygon>  
class PolygonIntersection
:
    public PolygonIntersectionBase<Polygon>
{};

template<>  
class PolygonIntersection<vectorPolygon>
:
    public PolygonIntersectionBase<vectorPolygon>
{ 
    typedef PolygonIntersectionBase<vectorPolygon> Base; 

    public: 

    PolygonIntersection()
    {
        Base::intersectionPoints_.reserve(2); 
        Base::intersectionPolygon_.reserve(2);
    }
};

template<typename Polygon>
struct tag <PolygonIntersection<Polygon>>
{
    typedef polygon_intersection_tag type;
};

// Common intersection aliases.
using vectorPolygonIntersection     = PolygonIntersection<vectorPolygon>; 
using listPolygonIntersection       = PolygonIntersection<listPolygon>; 
using dequePolygonIntersection      = PolygonIntersection<dequePolygon>; 
using trianglePolygonIntersection   = PolygonIntersection<triangle>; 
using rectanglePolygonIntersection  = PolygonIntersection<rectangle>; 

} // End namespace geophase 

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

#endif

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