#include "povmesh.h"
#include <QTextStream>
#include <QDebug>


POVMesh2::POVMesh2() : Dups(0)
{
    resetBounds();
}

int POVMesh2::addVertice(double x, double y, double z)
{
    dvector3d vec(x,y,z);

    if (!VerticesHash.contains(vec))
    {
        extendBounds(x,y,z);
        Vertices.push_back(vec);
        VerticesHash[vec]=Vertices.count()-1;
    }
    else
      Dups++;

    return VerticesHash[vec];
}

POVMesh2::dvector3d POVMesh2::center() const
{
    double cc[3];

    for (int i = 0; i < 3; ++i)
        cc[i] = (Maxs[i] - Mins[i] ) / 2.0;

    return dvector3d(cc[0], cc[1], cc[2]);
}

void POVMesh2::setCenter(dvector3d c)
{
    dvector3d diff = c - center();
    moveBy(diff);
}

void POVMesh2::moveBy(dvector3d v)
{
    qDebug() << "moveBy" << v;
    for (PointListT::iterator it = Vertices.begin(); it != Vertices.end(); ++it)
         *it = *it + v;

    resetBounds();
}

double POVMesh2::getMaxSize() const
{
   return qMax(Maxs[2]-Mins[2], qMax(Maxs[1]-Mins[1], Maxs[0]-Mins[0]));
}

POVMesh2::dvector3d POVMesh2::normalize(double maxsize)
{
    resetBounds(true);

    double fac = maxsize / getMaxSize();

    qDebug() << "normalize by" << fac;


    for (PointListT::iterator it = Vertices.begin(); it != Vertices.end(); ++it)
        *it = *it * fac;

    return dvector3d(0,0,0);
}

void POVMesh2::resetBounds(bool recalc)
{
    Maxs[0] = Maxs[1] = Maxs[2] = INT_MIN;
    Mins[0] = Mins[1] = Mins[2] = INT_MAX;

    if (recalc)
    {
        qDebug() << "recalcbounds";

        for (PointListT::const_iterator it = Vertices.begin(); it != Vertices.end(); ++it)
            extendBounds(it->x(), it->y(), it->z());
    }
}

void POVMesh2::extendBounds(double x, double y, double z)
{
    Maxs[0] = qMax(Maxs[0], x);
    Maxs[1] = qMax(Maxs[1], y);
    Maxs[2] = qMax(Maxs[2], z);

    Mins[0] = qMin(Mins[0], x);
    Mins[1] = qMin(Mins[1], y);
    Mins[2] = qMin(Mins[2], z);
}

QTextStream &operator<<(QTextStream & ts, POVMesh2& m)
{
    qDebug() << "output starts, we have" << m.Vertices.count() << "vertices (" << m.Dups << " dups dropped) and" << m.Faces.count() << "faces";

    ts << "mesh2 { \n";
    ts << "\tvertex_vectors {\n";
    ts << "\t" << m.Vertices.size() << ", \n";

    for (POVMesh2::PointListT::const_iterator it = m.Vertices.begin(); it != m.Vertices.end(); ++it)
    {
        ts << "\t";
        it->toQTextStream(ts, m.Scale);
        ts << "\n";

    }

    ts << "\t}\n";
    ts << "\tface_indices {\n";
    ts << "\t" << m.Faces.size() << ", \n";

    for (POVMesh2::FacesListT::const_iterator it = m.Faces.begin(); it != m.Faces.end(); ++it)
    {
        ts << "\t";
        it->toQTextStream(ts);
        ts << "\n";

    }

    ts << "\t}\n";


	ts << "\tpigment {rgb 1}\n";
    //ts << "\t}\n";


    ts << "\trotate <-90,0,360*clock>\n";
	//ts << "\t}\n";
	//ts << "\t}\n";

    ts <<  "}\n";

    return ts;
}

bool operator== (const POVMesh2::dvector3d& left, const POVMesh2::dvector3d& right)
{
    return (
            (left.x() == right.x()) &&
            (left.y() == right.y()) &&
            (left.z() == right.z())
    );
}

uint qHash(const POVMesh2::dvector3d& key, uint seed)
{
    return qHash(key.x(), seed) ^ qHash(key.y(), seed) ^ qHash(key.z(), seed);
}

QDebug& operator<< (QDebug& dbg, POVMesh2::dvector3d v)
{
    dbg.nospace() << "{" << v.x() << ", " << v.y() << ", " << v.z() << "}";
    return dbg;
}

