#pragma once

#include "Point.h"
#include "Node.h"
#include "Transform.h"

#include <memory>
#include <vector>

using NodePtr = std::unique_ptr<Node>;
using VecNodes = std::vector<NodePtr>;

class AbstractMesh
{
public:
    enum class MeshType
    {
        LINE,
        TRI,
        QUAD
    };

    virtual ~AbstractMesh() = default;

    void addVectorAttribute(const std::string& tag, const std::vector<double>& values);

    void addConstantNodeVectorAttribute(const std::string& tag, const std::vector<double>& values);

    template<typename T>
    std::vector<T> getVerticesFlat(T scaleX = 1.0, T scaleY = 1.0, T scaleZ = 1.0) const
    {
        std::vector<T> ret(3*mNodes.size());
        for(std::size_t idx = 0; idx<mNodes.size(); idx++)
        {
            auto node = mNodes[idx].get();
            ret[3*idx] = node->getPoint().getX()/scaleX;
            ret[3*idx + 1] = node->getPoint().getY()/scaleY;
            ret[3*idx + 2] = node->getPoint().getZ()/scaleZ;
        }
        return ret;
    }

    virtual std::unique_ptr<AbstractMesh> copy() const = 0;

    std::vector<std::vector<double> > getNodeVectorAttributes(const std::string& tag);

    std::vector<double> getVectorAttribute(const std::string& tag) const;

    virtual MeshType getType() const = 0;

    bool hasVectorAttribute(const std::string& tag) const;

    void scale(double scaleX, double scaleY);

    void translate(const Point& offset);

    void translate(double offsetX, double offsetY, double offsetZ = 0.0);

    void transform(const Transform& transform);

    unsigned getNumNodes() const
    {
        return unsigned(mNodes.size());
    }

protected:
    std::unordered_map<std::string, std::vector<double> > mVectorAttributes;
    VecNodes mNodes;
};
