//
//  Polygon.h
//  Meteor
//
//  Created by Cesar Parent on 13/07/2015.
//  Copyright (c) 2015 Cesar Parent. All rights reserved.
//

#ifndef __Meteor__Polygon__
#define __Meteor__Polygon__

#include "../CPFoundation.h"
#include "Vec.h"
#include "Rect.h"
#include "Transform.h"
#include <initializer_list>

NS_BEGIN

/**
 * @class           Polygon
 * @ingroup         Geometry
 * @brief           An object that represents a polygon made of a list of arbitrary points.
 */
class Polygon {
    
public:
    
    /**
     * @name        Creating Polygons
     * @{
     */
    
    /**
     * @brief       Creates and returns a new star-shaped polygon.
     * @param       branches    The number of branches.
     * @param       tipLength   The distance between the star's center and the tip of the branches.
     * @param       dipLength   The distance between the star's center and the dip between branches.
     * @return      A star-shaped polygon.
     */
    static Polygon
    star(CPIndex branches, int tipLength, int dipLength);
    
    /**
     * @brief       Creates and returns a new regular polygon.
     * @param       sides       The number of sides.
     * @param       radius      The distance between the center and each vertex of the polygon.
     * @return      A regular polygon.
     */
    static Polygon
    regularPolygon(CPIndex sides, int radius);
    
    /**
     * @brief       Creates and returns a polygon from a Rect object.
     * @param       rect        A rectangle object.
     * @return      A polygon that represents a rectangle
     */
    static Polygon
    rectangle(const Rect& rect);
    
    
    /*!
     * @brief       Creates a new polygon.
     * @param       vertices    The Number of vertices in the polygon.
     */
    Polygon(CPIndex vertices);
    
    /*!
     * @brief       Creates a new polygon from a list of vertices.
     * @param       vertices    List of vertices located relative to the polygon's center.
     */
    Polygon(const std::initializer_list<vec2>& vertices);
    
    /**
     * @}
     */
    
    /*!
     * @internal
     * @brief       Copy contructor.
     */
    Polygon(const Polygon& p);
    
    /**
     * @internal
     * @brief       Move constructor.
     */
    Polygon(Polygon&& p);
    
    
    virtual ~Polygon();
    
    /*!
     * @internal
     * @brief       Assignment operator.
     */
    Polygon&
    operator=(const Polygon& rhs);
    
    /**
     * @name        Inspecting the Polygon's vertices
     * @{
     */
    
    /*!
     * @brief       Sets the position of a vertex.
     * @details     If <code>index</code> is greater than the number of vertices in the polygon,
     *              an error will be thrown.
     * @param       index       The index of the vertex.
     * @param       vertex      The position of the vertex.
     */
    void
    setVertex(CPIndex index, const vec2& vertex);
    
    /*!
     * @brief       Returns the number of vertices in the polygon.
     * @return      The number of vertices in the polygon.
     */
    const CPIndex
    vertexCount() const { return _numVertices; }
    
    /*!
     * @brief       Returns the polygon's center of gravity.
     * @details     The center of gravity is calculated from the positionf of each vertex, and is
     *              only valid if the polygon is convex.
     * @return      The polygon's center of gravity.
     */
    const vec2
    center() const;
    
    /**
     * @}
     * @name        Changing the Polygon's vertices
     * @{
     */
    
    /*!
     * @brief       Returns a vertex from the polygon.
     * @details     If <code>index</code> is greater than the number of vertices in the polygon,
     *              an error will be thrown.
     * @param       index       The index of the vertex.
     * @return      The polygon's vertex at <code>index</code>
     */
    const vec2
    vertexAt(CPIndex index) const;
    
    /**
     * @}
     */
    
private:
    
    /*!
     * @brief       List of the polygon's vertices.
     */
    vec2*           _vertices;
    
    /*!
     * @brief       Wether the cached center of gravity is valid or not.
     */
    mutable bool    _centerDirty;
    
    /*!
     * @brief       Vertices' center of gravity.
     */
    mutable vec2    _center;
    
    /*!
     * @brief       Number of vertices in the polygon.
     */
    CPIndex         _numVertices;
    
    /*!
     * @brief       Update the center of gravity after a point was changed.
     */
    void
    calculateCOG();
    
};

NS_END

#endif /* defined(__Meteor__Polygon__) */
