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

#include "GUI/Model/Sample/FormfactorsCatalog.h"
#include "Base/Util/Assert.h"
#include "GUI/Model/Sample/FormFactorItems.h"

FormFactorItem* FormfactorsCatalog::create(Type type)
{
#define CREATE(t)                                                                                  \
    case Type::t:                                                                                  \
        return new t##Item()

    switch (type) {
        CREATE(BarGauss);
        CREATE(BarLorentz);
        CREATE(Bipyramid4);
        CREATE(Box);
        CREATE(CantellatedCube);
        CREATE(Cone);
        CREATE(CosineRippleBox);
        CREATE(CosineRippleGauss);
        CREATE(CosineRippleLorentz);
        CREATE(Cylinder);
        CREATE(Dodecahedron);
        CREATE(EllipsoidalCylinder);
        CREATE(Sphere);
        CREATE(Spheroid);
        CREATE(HemiEllipsoid);
        CREATE(HorizontalCylinder);
        CREATE(Icosahedron);
        CREATE(PlatonicOctahedron);
        CREATE(PlatonicTetrahedron);
        CREATE(Prism3);
        CREATE(Prism6);
        CREATE(Pyramid2);
        CREATE(Pyramid3);
        CREATE(Pyramid4);
        CREATE(Pyramid6);
        CREATE(SawtoothRippleBox);
        CREATE(SawtoothRippleGauss);
        CREATE(SawtoothRippleLorentz);
        CREATE(TruncatedCube);
        CREATE(TruncatedSphere);
        CREATE(TruncatedSpheroid);
    default:
        ASSERT_NEVER;
    }

#undef CREATE
}

QVector<FormfactorsCatalog::Type> FormfactorsCatalog::types()
{
    return {Type::BarGauss,
            Type::BarLorentz,
            Type::Bipyramid4,
            Type::Box,
            Type::CantellatedCube,
            Type::Cone,
            Type::CosineRippleBox,
            Type::CosineRippleGauss,
            Type::CosineRippleLorentz,
            Type::Cylinder,
            Type::Dodecahedron,
            Type::EllipsoidalCylinder,
            Type::Sphere,
            Type::Spheroid,
            Type::HemiEllipsoid,
            Type::HorizontalCylinder,
            Type::Icosahedron,
            Type::PlatonicOctahedron,
            Type::PlatonicTetrahedron,
            Type::Prism3,
            Type::Prism6,
            Type::Pyramid2,
            Type::Pyramid3,
            Type::Pyramid4,
            Type::Pyramid6,
            Type::SawtoothRippleBox,
            Type::SawtoothRippleGauss,
            Type::SawtoothRippleLorentz,
            Type::TruncatedCube,
            Type::TruncatedSphere,
            Type::TruncatedSpheroid};
}

QVector<FormfactorsCatalog::Type> FormfactorsCatalog::hardParticleTypes()
{
    return {Type::Bipyramid4,
            Type::Box,
            Type::CantellatedCube,
            Type::Cone,
            Type::Cylinder,
            Type::Dodecahedron,
            Type::EllipsoidalCylinder,
            Type::Sphere,
            Type::Spheroid,
            Type::HemiEllipsoid,
            Type::HorizontalCylinder,
            Type::Icosahedron,
            Type::PlatonicOctahedron,
            Type::PlatonicTetrahedron,
            Type::Prism3,
            Type::Prism6,
            Type::Pyramid2,
            Type::Pyramid3,
            Type::Pyramid4,
            Type::Pyramid6,
            Type::TruncatedCube,
            Type::TruncatedSphere,
            Type::TruncatedSpheroid};
}


QVector<FormfactorsCatalog::Type> FormfactorsCatalog::rippleTypes()
{
    return {Type::BarGauss,          Type::BarLorentz,          Type::Box,
            Type::CosineRippleBox,   Type::CosineRippleGauss,   Type::CosineRippleLorentz,
            Type::SawtoothRippleBox, Type::SawtoothRippleGauss, Type::SawtoothRippleLorentz};
}

