using FeMM.Grasshopper.Helpers;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Data;
using Grasshopper.Kernel.Types;
using St7API;
using System;
using System.Collections.Generic;
using System.Text;

namespace FeMM.Grasshopper.Components.ST2R
{
    public class St7ReadBeamForcesWithEnvelopesComponent : GH_Component
    {
        private bool _run = false;

        public St7ReadBeamForcesWithEnvelopesComponent()
            : base(
                "Read Beam Forces",
                "ReadBeamForces",
                "Reads beam force from the result file",
                CategoryNameConstants.CATEGORY_F2R, CategoryNameConstants.SUBCATEGORY_ST2R_BAKE)
        { }

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

        protected override void RegisterInputParams(GH_InputParamManager p)
        {
            p.AddIntegerParameter("uID", "ID", "uID of the opened Straus7 model", GH_ParamAccess.item);
            p.AddTextParameter("Result File", "Res", "Path to .NLA / .NLF / .RST result file", GH_ParamAccess.item);
            p.AddIntegerParameter("Beam Number", "BeamNum", "Beam number(s)", GH_ParamAccess.list);
            p.AddIntegerParameter("Min Stations", "Min", "Minimum number of stations", GH_ParamAccess.item, 5);
            p.AddTextParameter("Ref System", "Ref", "Reference system: stBeamLocal, stBeamPrincipal, stBeamGlobal, or UCS ID", GH_ParamAccess.item, "stBeamGlobal");
        }

        protected override void RegisterOutputParams(GH_OutputParamManager p)
        {
            p.AddTextParameter("Case Names", "Names", "Result case, combination and envelope names", GH_ParamAccess.tree);
            p.AddNumberParameter("Positions", "P", "Station positions", GH_ParamAccess.tree);
            p.AddNumberParameter("Fx", "Fx", "Axial force", GH_ParamAccess.tree);
            p.AddNumberParameter("Fy", "Fy", "Shear force local Y", GH_ParamAccess.tree);
            p.AddNumberParameter("Fz", "Fz", "Shear force local Z", GH_ParamAccess.tree);
            p.AddNumberParameter("Mx", "Mx", "Torsion", GH_ParamAccess.tree);
            p.AddNumberParameter("My", "My", "Bending moment local Y", GH_ParamAccess.tree);
            p.AddNumberParameter("Mz", "Mz", "Bending moment local Z", GH_ParamAccess.tree);
            p.AddTextParameter("Log", "Log", "Debug log messages", GH_ParamAccess.list);
        }

