using SAP2000v1;
using FeMM.Common.Models;
using FeMM.Grasshopper.DataTypes.FeMM;
using FeMM.Grasshopper.Helpers;
using Grasshopper.Kernel;
using Rhino.Geometry;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Versioning;

// In order to load the result of this wizard, you will also need to
// add the output bin/ folder of this project to the list of loaded
// folder in Grasshopper.
// You can use the _GrasshopperDeveloperSettings Rhino command for that.

namespace FeMM.Grasshopper.Components.SAPExtra
{
#if NETCOREAPP
    [SupportedOSPlatform("windows")]
#endif
    public class SAPNodeLoaderComponent : GH_Component
    {
        /// <summary>
        /// Each implementation of GH_Component must provide a public 
        /// constructor without any arguments.
        /// Category represents the Tab in which the component will appear, 
        /// Subcategory the panel. If you use non-existing tab or panel names, 
        /// new tabs/panels will automatically be created.
        /// </summary>
        public SAPNodeLoaderComponent()
          : base("Node Loader", "NLC", "SAP Node Loader", CategoryNameConstants.CATEGORY_CHECKS, CategoryNameConstants.SUBCATEGORY_SAPEXTRA)
        {
            _run = false;
        }

        bool _run;

        public override void CreateAttributes()
        {
            var attr = new ComponentAttributes.ComponentOneButtonAttributes(this, "Run");
            attr.ButtonPressed += () =>
            {
                _run = true;
                ExpireSolution(true);
            };
            m_attributes = attr;
        }

        /// <summary>
        /// Registers all the input parameters for this component.
        /// </summary>
        protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager)
        {
            pManager.AddGenericParameter("Nodes", "N", "FEMM Nodes", GH_ParamAccess.list);
            pManager.AddTextParameter("Path SAP Model", "P", "", GH_ParamAccess.item);
            int j = pManager.AddTextParameter("Load Pattern", "LP", "Load Patterns to copy. If is empty, copy all load patterns", GH_ParamAccess.list, new List<string>());
            pManager[j].Optional = true;
            int i = pManager.AddTextParameter("SapExe", "S", "sap2000 exe fullpath", GH_ParamAccess.item);
            pManager[i].Optional = true;
        }

