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;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.Versioning;
using System.Windows.Forms;

namespace FeMM.Grasshopper.Components.SAPExtra
{
#if NETCOREAPP
    [SupportedOSPlatform("windows")]
#endif
    public class SAPBeamsLoaderResultsComponent : GH_Component
    {
        private bool _run;
        private ComponentAttributes.ComponentOneButtonAttributes _attr;
        private List<BeamModel> _output_beam;
        private List<string> _dev;

        /// <summary>
        /// Initializes a new instance of the FeMMBeamsLoaderResults class.
        /// </summary>
        public SAPBeamsLoaderResultsComponent()
          : base("Beams Loader Results", "SAP Beams Loader Results", "Get results after analysis in beams", CategoryNameConstants.CATEGORY_CHECKS, CategoryNameConstants.SUBCATEGORY_SAPEXTRA)
        {
            _run = false;
            _output_beam = [];
            _dev = [];
        }

        public override void CreateAttributes()
        {
            _attr = new ComponentAttributes.ComponentOneButtonAttributes(this, "Run");

            _attr.ButtonPressed += () =>
            {
                _attr.Text = "Running...";
                _output_beam = [];
                _run = true;
                _dev = [];

                ExpireSolution(true);
            };
            m_attributes = _attr;
        }

        /// <summary>
        /// Registers all the input parameters for this component.
        /// </summary>
        protected override void RegisterInputParams(GH_InputParamManager pManager)
        {
            pManager.AddGenericParameter("Beams", "B", "FeMM beam to read results", GH_ParamAccess.list);
            pManager.AddTextParameter("SapFile", "SapFile", "Sdb file runned", GH_ParamAccess.item, "");
            pManager.AddBooleanParameter("Attach to istance", "A", "If true, attach to the open SAP istance", GH_ParamAccess.item, false);
            pManager.AddGenericParameter("Load Cases", "LC", "Load case or Combo to be loaded", GH_ParamAccess.list);
        }

        /// <summary>
        /// Registers all the output parameters for this component.
        /// </summary>
        protected override void RegisterOutputParams(GH_OutputParamManager pManager)
        {
            pManager.AddGenericParameter("Beam", "B", "Loaded FeMM beam", GH_ParamAccess.list);
            pManager.AddGenericParameter("Log", "L", "Conversion log", GH_ParamAccess.list);
        }

        /// <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>
        /// 

        //var mre = new ManualResetEvent(false);

        protected override void SolveInstance(IGH_DataAccess DA)
        {
            if (_run)
            {
                if (_output_beam.Count() == 0) //result not yet processed
                {
                    var input_beam = new List<GH_Beam>();
                    var combo = new List<string>();
                    string sapfile = "";
                    bool attach = false;

                    if (!DA.GetDataList(0, input_beam))
                        return;
                    if (!DA.GetData(1, ref sapfile))
                        return;
                    if (!DA.GetData(2, ref attach))
                        return;
                    if (!DA.GetDataList(3, combo))
                        return;

                    var worker = new BackgroundWorker();
                    var parameters = new Hashtable
                    {
                        { "sapfile", sapfile },
                        { "combo", combo },
                        { "input_beam", input_beam },
                        { "attach", attach }
                    };

                    worker.DoWork += Execute;
                    worker.RunWorkerAsync(parameters);
                    worker.RunWorkerCompleted += finish;

                    void finish(object sender, RunWorkerCompletedEventArgs e)
                    {
                        ExpireSolution(true);
                        return;
                    }
                }
                else
                {
                    var out_b = new List<GH_Beam>();
                    for (int i = 0; i < _output_beam.Count; i++)
                        out_b.Add(new GH_Beam(_output_beam[i]));

                    if (out_b.Count == 0)
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "No beams selected");

                    DA.SetDataList(0, out_b);
                    DA.SetDataList(1, _dev);
                    _run = false;
                }
            }
        }

