#include "EOFBlockTemplate.h"

#include <GC_MakeSegment.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Shell.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopTools_MapOfShape.hxx>
#include <BRepAlgoAPI_BuilderAlgo.hxx>
#include <STEPControl_Writer.hxx>
#include <TopExp_Explorer.hxx>
#include <GProp_GProps.hxx>
#include <BRepGProp.hxx>
#include <BRepPrimAPI_MakeSphere.hxx>
#include <BRepPrimAPI_MakePrism.hxx>
#include <BRepBuilderAPI_MakeSolid.hxx>
#include <BRepBndLib.hxx>
#include <BRepTools.hxx>
#include <map>
#include <filesystem>

#include "topology/ShapeAlgorithms.h"
#include "misc/miscFunctions.hpp"
#include "vtkForCenos/topologyToVTK.h"
#include "mesh/MeshGenerator.h"
#include "mesh/AutoMeshSize.h"

EOFBlockTemplate::EOFBlockTemplate(std::string path) : BasicTemplate(path)
{
    type = BLOCK;
}

void EOFBlockTemplate::parseInputJSON(json* j)
{
    json& data = *j;
    name = data["name"].get<std::string>();
    f_l = data["properties"]["f_l"];
    f_w = data["properties"]["f_w"];
    f_h = data["properties"]["f_h"];
    
    
}


TopoDS_Solid EOFBlockTemplate::makeMelt() {
    gp_Pnt boxPnt1(-f_w , 0, 0);
    gp_Pnt boxPnt2(0, f_l, f_h);
    BRepPrimAPI_MakeBox substrate_box(boxPnt1, boxPnt2);
    substrate_box.Build();

    TopoDS_Solid substrate_solid = substrate_box.Solid();
    return substrate_solid;
}






void EOFBlockTemplate::generateGeometry()
{
    if (progress != nullptr)
        progress->sendLog("Generating melt geometry ");

    

    TopoDS_Solid melt_solid = makeMelt();
    TopoEntity_ melt_ent = std::make_shared<TopoEntity>(melt_solid, "melt");
    geom_data->addEntity(melt_ent);

    DomainGroup_ melt_group = std::make_shared<DomainGroup>();
    melt_group->setName("melt");
    melt_group->setLabel("Melt");
    melt_group->setRole("melt");
    melt_group->addEntity(melt_ent);
    melt_group->update();
    geom_data->addDomainGroup(melt_group);


    BoundaryGroup_ bc_group = std::make_shared<BoundaryGroup>();
    bc_group->setName("melt_boundary");
    bc_group->setLabel("Melt Boundary");
    bc_group->setRole("");

    int sh_nr = 0;
    for (TopExp_Explorer explorer(melt_solid, TopAbs_FACE); explorer.More(); explorer.Next())
    {
        TopoEntity_ ent = std::make_shared<TopoEntity>(explorer.Current(), "melt_boundary_ent" + std::to_string(++sh_nr));
        geom_data->addEntity(ent);
        bc_group->addEntity(ent);
    }

    bc_group->update();
    geom_data->addBoundaryGroup(bc_group);
}

void EOFBlockTemplate::assignMeshSizes(MeshGenerator_ mg, GeometryData_ gd, double mesh_density_factor, double global_max)
{
    // melt mesh sizing
    std::shared_ptr<MeshParameters> mp_melt = std::make_shared<MeshParameters>();
    double maxh_local = std::min({ global_max, f_l / 4, f_w / 4, f_w/2 });
    double minh_local = std::min(f_w / 2, f_h/1) / 2;

    if (minh_local * 1.5 > maxh_local)
        minh_local = minh_local / 2;


 //   mp_melt->calculateLayers(f_l/100, f_l/50);


    mp_melt->setMaxH(maxh_local * mesh_density_factor);
    mp_melt->setMinH(minh_local * mesh_density_factor);

    // assign mp_substrate to entities and subentities of substrate
    auto s_group = gd->getDomainByName("melt");
    for (auto ent : s_group->getEntities())
    {
        mg->setParameters(mp_melt, ent);
        for (auto subent : gd->getEntities())
        {
            if (subent->isSubShapeOf(ent))
                mg->setParameters(mp_melt, subent);
        }
    }
}

bool EOFBlockTemplate::validate(std::string& msg)
{

    if (f_w <= 0)
    {
        msg = "Substrate width should be positive number.";
        return false;
    }
    if (f_l <= 0)
    {
        msg = "Substrate length should be positive number.";
        return false;
    }
    if (f_l <= 0)
    {
        msg = "Substrate height should be positive number.";
        return false;
    }
  return true;
}