        protected override void SolveInstance(IGH_DataAccess DA)
        {
            int uID = 0;
            string resultFile = "";
            List<int> beamNums = [];
            int minStations = 5;
            string refSystemInput = "stBeamGlobal";

            if (!DA.GetData(0, ref uID)) return;
            if (!DA.GetData(1, ref resultFile)) return;
            if (!DA.GetDataList(2, beamNums)) return;
            if (!DA.GetData(3, ref minStations)) return;
            if (!DA.GetData(4, ref refSystemInput)) return;

            List<string> log = [];

            if (!_run)
            {
                DA.SetDataList(8, log);
                return;
            }

            // --------------------------
            // Map reference system input to int
            // --------------------------
            int refSystem = St7.stBeamGlobal; // default
            switch (refSystemInput.Trim())
            {
                case "BeamLocal":
                    refSystem = St7.stBeamLocal;
                    break;
                case "BeamPrincipal":
                    refSystem = St7.stBeamPrincipal;
                    break;
                case "BeamGlobal":
                    refSystem = St7.stBeamGlobal;
                    break;
                default:
                    if (int.TryParse(refSystemInput, out int ucsID))
                        refSystem = ucsID;
                    else
                        log.Add($"Invalid Ref System input: {refSystemInput}, using Global.");
                    break;
            }

            // --------------------------
            // Open result file
            // --------------------------
            int numPrimary = 0;
            int numSecondary = 0;
            int err = St7.St7OpenResultFile(
                uID,
                resultFile,
                null,
                St7.kUseExistingCombinations,
                ref numPrimary,
                ref numSecondary);

            if (err != 0)
            {
                log.Add($"Error opening result file: {err}");
                DA.SetDataList(8, log);
                _run = false;
                return;
            }

            log.Add($"Result file opened. Primary cases: {numPrimary}, Secondary combos: {numSecondary}");

            // --------------------------
            // Generate envelopes
            // --------------------------
            int numLimitEnv = 0, numComboEnv = 0, numFactorEnv = 0;
            err = St7.St7GenerateEnvelopes(uID, ref numLimitEnv, ref numComboEnv, ref numFactorEnv);

            if (err != 0)
                log.Add($"Error generating envelopes: {err}");
            else
                log.Add($"Envelopes generated. Limits={numLimitEnv}, Combinations={numComboEnv}, Factors={numFactorEnv}");

            // --------------------------
            // Prepare GH trees
            // --------------------------
            GH_Structure<GH_String> treeNames = new();
            GH_Structure<GH_Number> treeN = new();
            GH_Structure<GH_Number> treeFx = new();
            GH_Structure<GH_Number> treeFy = new();
            GH_Structure<GH_Number> treeFz = new();
            GH_Structure<GH_Number> treeMx = new();
            GH_Structure<GH_Number> treeMy = new();
            GH_Structure<GH_Number> treeMz = new();

            int beamIndex = 0;

            foreach (int beamNum in beamNums)
            {
                int caseBranchIndex = 0;

                void ReadBeamCase(int caseNum, string caseName)
                {
                    int maxStations = 200;
                    int maxCols = 6;
                    double[] beamPos = new double[maxStations];
                    double[] beamResults = new double[maxStations * maxCols];
                    int numStations = 0;
                    int numColumns = 0;

                    int errBeam = St7.St7GetBeamResultArray(
                        uID,
                        St7.rtBeamForce,
                        refSystem,      
                        beamNum,
                        minStations,
                        caseNum,
                        ref numStations,
                        ref numColumns,
                        beamPos,
                        beamResults);

                    if (errBeam != 0)
                    {
                        log.Add($"Error reading beam {beamNum} results for {caseName} (Case {caseNum}): {errBeam}");
                        return;
                    }

                    log.Add($"Read {numStations} stations for beam {beamNum}, case {caseName}");

                    GH_Path path = new(beamIndex, caseBranchIndex);

                    for (int i = 0; i < numStations; i++)
                    {
                        treeNames.Append(new GH_String(caseName), path);
                        treeN.Append(new GH_Number(beamPos[i]), path);
                        treeFx.Append(new GH_Number(beamResults[i * numColumns + 0]), path);
                        treeFy.Append(new GH_Number(beamResults[i * numColumns + 2]), path);
                        treeFz.Append(new GH_Number(beamResults[i * numColumns + 4]), path);
                        treeMx.Append(new GH_Number(beamResults[i * numColumns + 1]), path);
                        treeMy.Append(new GH_Number(beamResults[i * numColumns + 3]), path);
                        treeMz.Append(new GH_Number(beamResults[i * numColumns + 5]), path);
                    }

                    caseBranchIndex++;
                }

                // --------------------------
                // Primary Cases
                // --------------------------
                for (int i = 1; i <= numPrimary; i++)
                {
                    StringBuilder name = new(256);
                    int errCase = St7.St7GetResultCaseName(uID, i, name, name.Capacity);
                    if (errCase != 0) continue;
                    ReadBeamCase(i, name.ToString().TrimEnd('\0'));
                }

                // --------------------------
                // Secondary Combinations
                // --------------------------
                for (int i = 1; i <= numSecondary; i++)
                {
                    StringBuilder name = new(256);
                    int errCombo = St7.St7GetLSACombinationName(uID, i, name, name.Capacity);
                    if (errCombo != 0) continue;
                    ReadBeamCase(i + numPrimary, name.ToString().TrimEnd('\0').Replace("COMBO", "").Trim());
                }

                // --------------------------
                // Envelopes
                // --------------------------
                for (int i = 1; i <= numLimitEnv + numComboEnv + numFactorEnv; i++)
                {
                    StringBuilder name = new(256);
                    int errEnv = St7.St7GetResultCaseName(uID, i + numPrimary + numSecondary, name, name.Capacity);
                    if (errEnv != 0) continue;
                    ReadBeamCase(i + numPrimary + numSecondary, name.ToString().TrimEnd('\0'));
                }

                beamIndex++;
            }

            // --------------------------
            // Output
            // --------------------------
            DA.SetDataTree(0, treeNames);
            DA.SetDataTree(1, treeN);
            DA.SetDataTree(2, treeFx);
            DA.SetDataTree(3, treeFy);
            DA.SetDataTree(4, treeFz);
            DA.SetDataTree(5, treeMx);
            DA.SetDataTree(6, treeMy);
            DA.SetDataTree(7, treeMz);
            DA.SetDataList(8, log);

            _run = false;
        }

        protected override System.Drawing.Bitmap Icon => Properties.Resources.St7ReadBeamForcesWithEnvelopesIcon;

        public override Guid ComponentGuid => new("3a21afc0-ff30-44af-a0f8-58e6aa9b9ab0");
    }
}
303 files24 directories