#include "TriFace.h"

#include "Edge.h"
#include "Node.h"

TriFace::TriFace(Edge* edge0, Edge* edge1, Edge* edge2, std::size_t id)
    :  AbstractFace(id),
        mEdge0(edge0),
        mEdge1(edge1),
        mEdge2(edge2)
{

}

std::unique_ptr<TriFace> TriFace::Create(Edge* edge0, Edge* edge1, Edge* edge2, std::size_t id)
{
    return std::make_unique<TriFace>(edge0, edge1, edge2, id);
}

TriFace::~TriFace()
{

}

std::vector<std::size_t> TriFace::getNodeIds() const
{
    return {mEdge0->getNode0Id(), mEdge0->getNode1Id(), mEdge1->getNode1Id()};
}

std::size_t TriFace::getNumNodes() const
{
    return 3;
}

void TriFace::replaceEdge(Edge* original, Edge* replacement)
{
    if (original == mEdge0)
    {
        mEdge0 = replacement;
    }
    else if (original == mEdge1)
    {
        mEdge1 = replacement;
    }
    else if (original == mEdge2)
    {
        mEdge2 = replacement;
    }
}

std::size_t TriFace::getEdge0Id () const
{
    return mEdge0->getId();
}

std::size_t TriFace::getEdge1Id () const
{
    return mEdge1->getId();
}

std::size_t TriFace::getEdge2Id () const
{
    return mEdge2->getId();
}

std::vector<std::size_t> TriFace::getEdgeIds() const
{
    return {mEdge0->getId(), mEdge1->getId(), mEdge2->getId()};
}

void TriFace::associateWidthEdges()
{
    mEdge0->associateFace(mId);
    mEdge1->associateFace(mId);
    mEdge2->associateFace(mId);
}

std::vector<Point> TriFace::getNodeLocations(Orientation orientation) const
{
    if (orientation != getOrientation())
    {
        return { mEdge0->getNode0()->getPoint(), mEdge0->getNode1()->getPoint(), mEdge1->getNode1()->getPoint() };
    }
    else
    {
        return { mEdge0->getNode0()->getPoint(), mEdge1->getNode1()->getPoint(), mEdge0->getNode1()->getPoint() };
    }
}

Vector TriFace::getNormal() const
{
    auto v0 = mEdge0->getNode0()->getPoint().getDelta(mEdge0->getNode1()->getPoint());
    auto v1 = mEdge0->getNode0()->getPoint().getDelta(mEdge1->getNode1()->getPoint());
    return v0.crossProduct(v1).getNormalized();
}

AbstractFace::Orientation TriFace::getOrientation() const
{
    Vector z_norm(0, 0, 1);
    if (z_norm.dotProduct(getNormal()) < 0.0)
    {
        return Orientation::CW;
    }
    else
    {
        return Orientation::CCW;
    }
}
