//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Img3D/Model/Model.cpp
//! @brief     Implements Model class
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#include "Img3D/Model/Model.h"
#include "Base/Util/Assert.h"

namespace Img3D {

Model::Model()
    : defaultCameraPosition(F3(1, 1, 1), F3(0, 0, 0), F3(0, 0, 1))
{
}

Model::~Model() = default;

void Model::clearOpaque()
{
    m_objects.clear();
    emit updated(false);
}

void Model::clearBlend()
{
    m_transparentObjects.clear();
    emit updated(false);
}

PlotParticle* Model::newParticle(EShape k, float R)
{
    using namespace Particles;

    float D = 2 * R;

    switch (k) {
    case EShape::None:
        return nullptr;
    case EShape::BarGauss:
        return new BarGauss(D, D, 5 * D);
    case EShape::BarLorentz:
        return new BarLorentz(D, D, 5 * D);
    case EShape::Box:
        return new Box(D, D, D);
    case EShape::Sphere:
        return new Sphere(R);
    case EShape::Spheroid:
        return new Spheroid(R / 2, D);
    case EShape::Cylinder:
        return new Cylinder(R, D);
    case EShape::TruncatedSphere:
        return new TruncatedSphere(R, D / 3);
    case EShape::TruncatedSpheroid:
        return new TruncatedSpheroid(R, 2 * R, 1.5);
    case EShape::Cone:
        return new Cone(R, D, 1.3f);
    case EShape::Icosahedron:
        return new Icosahedron(R * IcosahedronL2R);
    case EShape::Dodecahedron:
        return new Dodecahedron(R * DodecahedronL2R);
    case EShape::TruncatedCube:
        return new TruncatedCube(D, D / 3);
    case EShape::Prism6:
        return new Prism6(R, D);
    case EShape::Pyramid6:
        return new Pyramid6(R, D, 1.3f);
    case EShape::Pyramid4:
        return new Pyramid4(D, D, 1.3f);
    case EShape::Bipyramid4:
        return new Bipyramid4(D, R * 3 / 2, 2.f / 3, 2);
    case EShape::Prism3:
        return new Prism3(R, D);
    case EShape::Pyramid3:
        return new Pyramid3(R, D, 1.3f);
    case EShape::EllipsoidalCylinder:
        return new EllipsoidalCylinder(R, R / 2, D);
    case EShape::HemiEllipsoid:
        return new HemiEllipsoid(R, R, D);
    case EShape::CosineRippleBox:
        return new CosineRippleBox(D, D, D); // TODO ripples should be elongated
    case EShape::CosineRippleGauss:
        return new CosineRippleGauss(D, D, D); // TODO ripples should be elongated
    case EShape::CosineRippleLorentz:
        return new CosineRippleLorentz(D, D, D); // TODO ripples should be elongated
    case EShape::SawtoothRippleBox:
        return new SawtoothRippleBox(D, D, D); // TODO ripples should be elongated
    case EShape::SawtoothRippleGauss:
        return new SawtoothRippleGauss(D, D, D); // TODO ripples should be elongated
    case EShape::SawtoothRippleLorentz:
        return new SawtoothRippleLorentz(D, D, D); // TODO ripples should be elongated
    case EShape::CantellatedCube:
        return new CantellatedCube(D, D / 3);
    case EShape::HorizontalCylinder:
        return new HorizontalCylinder(R, D, -R, R);
    case EShape::PlatonicOctahedron:
        return new PlatonicOctahedron(D);
    case EShape::PlatonicTetrahedron:
        return new PlatonicTetrahedron(D);
    case EShape::Pyramid2:
        return new Pyramid2(R, D, D, 1.3f);
    }
    return nullptr;
}

void Model::emplaceSolidBody(PlottableBody* o)
{
    ASSERT(o);
    m_objects.emplace_back(o);
}

void Model::emplaceTransparentBody(PlottableBody* o)
{
    ASSERT(o);
    m_transparentObjects.emplace_back(o);
}

void Model::releaseGeometries()
{
    for (auto* o : m_objects)
        o->releaseGeometry();
    for (auto* o : m_transparentObjects)
        o->releaseGeometry();
}

bool Model::modelIsEmpty() const
{
    return m_objects.empty() && m_transparentObjects.empty();
}

} // namespace Img3D