UiInfo FormfactorsCatalog::uiInfo(Type type)
{
    switch (type) {
    case Type::Pyramid2:
        return {"Anisotropic pyramid", "Truncated pyramid with a rectangular base",
                ":/images/ff_Pyramid2_64x64.png"};

    case Type::BarGauss:
        return {"BarGauss", "Rectangular cuboid", ":/images/ff_Box_64x64.png"};

    case Type::BarLorentz:
        return {"BarLorentz", "Rectangular cuboid", ":/images/ff_Box_64x64.png"};

    case Type::Box:
        return {"Box", "Rectangular cuboid", ":/images/ff_Box_64x64.png"};

    case Type::Cone:
        return {"Cone", "Truncated cone with circular base", ":/images/ff_Cone_64x64.png"};

    case Type::Pyramid6:
        return {"Pyramid6", "A truncated pyramid, based on a regular hexagon",
                ":/images/ff_Pyramid6_64x64.png"};

    case Type::Bipyramid4:
        return {"Bipyramid4",
                "Compound of two truncated pyramids with a common square base "
                "and opposite orientations",
                ":/images/ff_Bipyramid4_64x64.png"};

    case Type::Dodecahedron:
        return {"Dodecahedron", "Dodecahedron", ":/images/ff_Dodecahedron_64x64.png"};

    case Type::Cylinder:
        return {"Cylinder", "Cylinder with a circular base", ":/images/ff_Cylinder_64x64.png"};

    case Type::EllipsoidalCylinder:
        return {"Ellipsoidal cylinder", "Cylinder with an ellipse cross section",
                ":/images/ff_EllipsoidalCylinder_64x64.png"};

    case Type::Sphere:
        return {"Full sphere", "Full sphere", ":/images/ff_Sphere_64x64.png"};

    case Type::Spheroid:
        return {"Full spheroid",
                "Full spheroid, generated by rotating an ellipse around the vertical axis",
                ":/images/ff_Spheroid_64x64.png"};

    case Type::HemiEllipsoid:
        return {"Hemi ellipsoid",
                "A horizontally oriented ellipsoid, truncated at the central plane",
                ":/images/ff_HemiEllipsoid_64x64.png"};

    case Type::Icosahedron:
        return {"Icosahedron", "Icosahedron", ":/images/ff_Icosahedron_64x64.png"};

    case Type::Prism3:
        return {"Prism3", "Prism with an equilateral triangle base",
                ":/images/ff_Prism3_64x64.png"};

    case Type::Prism6:
        return {"Prism6", "Prism with a regular hexagonal base", ":/images/ff_Prism6_64x64.png"};

    case Type::Pyramid4:
        return {"Pyramid4", "Truncated pyramid with a square base",
                ":/images/ff_Pyramid4_64x64.png"};

    case Type::CosineRippleBox:
        return {"CosineRippleBox", "Particle with a cosine profile and a rectangular base",
                ":/images/ff_CosineRipple_64x64.png"};

    case Type::CosineRippleGauss:
        return {"CosineRippleGauss", "Particle with a cosine profile and a rectangular base",
                ":/images/ff_CosineRipple_64x64.png"};

    case Type::CosineRippleLorentz:
        return {"CosineRippleLorentz", "Particle with a cosine profile and a rectangular base",
                ":/images/ff_CosineRipple_64x64.png"};

    case Type::SawtoothRippleBox:
        return {"SawtoothRippleBox",
                "Particle with an asymmetric triangle profile and a rectangular base",
                ":/images/ff_SawtoothRipple_64x64.png"};

    case Type::SawtoothRippleGauss:
        return {"SawtoothRippleGauss",
                "Particle with an asymmetric triangle profile and a rectangular base",
                ":/images/ff_SawtoothRipple_64x64.png"};

    case Type::SawtoothRippleLorentz:
        return {"SawtoothRippleLorentz",
                "Particle with an asymmetric triangle profile and a rectangular base",
                ":/images/ff_SawtoothRipple_64x64.png"};

    case Type::Pyramid3:
        return {"Pyramid3",
                "Truncated polyhedron with equilateral triangle base and cropped side faces",
                ":/images/ff_Pyramid3_64x64.png"};

    case Type::TruncatedCube:
        return {"Truncated cube", "A cube whose eight vertices have been removed",
                ":/images/ff_TruncatedCube_64x64.png"};

    case Type::TruncatedSphere:
        return {"Truncated sphere", "Spherical dome", ":/images/ff_TruncatedSphere_64x64.png"};

    case Type::TruncatedSpheroid:
        return {"Truncated spheroid", "Spheroidal dome", ":/images/ff_TruncatedSpheroid_64x64.png"};

    case Type::CantellatedCube:
        return {"Cantellated cube", "A cube with truncated edges and vertices",
                ":/images/ff_CantellatedCube_64x64.png"};

    case Type::HorizontalCylinder:
        return {"Horizontal cylinder", "Cylinder with a circular base, lying in x direction",
                ":/images/ff_HorizontalCylinder_64x64.png"};

    case Type::PlatonicOctahedron:
        return {"Platonic octahedron", "Regular octahedron",
                ":/images/ff_PlatonicOctahedron_64x64.png"};

    case Type::PlatonicTetrahedron:
        return {"Platonic tetrahedron", "Regular tetrahedron",
                ":/images/ff_PlatonicTetrahedron_64x64.png"};

    default:
        ASSERT_NEVER;
    }
}

FormfactorsCatalog::Type FormfactorsCatalog::type(const FormFactorItem* item)
{
    ASSERT(item);

#define RETURN_IF(type)                                                                            \
    if (dynamic_cast<const type##Item*>(item))                                                     \
    return Type::type

    RETURN_IF(BarGauss);
    RETURN_IF(BarLorentz);
    RETURN_IF(Bipyramid4);
    RETURN_IF(Box);
    RETURN_IF(CantellatedCube);
    RETURN_IF(Cone);
    RETURN_IF(CosineRippleBox);
    RETURN_IF(CosineRippleGauss);
    RETURN_IF(CosineRippleLorentz);
    RETURN_IF(Cylinder);
    RETURN_IF(Dodecahedron);
    RETURN_IF(EllipsoidalCylinder);
    RETURN_IF(Sphere);
    RETURN_IF(Spheroid);
    RETURN_IF(HemiEllipsoid);
    RETURN_IF(HorizontalCylinder);
    RETURN_IF(Icosahedron);
    RETURN_IF(PlatonicOctahedron);
    RETURN_IF(PlatonicTetrahedron);
    RETURN_IF(Prism3);
    RETURN_IF(Prism6);
    RETURN_IF(Pyramid2);
    RETURN_IF(Pyramid3);
    RETURN_IF(Pyramid4);
    RETURN_IF(Pyramid6);
    RETURN_IF(SawtoothRippleBox);
    RETURN_IF(SawtoothRippleGauss);
    RETURN_IF(SawtoothRippleLorentz);
    RETURN_IF(TruncatedCube);
    RETURN_IF(TruncatedSphere);
    RETURN_IF(TruncatedSpheroid);
#undef RETURN_IF
    ASSERT_NEVER;
}

QString FormfactorsCatalog::menuEntry(const FormFactorItem* item)
{
    return uiInfo(type(item)).menuEntry;
}
