/*
 * Copyright (c) 1999-2021 Hartmut Seichter
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */
#ifndef PW_CORE_GEOMETRY_HPP
#define PW_CORE_GEOMETRY_HPP

#include <cstddef>
#include <pw/core/aabb.hpp>
#include <pw/core/globals.hpp>
#include <pw/core/resource.hpp>
#include <pw/core/vector.hpp>
#include <vector>

namespace pw {

/*
 * NOTE this needs to be rewritten to take into account for *any* kind of
 * geometry Some ideas are drafted down there to separate out the attribute
 * buffers. Things to consider: multiple UVs, triangle soup, per-vertex-color,
 * texture transforms, weights, etc. pp.
 */

class geometry {
  public:
    /**
     * @brief describes the topology for the primitives based on Vulkan
     */
    enum class primitive_topology_type {
        point_list,
        line_list,
        line_strip,
        triangle_list,
        triangle_strip,
        triangle_fan
    };

    using index_t   = uint32_t; //< needs to be compatible with GL_UNSIGNED_INT
    using indices_t = std::vector<index_t>;

    geometry() = default;
    geometry(primitive_topology_type t, vector3_array v, indices_t i);
    ~geometry() = default;

    void set_primitive_topology(primitive_topology_type t) {
        _primitive_topology = t;
    }
    primitive_topology_type primitive_topology() { return _primitive_topology; }

    void set_vertices(vector3_array v);
    vector3_array vertices() const { return _vertices; }

    void set_indices(indices_t v);
    const indices_t& indices() const;

    void set_normals(vector3_array v);
    const vector3_array& normals() const;

    void set_texture_coordinates(std::vector<vector2_array> v);
    const std::vector<vector2_array>& texture_coordinates() const {
        return _texture_coords;
    }

    void transform(const matrix4x4& m);

    void compute_normals();

    void compute_tangent_space();

    aabb bounds() const;

    uint64_t change_count() const { return _change_count; }
    void set_change_count(uint64_t n) { _change_count = n; }

  protected:
    primitive_topology_type _primitive_topology =
        primitive_topology_type::point_list;

    vector3_array _vertices; //!< vertex data
    indices_t _indices;      //!< indices

    vector3_array _normals;    //!< normal data
    vector3_array _tangents;   //!< tangent data
    vector3_array _bitangents; //!< bitangent

    std::vector<vector2_array> _texture_coords; //! texture coordinates

    uint64_t _change_count{0};
};

struct attribute final {

};


} // namespace pw

#endif