        /// <summary>
        /// Registers all the output parameters for this component.
        /// </summary>
        protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager)
        {
            pManager.AddGenericParameter("Nodes", "N", "", GH_ParamAccess.list);
            pManager.AddTextParameter("dev", "dev", "", GH_ParamAccess.item);
        }

        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object can be used to retrieve data from input parameters and 
        /// to store data in output parameters.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            var nodes = new List<GH_Node>();
            string path = "";
            var load_patterns = new List<string>();
            string sapExe = "";

            if (!DA.GetDataList(0, nodes))
                return;
            if (!DA.GetData(1, ref path))
                return;
            DA.GetDataList(2, load_patterns);
            DA.GetData(3, ref sapExe);

            if (_run)
            {
                var new_nodes = new List<GH_Node>();
                for (int i = 0; i < nodes.Count; i++)
                {
                    new_nodes.Add(new GH_Node(nodes[i]));
                }
                string dev = "";
                LoadNodes(sapExe, path, load_patterns, ref new_nodes, ref dev);

                DA.SetDataList(0, new_nodes);
                DA.SetData(1, dev);
            }

            _run = false;
        }

        /// <summary>
        /// Provides an Icon for every component that will be visible in the User Interface.
        /// Icons need to be 24x24 pixels.
        /// </summary>
        protected override System.Drawing.Bitmap Icon => Properties.Resources.SAPNodeLoaderIcon;

        /// <summary>
        /// Each component must have a unique Guid to identify it. 
        /// It is vital this Guid doesn't change otherwise old ghx files 
        /// that use the old ID will partially fail during loading.
        /// </summary>
        public override Guid ComponentGuid => new("a8923d60-824f-4036-abf3-3dee3751a9c2");

        public void LoadNodes(string sapExe, string path_model, List<string> load_patterns, ref List<GH_Node> new_nodes, ref string dev)
        {
            bool AttachToInstance = false;
            int ret = 0;

            if (!ExtraSapHelper.InitializeModel(!AttachToInstance, sapExe, path_model, out cOAPI mySapObject, out cSapModel mySapModel, out cHelper myHelper))
                return;

            bool exportAll = false;
            if (load_patterns == null || load_patterns.Count == 0)
                exportAll = true;

            //get name list of all nodes
            int nodes_nr = -1;
            string[] nodes_name = [];
            ret = mySapObject.SapModel.PointObj.GetNameList(ref nodes_nr, ref nodes_name);
            var nodes_name_list = new List<string>(nodes_name);

            int tot = mySapObject.SapModel.PointObj.Count();
            if (tot != nodes_nr || tot != nodes_name_list.Distinct().ToList().Count)
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Plese add unique ID to all nodes!");
                return;
            }

            for (int i = 0; i < nodes_nr; i++)
            {
                //search in selected beam if have same name
                int j_iter = -1;
                for (int j = 0; j < new_nodes.Count; j++)
                {
                    ElementIdAttributeModel attr;
                    try
                    {
                        attr = (ElementIdAttributeModel)new_nodes[j].Value.Attributes.Where(a => a is ElementIdAttributeModel).First();
                    }
                    catch (Exception)
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Add ID to nodes!");
                        return;
                    }

                    if (attr.Value == nodes_name[i])
                    {
                        j_iter = j;
                        j = new_nodes.Count(); //exit
                    }
                }
                if (j_iter >= 0) //I have found
                {
                    //dev = dev + " " + beams_name[i] + "\n";
                    int nr_load = -1;
                    string[] node_name = [];
                    string[] load_pat = [];
                    int[] my_type = [];
                    int[] LC_step = [];
                    string[] c_sys = [];
                    double[] F1 = [];
                    double[] F2 = [];
                    double[] F3 = [];
                    double[] M1 = [];
                    double[] M2 = [];
                    double[] M3 = [];

                    ret = mySapObject.SapModel.PointObj.GetLoadForce(nodes_name[i], ref nr_load, ref node_name, ref load_pat, ref LC_step, ref c_sys, ref F1, ref F2, ref F3, ref M1, ref M2, ref M3);

                    for (int j = 0; j < nr_load; j++)
                    {
                        if (load_patterns.Contains(load_pat[j]) || exportAll)
                        {
                            if (c_sys[j] != "GLOBAL")
                            {
                                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Forces/Moments on local axis not supported");
                                return;
                            }
                            dev = dev + " name = " + node_name[j] + "\n";
                            dev = dev + " load pattern = " + load_pat[j] + "\n";
                            dev = dev + " LC step = " + LC_step[j] + "\n";
                            dev = dev + " c sys = " + c_sys[j] + "\n";
                            dev = dev + " F1 = " + F1[j] + "\n";
                            dev = dev + " F2 = " + F2[j] + "\n";
                            dev = dev + " F3 = " + F3[j] + "\n";
                            dev = dev + " M1 = " + M1[j] + "\n";
                            dev = dev + " M2 = " + M2[j] + "\n";
                            dev = dev + " M3 = " + M3[j] + "\n \n";

                            //Add load to new points
                            string id = load_pat[j];
                            string name = load_pat[j];
                            var loadCase = new LoadCaseModel(-1, name);


                            if (F1[j] != 0 || F2[j] != 0 || F3[j] != 0)
                            {
                                var load_force = new NodeForceLoadModel(loadCase, new Vector3d(F1[j], F2[j], F3[j]));
                                new_nodes[j_iter].Value.Loads.Add(load_force);
                            }

                            if (M1[j] != 0 || M2[j] != 0 || M3[j] != 0)
                            {
                                var load_moment = new NodeMomentLoadModel(loadCase, new Vector3d(M1[j], M2[j], M3[j]));
                                new_nodes[j_iter].Value.Loads.Add(load_moment);
                            }
                        }
                    }
                }
            }
            mySapObject.ApplicationExit(false);
        }
    }
}

303 files24 directories