using FeMM.Common.Helpers;
using FeMM.Common.Models;
using FeMM.Grasshopper.Components.Parameters;
using FeMM.Grasshopper.DataTypes.FeMM;
using FeMM.Grasshopper.Helpers;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Parameters;
using Grasshopper.Kernel.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Versioning;

namespace FeMM.Grasshopper.Components.Models
{
#if NETCOREAPP
    [SupportedOSPlatform("windows")]
#endif
    public class BuildModelComponent : GH_Component
    {
        /// <summary>
        /// Initializes a new instance of the BuildModelComponent class.
        /// </summary>
        public BuildModelComponent()
          : base("Build Model", "BM", "Build the FEM model", CategoryNameConstants.CATEGORY_FEMM, CategoryNameConstants.SUBCATEGORY_MODEL)
        {
        }

        /// <summary>
        /// Registers all the input parameters for this component.
        /// </summary>
        protected override void RegisterInputParams(GH_InputParamManager pManager)
        {
            pManager.AddGenericParameter("Elements", "E", "The model elements", GH_ParamAccess.list);
            pManager.AddTextParameter("Name", "N", "The name of the model", GH_ParamAccess.item, "");
            pManager.AddIntegerParameter("Units", "U", "The measure units", GH_ParamAccess.item, 2);
            Param_Integer type_param = (Param_Integer)pManager[2];
            Array names = Enum.GetValues(typeof(ModelModel.ModelUnits));
            foreach (ModelModel.ModelUnits name in names)
                type_param.AddNamedValue(name.GetDescription(), (int)name);
            int i = pManager.AddGenericParameter("Cases/Combinations", "LCB", "The load cases and combinations list", GH_ParamAccess.list);
            pManager[i].Optional = true;
            pManager.AddGenericParameter("Functions/Definitions", "FD", "The analysis functions and definitions", GH_ParamAccess.list);
            pManager[pManager.ParamCount - 1].Optional = true;
        }

