using SAP2000v1;
using FeMM.Grasshopper.Helpers;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Parameters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Versioning;

namespace FeMM.Grasshopper.Components.SAPExtra
{
#if NETCOREAPP
    [SupportedOSPlatform("windows")]
#endif
    public class SAPGetWorstComboComponent : GH_Component
    {
        protected Dictionary<int, string> _stations = new()
        {
            { 0, "I"},
            { 1, "J"},
            { 2, "Ends"},
            { 3, "EndsAndMiddle"},
            { 4, "AllStations" }
        };

        private bool _run = false;

        /// <summary>
        /// Initializes a new instance of the BeamResultFilterComponent class.
        /// </summary>
        public SAPGetWorstComboComponent()
          : base("12+2 Worst combo", "12+2C", "Return the 12+2 worst combinations", CategoryNameConstants.CATEGORY_F2R, CategoryNameConstants.SUBCATEGORY_F2R_INTERACTIVESAP)
        {
        }

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

            m_attributes = buttonAttributes;
        }

        /// <summary>
        /// Registers all the input parameters for this component.
        /// </summary>
        protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager)
        {
            pManager.AddTextParameter("Model Path", "MP", "Sap2000 model path to open. If empty it will open an empty file", GH_ParamAccess.item, "");
            pManager[0].Optional = true;
            pManager.AddBooleanParameter("Attach to Instance", "AI", "Attach to instance. If true, 'model path' will be ignored", GH_ParamAccess.item, false);
            pManager[1].Optional = true;
            pManager.AddGenericParameter("Groups", "G", "Groups for beams", GH_ParamAccess.list);
            pManager.AddGenericParameter("Combinations", "C", "Combinations", GH_ParamAccess.list);
            int i = pManager.AddIntegerParameter("Stations", "S", "The stations where calculate the worst combos", GH_ParamAccess.item, 4);
            Param_Integer mtParam = pManager[i] as Param_Integer;
            foreach (KeyValuePair<int, string> v in _stations)
                mtParam.AddNamedValue(v.Value, v.Key);
        }

        /// <summary>
        /// Registers all the output parameters for this component.
        /// </summary>
        protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager)
        {
            pManager.AddTextParameter("Worst Combos", "C", "The combinations filtered", 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>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            string modelPath = "";
            bool attachToInstance = false;
            var groupWanted = new List<string>();
            var combosWanted = new List<string>();
            int stat = 0;

            DA.GetData(0, ref modelPath);
            DA.GetData(1, ref attachToInstance);
            if (!DA.GetDataList(2, groupWanted))
                return;
            if (!DA.GetDataList(3, combosWanted))
                return;
            DA.GetData(4, ref stat);


            if (_run)
            {
                try
                {
                    if (!System.IO.File.Exists(modelPath) && !attachToInstance) // model path non valido, Se path modello non valido fa partire con stringa vuota (file vuoto)
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Sap model path not valid, opening an empty file");
                        return;
                    }

                    if (!ExtraSapHelper.InitializeModel(!attachToInstance, "", modelPath, out cOAPI _mySapObject, out cSapModel _mySapModel, out _))
                    {
                        _run = false;
                        Message = "SAP Fail";
                        return;
                    }

                    if (!_mySapObject.SapModel.GetModelIsLocked())
                    {
                        _run = false;
                        Message = "SAP Fail";
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Plase run the analysis");
                        return;
                    }

                    if (_mySapModel.SelectObj.ClearSelection() != 0)
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Error deselect previous groups for output");
                        _run = false;
                        return;
                    }

                    int nGroups = 0;
                    string[] allGroups = [];
                    if (_mySapModel.GroupDef.GetNameList(ref nGroups, ref allGroups) != 0)
                        return;
                    Array.Sort(allGroups);

                    int groupRead = 0;
                    for (int i = 0; i < groupWanted.Count; i++)
                    {
                        if (allGroups.Contains(groupWanted[i]))
                        {
                            if (groupWanted[i] != "ALL")
                            {
                                _mySapModel.SelectObj.Group(groupWanted[i]);
                                groupRead++;
                            }
                            else
                            {
                                if (_mySapModel.SelectObj.All() != 0)
                                {
                                    AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, $"Error during selection of {groupWanted[i]}");
                                    _run = false;
                                    return;
                                }
                            }
                        }
                    }


                    int nCombos = 0;
                    string[] allCombos = [];
                    if (_mySapModel.RespCombo.GetNameList(ref nCombos, ref allCombos) != 0)
                        return;
                    Array.Sort(allCombos);

                    if (_mySapObject.SapModel.Results.Setup.DeselectAllCasesAndCombosForOutput() != 0)
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Error deselect previous combo for output");
                        _run = false;
                        return;
                    }

                    int comboRead = 0;
                    for (int i = 0; i < allCombos.Count(); i++)
                    {
                        if (combosWanted.Contains(allCombos[i]))
                        {
                            if (_mySapObject.SapModel.Results.Setup.SetCaseSelectedForOutput(allCombos[i]) == 0)
                            {
                                comboRead++;
                            }
                            else
                            {
                                if (_mySapObject.SapModel.Results.Setup.SetComboSelectedForOutput(allCombos[i]) == 0)
                                {
                                    comboRead++;
                                }
                                else
                                {
                                    AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Error set combo/load case of output");
                                    _run = false;
                                    return;
                                }
                            }
                        }
                    }

                    int nrBeams = 0;
                    string[] nameBeams = [];
                    _mySapModel.FrameObj.GetNameList(ref nrBeams, ref nameBeams);

                    var outCombos = new HashSet<string>();

                    for (int i = 0; i < nrBeams; i++)
                    {
                        string name_beam = nameBeams[i];

                        //get groups of beam
                        int nr_groups_beam = 0;
                        string[] groups_beam = [];
                        if (_mySapModel.FrameObj.GetGroupAssign(name_beam, ref nr_groups_beam, ref groups_beam) != 0)
                        {
                            AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "No group assign for beam {name_beam}");
                            _run = false;
                            return;
                        }

                        bool flag = false;

                        for (int j = 0; j < groups_beam.Length; j++)
                        {
                            if (groupWanted.Contains(groups_beam[j]))
                            {
                                flag = true;
                                break;
                            }
                        }

                        if (flag)
                        {
                            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 = [];

                            //get results
                            if (_mySapObject.SapModel.Results.FrameForce(name_beam, 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)
                            {
                                double length = obj_station[number_result - 1];
                                //get section data for calculation of stress
                                string property_name = "";
                                string SAuto = "";
                                if (_mySapModel.FrameObj.GetSection(name_beam, ref property_name, ref SAuto) != 0)
                                    return;

                                //get frame section properties
                                double Area = 0, As2 = 0, As3 = 0, Torsion = 0, I22 = 0, I33 = 0, S22 = 0, S33 = 0, Z22 = 0, Z33 = 0, R22 = 0, R33 = 0;
                                if (_mySapModel.PropFrame.GetSectProps(property_name, ref Area, ref As2, ref As3, ref Torsion, ref I22,
                                    ref I33, ref S22, ref S33, ref Z22, ref Z33, ref R22, ref R33) != 0)
                                    return;

                                //check if round section
                                eFramePropType type_section = 0;
                                if (_mySapModel.PropFrame.GetTypeOAPI(property_name, ref type_section) != 0)
                                    return;

                                bool flagCircleSection = false;
                                if (type_section == eFramePropType.Pipe || type_section == eFramePropType.Circle)
                                {
                                    flagCircleSection = true;
                                }

                                FrameForcesResultsStructSigma[] resultsStructSigmasBuffer = new FrameForcesResultsStructSigma[number_result];

                                for (int j = 0; j < number_result; j++)
                                {
                                    try
                                    {
                                        double multiplier = 1.0;

                                        P[j] = multiplier * P[j];
                                        V2[j] = multiplier * V2[j];
                                        V3[j] = multiplier * V3[j];
                                        M2[j] = multiplier * M2[j];
                                        M3[j] = multiplier * M3[j];
                                        T[j] = multiplier * T[j];

                                        double[] sigma = new double[4];
                                        if (flagCircleSection == false)
                                        {
                                            sigma[0] = P[j] / Area + M2[j] / S22 + M3[j] / S33;
                                            sigma[1] = P[j] / Area + M2[j] / S22 - M3[j] / S33;
                                            sigma[2] = P[j] / Area - M2[j] / S22 + M3[j] / S33;
                                            sigma[3] = P[j] / Area - M2[j] / S22 - M3[j] / S33;
                                        }
                                        else
                                        {
                                            double M = Math.Pow(Math.Pow(M2[j], 2.0) + Math.Pow(M3[j], 2.0), 0.5);
                                            sigma[0] = P[j] / Area + M / S22;
                                            sigma[1] = P[j] / Area - M / S22;
                                            sigma[2] = sigma[0];
                                            sigma[3] = sigma[1];
                                        }

                                        double sigmaMax = sigma.Max();
                                        double sigmaMin = sigma.Min();

                                        var r = new FrameForcesResultsStructSigma
                                        {
                                            SectionName = property_name,
                                            NameBeam = obj[j],
                                            Station = obj_station[j],
                                            LoadCase = load_case[j],
                                            N = P[j],
                                            V2 = V2[j],
                                            V3 = V3[j],
                                            M2 = M2[j],
                                            M3 = M3[j],
                                            T = T[j],
                                            SigmaMax = sigmaMax,
                                            SigmaMin = sigmaMin
                                        };

                                        resultsStructSigmasBuffer[j] = r;
                                    }
                                    catch (Exception ex)
                                    {
                                        {
                                            AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, ex.Message + " " + ex.StackTrace);
                                            _run = false;
                                            return;
                                        }
                                    }
                                }

                                #region Max/Min

                                int stations;
                                switch (stat)
                                {
                                    case 0:
                                    case 1:
                                        stations = 1;
                                        break;
                                    case 2:
                                        stations = 2;
                                        break;
                                    case 3:
                                        stations = 3;
                                        break;
                                    case 4:
                                        {
                                            stations = 0;
                                            for (int k = 0; k < obj_station.Length; k++)
                                            {
                                                if (k != 0)
                                                {
                                                    if (obj_station[k] == obj_station[0])
                                                        break;
                                                    else
                                                        stations++;
                                                }
                                                else
                                                    stations++;
                                            }

                                            break;
                                        }
                                    default:
                                        return;
                                }

                                for (int s = 0; s < stations; s++)
                                {
                                    double stationsLenght = -1;

                                    switch (s)
                                    {
                                        case 0 when stat == 0:
                                            stationsLenght = obj_station[0];
                                            break;
                                        case 0 when stat == 1:
                                            stationsLenght = length;
                                            break;
                                        case 0 when stat == 2:
                                            stationsLenght = obj_station[0];
                                            break;
                                        case 1 when stat == 2:
                                            stationsLenght = length;
                                            break;
                                        default:
                                            if (stat == 3)
                                            {
                                                if (s == 1)
                                                    stationsLenght = obj_station[0];
                                                else if (s == 1)
                                                    stationsLenght = length / 2.0;
                                                else if (s == 2)
                                                    stationsLenght = length;
                                            }
                                            else if (stat == 4)
                                                stationsLenght = obj_station[s];
                                            break;
                                    }

                                    if (stationsLenght == -1)
                                        return;

                                    double[] minMax =
                                    [
                                        double.MinValue, double.MaxValue,
                                        double.MinValue, double.MaxValue,
                                        double.MinValue, double.MaxValue,
                                        double.MinValue, double.MaxValue,
                                        double.MinValue, double.MaxValue,
                                        double.MinValue, double.MaxValue,
                                        double.MinValue, double.MaxValue,
                                    ];

                                    FrameForcesResultsStructSigma[] res = new FrameForcesResultsStructSigma[14];
                                    for (int r = 0; r < resultsStructSigmasBuffer.Length; r++)
                                    {
                                        if (Math.Abs(resultsStructSigmasBuffer[r].Station - stationsLenght) < 0.01)
                                        {
                                            // massimo valore di N e relativo BeamForceResult

                                            int count = 0;
                                            SetMinMax(resultsStructSigmasBuffer[r].N, ref resultsStructSigmasBuffer, ref res, ref minMax, r, ref count);
                                            SetMinMax(resultsStructSigmasBuffer[r].V2, ref resultsStructSigmasBuffer, ref res, ref minMax, r, ref count);
                                            SetMinMax(resultsStructSigmasBuffer[r].V3, ref resultsStructSigmasBuffer, ref res, ref minMax, r, ref count);
                                            SetMinMax(resultsStructSigmasBuffer[r].T, ref resultsStructSigmasBuffer, ref res, ref minMax, r, ref count);
                                            SetMinMax(resultsStructSigmasBuffer[r].M2, ref resultsStructSigmasBuffer, ref res, ref minMax, r, ref count);
                                            SetMinMax(resultsStructSigmasBuffer[r].M3, ref resultsStructSigmasBuffer, ref res, ref minMax, r, ref count);
                                            SetMax(resultsStructSigmasBuffer[r].SigmaMax, ref resultsStructSigmasBuffer, ref res, ref minMax, r, ref count);
                                            SetMin(resultsStructSigmasBuffer[r].SigmaMin, ref resultsStructSigmasBuffer, ref res, ref minMax, r, ref count);
                                        }
                                    }

                                    for (int k = 0; k < res.Length; k++)
                                        outCombos.Add(res[k].LoadCase);

                                    #endregion
                                }
                            }
                        }
                    }

                    void SetMax(double value, ref FrameForcesResultsStructSigma[] resultsStructSigmasBuffer, ref FrameForcesResultsStructSigma[] res,
                        ref double[] minMax, int r, ref int count)
                    {
                        if (value > minMax[count])
                        {
                            minMax[count] = value;
                            res[count] = resultsStructSigmasBuffer[r];
                        }
                        count++;
                    }

                    void SetMin(double value, ref FrameForcesResultsStructSigma[] resultsStructSigmasBuffer, ref FrameForcesResultsStructSigma[] res,
                        ref double[] minMax, int r, ref int count)
                    {
                        if (value < minMax[count])
                        {
                            minMax[count] = value;
                            res[count] = resultsStructSigmasBuffer[r];
                        }
                        count++;
                    }

                    void SetMinMax(double value, ref FrameForcesResultsStructSigma[] resultsStructSigmasBuffer, ref FrameForcesResultsStructSigma[] res,
                        ref double[] minMax, int r, ref int count)
                    {
                        SetMax(value, ref resultsStructSigmasBuffer, ref res, ref minMax, r, ref count);
                        SetMin(value, ref resultsStructSigmasBuffer, ref res, ref minMax, r, ref count);
                    }

                    Message = "Done";
                    _run = false;
                    DA.SetDataList(0, outCombos.ToList());
                }
                catch (Exception ex)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, ex.Message);
                    _run = false;
                    return;
                }
            }
        }

        public struct FrameForcesResultsStructSigma
        {
            public string SectionName;
            public string NameBeam;
            public string LoadCase;
            public double Station;
            public double N;
            public double V2;
            public double V3;
            public double M2;
            public double M3;
            public double T;
            public double SigmaMax;
            public double SigmaMin;
        }

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

        /// <summary>
        /// Gets the unique ID for this component. Do not change this ID after release.
        /// </summary>
        public override Guid ComponentGuid => new("dfb7ddb5-663e-45ad-8107-150d977c8ff1");
    }
}
303 files24 directories