        public void Execute(object sender, DoWorkEventArgs e)
        {
            Hashtable parameters = e.Argument as Hashtable;
            string sapfile = parameters["sapfile"].ToString();
            bool attach = (bool)parameters["attach"];
            List<string> combo = (List<string>)parameters["combo"];
            List<GH_Beam> input_beam = (List<GH_Beam>)parameters["input_beam"];

            ExternalProgram.CSIComObjects.InizializeSAPModel(out cSapModel mySapModel, out cOAPI mySapObject, out cHelper myHelper,
                attach, sapfile, eUnits.N_mm_C, true);

            if (mySapModel == null)
            {
                MessageBox.Show("Error open SAP2000");
                _run = false;
                return;
            }

            bool runned = mySapObject.SapModel.GetModelIsLocked();
            if (runned == false)
            {
                MessageBox.Show("Please run the analysis!");
                _run = false;
                return;
            }

            //clear all case and combo output selections
            if (mySapObject.SapModel.Results.Setup.DeselectAllCasesAndCombosForOutput() != 0)
            {
                MessageBox.Show("Error deselect previous combo for output");
                _run = false;
                return;
            }

            //set case and combo output selections
            for (int i = 0; i < combo.Count; i++)
            {
                if (mySapObject.SapModel.Results.Setup.SetCaseSelectedForOutput(combo[i]) != 0)
                {
                    if (mySapObject.SapModel.Results.Setup.SetComboSelectedForOutput(combo[i]) != 0)
                    {
                        MessageBox.Show("Error set combo/load case of output");
                        _run = false;
                        return;
                    }
                }
            }

            //delete all old results of beam
            for (int i = 0; i < input_beam.Count; i++)
            {
                input_beam[i].Value.Results.Clear();
            }

            //get all beams
            int nr_frame = 0;
            string[] name_frame = [];
            if (mySapObject.SapModel.FrameObj.GetNameList(ref nr_frame, ref name_frame) != 0)
            {
                MessageBox.Show("Error get beams");
                _run = false;
                return;
            }

            //check if double beams in input or if beams without ID
            var unique_label = new HashSet<string>();
            //Parallel.For(0, input_beam.Count, 
            for (int k = 0; k < input_beam.Count; k++)
            {
                try
                {
                    ElementIdAttributeModel attr = (ElementIdAttributeModel)input_beam[k].Value.Attributes.Where(a => a is ElementIdAttributeModel).First();
                    unique_label.Add(attr.Value);
                    if (k >= unique_label.Count)
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Duplicate beam! " + attr.Value);
                        _run = false; return;
                    }
                }
                catch (Exception)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Please add ID to beam");
                    _run = false; return;
                }
            }

            string[] labels = [.. unique_label];

            //get frame forces foreach beam
            var _obj = new object();
            int iter = 0;

            for (int i = 0; i < input_beam.Count; i++)
            {
                bool found = false;
                string label = labels[i];

                for (int k = 0; k < nr_frame; k++) //search for the right beam
                {
                    if (label == name_frame[k]) //right beam found!
                    {
                        found = true;
                        var new_beam = new BeamModel(input_beam[i].Value);
                        _output_beam.Add(new_beam); //Add to output beams
                        int index = _output_beam.Count - 1;
                        int number_result = 0;
                        string[] obj = [];
                        double[] obj_station = [];
                        string[] element = [];
                        double[] element_station = [];
                        string[] load_case = [];
                        string[] step_type = [];
                        double[] step_num = [];
                        double[] P = [];
                        double[] V2 = [];
                        double[] V3 = [];
                        double[] T = [];
                        double[] M2 = [];
                        double[] M3 = [];

                        if (mySapObject.SapModel.Results.FrameForce(label, eItemTypeElm.ObjectElm, ref number_result, ref obj, ref obj_station, ref element,
                            ref element_station, ref load_case, ref step_type, ref step_num, ref P, ref V2, ref V3, ref T, ref M2, ref M3) != 0)
                        {
                            MessageBox.Show("Error get forces for " + name_frame[k]);
                            _run = false;
                            return;
                        }

                        for (int j = 0; j < number_result; j++)
                        {
                            string dev = string.Empty;
                            dev = dev + "Obj = " + obj[j] + "\n";
                            dev = dev + "Element = " + element[j] + "\n";
                            dev = dev + "Obj station = " + obj_station[j] + "\n";
                            dev = dev + "El station = " + element_station[j] + "\n";
                            dev = dev + "Load case = " + load_case[j] + "\n";

                            var comb = new LoadCaseModel(j, load_case[j]);
                            ExtraSapHelper.ConvertStressesFromSAP2000(_output_beam[index], ref M2[j], ref M3[j], ref V2[j], ref V3[j]);
                            var res = new BeamForceResultModel(comb, obj_station[j], step_num[j], step_type[j])
                            {
                                AxialForce = P[j],
                                BendingMoment = new Vector2d(M2[j], M3[j]),
                                Torque = T[j],
                                ShearForce = new Vector2d(V2[j], V3[j])
                            };

                            _output_beam[index].Results.Add(res);
                            _dev.Add(dev);
                        }
                        k = nr_frame; //beam found -> exit
                    }
                    if (k == (nr_frame - 1) && found == false)
                    {
                        //BEAM NOT FOUND!!!
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Beam in input not found in model! ID = " + label);
                        _dev.Add("Beam in input not found in model! ID = " + label + "\n");
                    }
                }
                lock (_obj)
                {
                    iter++;
                    _attr.Text = "Processing element " + iter + " of " + input_beam.Count();
                }
            }

            if (mySapObject.ApplicationExit(false) != 0)
            {
                MessageBox.Show("Error exit SAP");
                _run = false;
                return;
            }
            _attr.Text = "Finish";
        }

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

        /// <summary>
        /// Gets the unique ID for this component. Do not change this ID after release.
        /// </summary>
        public override Guid ComponentGuid => new("9e1645eb-0748-472d-8157-4b864b4061a0");
    }
}
303 files24 directories