        /// <summary>
        /// Registers all the output parameters for this component.
        /// </summary>
        protected override void RegisterOutputParams(GH_OutputParamManager pManager)
        {
            pManager.AddGenericParameter("Model", "M", "The FEM model", GH_ParamAccess.item);
        }

        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            try
            {
                var elements = new List<IGH_GeometricGoo>();
                string name = "";
                int units = 0;
                var objs = new List<object>();
                var functions = new List<GH_FunctionDefinition>();

                if (!DA.GetDataList(0, elements))
                    return;
                DA.GetData(1, ref name);
                if (!DA.GetData(2, ref units))
                    return;
                bool hasCombo = DA.GetDataList(3, objs);
                bool hasFunction = DA.GetDataList(4, functions);

                var inputCases = new List<CaseModel>();
                for (int i = 0; i < objs.Count; i++)
                {
                    if (objs[i] is GH_Case gH_Case)
                    {
                        if (gH_Case.Value is StagedConstructionCombinationModel stagedConstructionModel)
                            inputCases.Add(stagedConstructionModel);
                        else if (gH_Case.Value is StageConstructionLoadCaseModel stageConstructionLoadCaseModel)
                            inputCases.Add(stageConstructionLoadCaseModel);
                        else if (gH_Case.Value is LoadCaseModel loadCaseModel)
                            inputCases.Add(loadCaseModel);
                        else if (gH_Case.Value is LoadCaseLinearStaticSAPModel loadCaseLinearStaticSAPModel)
                            inputCases.Add(loadCaseLinearStaticSAPModel);
                        else if (gH_Case.Value is LoadCaseResponseSpectrumModel loadCaseResponseSpectrumModel)
                            inputCases.Add(loadCaseResponseSpectrumModel);
                        else if (gH_Case.Value is FreedomCaseModel freedomCaseModel)
                            inputCases.Add(freedomCaseModel);
                        else if (gH_Case.Value is ModalEigenModel modalEigenModel)
                            inputCases.Add(modalEigenModel);
                        else if (gH_Case.Value is ModalRitzModel modalRitzModel)
                            inputCases.Add(modalRitzModel);
                    }
                    else if (objs[i] is GH_Combination gH_Combination)
                    {
                        if (gH_Combination.Value is FreedomCaseCombinationModel freedomCaseCombinationModel)
                            inputCases.Add(freedomCaseCombinationModel);
                        else if (gH_Combination.Value is LoadCaseCombinationModel loadCaseCombinationModel)
                            inputCases.Add(loadCaseCombinationModel);
                    }
                }

                var cases = new List<CaseModel>();
                Helpers.ModelHelper.ParseElements(elements, out List<GH_Node> nodes, out List<GH_Beam> beams, out List<GH_Plate> plates, out List<GH_Link> links);
                Helpers.ModelHelper.GetCases(nodes, beams, plates, out List<CaseModel> loadCases);
                Common.Helpers.CommonModelHelper.GetStagedConstructionConstructionModel(inputCases, out List<StagedConstructionCombinationModel> stagedConstr);
                Common.Helpers.CommonModelHelper.GetStagedModelModel([.. functions.Select(i => i.Value)], out List<StagedModel> stagedModels);
                Common.Helpers.CommonModelHelper.GetStageConstructionLoadCaseModel(inputCases, out List<StageConstructionLoadCaseModel> stageConstructionLoadCaseModels);
                Common.Helpers.CommonModelHelper.GetLoadCombinations(inputCases, out List<LoadCaseCombinationModel>  loadComb);
                Common.Helpers.CommonModelHelper.GetLoadCaseLinearStaticSAPModel(inputCases, out List<LoadCaseLinearStaticSAPModel> lcls);
                Common.Helpers.CommonModelHelper.GetLoadCaseResponseSpectrumModel(inputCases, out List<LoadCaseResponseSpectrumModel> lclm);
                var cccase = new List<CaseModel>();
                for (int i = 0; i < inputCases.Count; i++)
                {
                    if (inputCases[i] is ModalEigenModel modalEigenModel)
                        cccase.Add(modalEigenModel);
                    else if (inputCases[i] is ModalRitzModel modalRitzModel)
                        cccase.Add(modalRitzModel);
                }
                List<FreedomCaseModel> freedomCases = Helpers.ModelHelper.GetFreedomCases(nodes, beams, plates, inputCases);
                cases.AddRange(loadCases);
                cases.AddRange(freedomCases);
                cases.AddRange(loadComb);
                cases.AddRange(lcls);
                cases.AddRange(lclm);
                cases.AddRange(cccase);

                if (hasCombo)
                {
                    // Check the load cases names if the combinatoin is provided
                    var cc = cases.Where(j => j != null).Where(i => i.GetType() == typeof(LoadCaseCombinationModel)).ToArray();
                    if (cc.Length > 0)
                    {
                        LoadCaseCombinationModel[] cmbs = [.. cc.Where(i => i is LoadCaseCombinationModel).Select(i => (LoadCaseCombinationModel)i)];
                        var lcases = cmbs.SelectMany(c => c.Values.Keys).Select(lc => lc).Distinct().ToArray();

                        if (lcases.Length > 0)
                        {
                            for (int i = 0; i < lcases.Length; i++)
                            {
                                string lcase = lcases[i].Name;
                                if (!cases.Any(lc => lc.Name == lcase) && lcases[i].GetType() != typeof(StageConstructionLoadCaseModel) && lcases[i].GetType() != typeof(LoadCaseCombinationModel)
                                    && lcases[i].GetType() != typeof(FreedomCaseModel))
                                {
                                    AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, $"The load case {lcase} don't have associated load.");
                                    cases.Add(lcases[i]);
                                }
                            }
                        }
                    }

                    var fcc = cases.Where(j => j != null).Where(i => i.GetType() == typeof(FreedomCaseCombinationModel)).ToArray();
                    if (fcc.Length > 0)
                    {
                        FreedomCaseCombinationModel[] cmbs = [.. cc.Where(i => i is FreedomCaseCombinationModel).Select(i => (FreedomCaseCombinationModel)i)];
                        CaseModel[] lcases = [.. cmbs.SelectMany(c => c.Values.Keys).Select(lc => lc).Distinct()];

                        if (lcases.Length > 0)
                        {
                            for (int i = 0; i < lcases.Length; i++)
                            {
                                string lcase = lcases[i].Name;
                                if (!cases.Any(lc => lc.Name == lcase))
                                {
                                    AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, $"The load case {lcase} don't have associated load.");
                                    cases.Add(lcases[i]);
                                }
                            }
                        }
                    }
                }

                cases.AddRange(stagedConstr);
                cases.AddRange(stageConstructionLoadCaseModels);

                // Connect the LoadCombinationsComponent
                IGH_Param[] combinations_params = [.. Params.Input[3].Sources.Where(s => s.GetType() == typeof(LoadCombinationsParam))];
                for (int i = 0; i < combinations_params.Length; i++)
                {
                    LoadCombinationsParam param = (LoadCombinationsParam)combinations_params[i];
                    param.UpdateLoadCases(cases);
                }

                var model = new GH_Model((ModelModel.ModelUnits)units, nodes, beams, plates, links, cases, [.. functions.Select(i => i.Value)]);
                model.Value.Name = name;

                Message = ((ModelModel.ModelUnits)units).GetDescription();
                DA.SetData(0, model);
            }
            catch (Exception e)
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.Message);
            }
        }

        public override GH_Exposure Exposure => GH_Exposure.tertiary;

        /// <summary>
        /// Provides an Icon for the component.
        /// </summary>
        protected override System.Drawing.Bitmap Icon => Properties.Resources.BuildModelIcon;

        /// <summary>
        /// Gets the unique ID for this component. Do not change this ID after release.
        /// </summary>
        public override Guid ComponentGuid => new("c3c8837b-57fa-4fdc-8b99-849bfe468232");
    }
}
303 files24 directories