#ifndef __POINTCLOUD__
#define __POINTCLOUD__

// External libraries
#include <GEL/CGLA/Vec3d.h>

// Standard libraries
#include <string>
#include <vector>

/** Point cloud class.
 *
 * This is a class designed to handle a pointcloud data structure. It is a
 * single wrapper of lists of points, normals and optional intensity
 * information per point.
 */
class PointCloud {
  private:
    // ====================================================================== //
    // Underlying data fields

    std::vector<CGLA::Vec3d> point_list;  // Point Cloud positions
    std::vector<CGLA::Vec3d> normal_list; // Point cloud normals
    std::vector<double>      color_list;  // Point cloud thickness

  public:
    // ====================================================================== //
    // Constructors and destructors

    /** Construct a new Point Cloud object. */
    PointCloud(){};
    /** Construct a new Point Cloud object with preallocated vectors. */
    PointCloud(int N);
    /** Construct a new Point Cloud object from single point. */
    PointCloud(CGLA::Vec3d p, CGLA::Vec3d n, double c = 1.0);
    /** Construct a new Point Cloud object from existing lists. */
    PointCloud(std::vector<CGLA::Vec3d> points,
               std::vector<CGLA::Vec3d> normals, std::vector<double> colors);

    // ====================================================================== //
    // Data access

    /** Access point at index. */
    CGLA::Vec3d &points(int idx);
    /** Access normal at index*/
    CGLA::Vec3d &normals(int idx);
    /** Access color at index*/
    double &colors(int idx);

    /** Access the point list. */
    std::vector<CGLA::Vec3d> &points();
    /** Access the normal list. */
    std::vector<CGLA::Vec3d> &normals();
    /** Access color list. */
    std::vector<double> &colors();
    /** Return the number of points in the cloud. */
    size_t size();

    // ====================================================================== //
    // Add new point at the end of the lists

    /** Append existing point cloud to this one. */
    void push_back(PointCloud &pcl);
    /** Pushback new points to the cloud. */
    void push_back(CGLA::Vec3d p, CGLA::Vec3d n = CGLA::Vec3d(1.0),
                   double c = 1.0);

    // ====================================================================== //
    // Export functions

    /** Save point cloud as file in ply format.
     *
     * @param fileName
     * @param pcl pointcloud object.
     */
    friend void ply_writer(std::string fileName, PointCloud &pcl);
    /** Load pointcloud from ply file.
     *
     * @param fileName
     * @param pcl pointcloud object.
     */
    friend void ply_reader(std::string fileName, PointCloud &pcl);
};

#endif /* __POINTCLOUD__ */