using FeMM.Common.Models;
using FeMM.Grasshopper.DataTypes.FeMM;
using FeMM.Grasshopper.Helpers;
using GH_IO.Serialization;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Parameters;
using Grasshopper.Kernel.Special;
using Rhino.Geometry;
using St7API;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Versioning;
using System.Text;
using System.Windows.Forms;

namespace FeMM.Grasshopper.Components.Analysis
{
#if NETCOREAPP
    [SupportedOSPlatform("windows")]
#endif
    public class StrausR3AnalysisComponent : GH_Component
    {
        protected bool _run;
        private GH_Model _model;
        private bool _just_loaded;

        /// <summary>
        /// Initializes a new instance of the StrausAnalysisComponent class.
        /// </summary>
        public StrausR3AnalysisComponent()
          : base("Straus R3 Analysis", "SA", "Model Analisys with Straus7", CategoryNameConstants.CATEGORY_FEMM, CategoryNameConstants.SUBCATEGORY_ANALYSIS)
        {
            _run = false;
            _model = new GH_Model();
            _just_loaded = false;
        }

        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_InputParamManager pManager)
        {
            pManager.AddGenericParameter("Model", "M", "The FEM model", GH_ParamAccess.item);
            pManager.AddIntegerParameter("Solver", "ST", "The type of solver to use", GH_ParamAccess.item, 0);
            Param_Integer solverParam = (Param_Integer)pManager[1];
            for (int i = 0; i < Common.Helpers.StrausR3Helper.Solvers.Length; i++)
                solverParam.AddNamedValue(Common.Helpers.StrausR3Helper.Solvers[i], i);
            int n = pManager.AddTextParameter("Analysis Results", "AR", "The analysis result cases or combination to returns", GH_ParamAccess.list);
            pManager[n].Optional = true;
            n = pManager.AddTextParameter("Freedom Cases", "FC", "The analysis freedom cases to returns", GH_ParamAccess.list);
            pManager[n].Optional = true;
            pManager.AddTextParameter("Output Path", "O", "The full path of the file model to create", GH_ParamAccess.item);
            n = pManager.AddBooleanParameter("Keep Running", "K", "Run analysis automatically when input is chaged", GH_ParamAccess.item, false);
            pManager[n].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)
        {
            Message = "";
            GH_Model model = null;
            int solver = 0;
            string outputPath = "";
            bool keepRunning = false;

            if (!DA.GetData("Model", ref model))
                return;
            if (!DA.GetData("Solver", ref solver))
                return;
            if (!DA.GetData("Output Path", ref outputPath))
                return;
            DA.GetData("Keep Running", ref keepRunning);

            if (Path.GetExtension(outputPath).ToLower() != ".st7")
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid extension in file name");
                return;
            }

            // Retrieve all te load cases used in the model
            var cases = new List<CaseModel>();
            Common.Helpers.CommonModelHelper.GetLoadCases(model.Value, out List<LoadCaseModel> loadCases);
            ModelHelper.GetStagedConstructionModel(model.Value, out List<StagedConstructionCombinationModel> stagedConstructionModels);
            cases.AddRange(loadCases);
            cases.AddRange(stagedConstructionModels);
            Common.Helpers.CommonModelHelper.GetFreedomCases(model.Value, out List<FreedomCaseModel> freedomCases);
            try
            {
                cases.Sort(new CaseModel.CaseModelComparer());
            }
            catch (Exception) { }

            // Connect the ValueList component on the analysis results input item
            IEnumerable<IGH_Param> keys_analysisResultLists = Params.Input[2].Sources.
                Where(s => s.GetType() == typeof(GH_ValueList));
            foreach (GH_ValueList vallist in keys_analysisResultLists.Cast<GH_ValueList>())
            {
                if (vallist.ListMode != GH_ValueListMode.CheckList)
                    vallist.ListMode = GH_ValueListMode.CheckList;

                List<string> names = [.. cases.Select(lc => lc.Name).Distinct()];
                names.AddRange(model.Value.Combinations.Select(c => c.Name));
                ComponentsHelper.SetValueList(vallist, names);
                vallist.NickName = "Results";
            }

            var analysisCaseResults = new List<string>();
            var requestedLoadCases = new List<LoadCaseModel>();
            var requestedFreedomCase = new List<FreedomCaseModel>();
            var requestedCombs = new List<BaseCaseCombinationModel>();
            var requestedStage = new List<StagedConstructionCombinationModel>();

            if (solver != 3)
            {
                if (DA.GetDataList("Analysis Results", analysisCaseResults))
                {
                    for (int i = 0; i < analysisCaseResults.Count; i++)
                    {
                        string caseName = analysisCaseResults[i];
                        LoadCaseModel lCase = loadCases.FirstOrDefault(lc => lc.Name == caseName);
                        StagedConstructionCombinationModel cstrStage = stagedConstructionModels.FirstOrDefault(lc => lc.Name == caseName);
                        LoadCaseCombinationModel cCase = (LoadCaseCombinationModel)model.Value.Combinations.Where(j => j is LoadCaseCombinationModel).FirstOrDefault(cc => cc.Name == caseName);
                        if (lCase != null)
                        {
                            requestedLoadCases.Add(lCase);
                        }
                        else if (cCase != null)
                        {
                            requestedCombs.Add(cCase);
                            foreach (KeyValuePair<CaseModel, double> kvp in cCase.Values)
                            {
                                if (kvp.Value != 0 && kvp.Key is LoadCaseModel && requestedLoadCases.FirstOrDefault(lc => lc.Name == kvp.Key.Name) == null)
                                {
                                    if (loadCases.Contains(kvp.Key))
                                        requestedLoadCases.Add(loadCases.Single(lc => lc.Name == kvp.Key.Name));
                                }
                                if (kvp.Value != 0 && kvp.Key is FreedomCaseModel && requestedFreedomCase.FirstOrDefault(lc => lc.Name == kvp.Key.Name) == null)
                                {
                                    if (freedomCases.Contains(kvp.Key))
                                        requestedFreedomCase.Add(freedomCases.Single(lc => lc.Name == kvp.Key.Name));
                                }
                            }
                        }
                        else if (cstrStage != null)
                        {
                            requestedStage.Add(cstrStage);
                            for (int j = 0; j < cstrStage.LoadCombinations.Count; j++)
                            {
                                LoadCaseCombinationModel combo = cstrStage.LoadCombinations[j];
                                Dictionary<CaseModel, double> kvp = combo.Values;
                                foreach (var kkk in kvp)
                                {
                                    if (kkk.Value != 0 && kkk.Key is LoadCaseModel && requestedLoadCases.FirstOrDefault(lc => lc.Name == kkk.Key.Name) == null)
                                    {
                                        requestedLoadCases.Add(loadCases.Where(lc => lc.Name == kkk.Key.Name).FirstOrDefault());
                                    }
                                    if (kkk.Value != 0 && kkk.Key is FreedomCaseModel && requestedFreedomCase.FirstOrDefault(lc => lc.Name == kkk.Key.Name) == null)
                                    {
                                        requestedFreedomCase.Add(freedomCases.Where(lc => lc.Name == kkk.Key.Name).FirstOrDefault());
                                    }
                                }
                            }
                            for (int j = 0; j < cstrStage.FreedomCases.Count; j++)
                            {
                                FreedomCaseCombinationModel combo = cstrStage.FreedomCases[j];
                                Dictionary<CaseModel, double> kvp = combo.Values;
                                foreach (var kkk in kvp)
                                {
                                    if (kkk.Value != 0 && kkk.Key is LoadCaseModel && requestedLoadCases.FirstOrDefault(lc => lc.Name == kkk.Key.Name) == null)
                                    {
                                        requestedLoadCases.Add(loadCases.Where(lc => lc.Name == kkk.Key.Name).FirstOrDefault());
                                    }
                                    if (kkk.Value != 0 && kkk.Key is FreedomCaseModel && requestedFreedomCase.FirstOrDefault(lc => lc.Name == kkk.Key.Name) == null)
                                    {
                                        requestedFreedomCase.Add(freedomCases.Where(lc => lc.Name == kkk.Key.Name).FirstOrDefault());
                                    }
                                }
                            }
                        }
                        else
                        {
                            AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"The result case name {caseName} does not exists.");
                            return;
                        }
                    }
                }
                else
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Input parameter Analysis Results failed to collect data");
                }
            }

            // Connect the ValueList component on the analysis results input item
            IEnumerable<IGH_Param> keys_freedomCasesLists = Params.Input[3].Sources.
                Where(s => s.GetType() == typeof(GH_ValueList));
            foreach (GH_ValueList vallist in keys_freedomCasesLists.Cast<GH_ValueList>())
            {
                if (vallist.ListMode != GH_ValueListMode.CheckList)
                    vallist.ListMode = GH_ValueListMode.CheckList;

                List<string> names = [.. freedomCases.Select(lc => lc.Name).Distinct()];
                ComponentsHelper.SetValueList(vallist, names);
                vallist.NickName = "Freedom Cases";
            }

            var freedomCasesString = new List<string>();

            if (DA.GetDataList("Freedom Cases", freedomCasesString))
            {
                for (int i = 0; i < freedomCasesString.Count; i++)
                {
                    string fcName = freedomCasesString[i];
                    FreedomCaseModel lCase = freedomCases.FirstOrDefault(lc => lc.Name == fcName);
                    if (lCase != null)
                    {
                        requestedFreedomCase.Add(lCase);
                    }
                    else
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"The freedom case name {fcName} does not exists.");
                        return;
                    }
                }
            }
            else
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Input parameter Analysis Results failed to collect data");
            }

            if (solver == 3)
            {
                if (freedomCasesString.Count > 1 || analysisCaseResults.Count > 0)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Only one freedom case and no load cases must be set for Natural Frequency analysis");
                    return;
                }
            }

            if (_run || keepRunning)
            {
                int modelId = 0;
                var warnings = new List<string>();
                var errors = new List<string>();
                try
                {
                    if (Common.Helpers.StrausR3Helper.CreateModelR3(model.Value, outputPath, Rhino.Settings.Tolerance, out modelId, out warnings, out errors,
                        out Dictionary<string, int> loadCaseNameIdMap, out Dictionary<string, int> freedomCasesIdMap, out Dictionary<string, int> stageConstrIdMap))
                    {
                        try
                        {
                            var primaryResultCases = new Dictionary<CaseModel, int>();
                            var secondaryResultCases = new Dictionary<CaseModel, int>();

                            int numbOfStage = 0;
                            int index = 1;
                            for (int i = 0; i < cases.Count; i++)
                            {
                                CaseModel lc = cases[i];
                                if (requestedLoadCases.Contains(lc))
                                {
                                    // Load cases solved as primary only in linear solver
                                    if (solver == 0)
                                    {
                                        // We don't consider load cases added only for combinations
                                        if (analysisCaseResults.Contains(lc.Name))
                                        {
                                            if (!primaryResultCases.ContainsKey(lc))
                                                primaryResultCases.Add(lc, index);
                                        }
                                        index++;
                                    }
                                }
                            }
                            if (solver == 0 || solver == 1)
                            {
                                for (int i = 0; i < model.Value.Combinations.Count; i++)
                                {
                                    BaseCaseCombinationModel c = model.Value.Combinations[i];
                                    if (requestedCombs.Contains(c))
                                    {
                                        if (solver == 0)
                                        {
                                            if (!secondaryResultCases.ContainsKey(c))
                                                secondaryResultCases.Add(c, index);
                                        }
                                        else if (solver == 1)
                                        {
                                            if (!primaryResultCases.ContainsKey(c))
                                                primaryResultCases.Add(c, index);
                                        }
                                    }
                                    index++; // Combinations are always resolved
                                }
                            }
                            else if (solver == 2)
                            {
                                for (int i = 0; i < model.Value.StagedConstruction.Count; i++)
                                {
                                    if (model.Value.StagedConstruction[i] is StagedConstructionCombinationModel sc)
                                    {
                                        if (analysisCaseResults.Contains(sc.Name))
                                        {
                                            if (!primaryResultCases.ContainsKey(sc))
                                            {
                                                primaryResultCases.Add(sc, index);
                                                numbOfStage++;
                                                index++;
                                            }
                                        }
                                    }
                                }
                            }
                            else if (solver == 3)
                            {
                                if (model.Value.LoadCases.Any(k => k.GetType() == typeof(ModalEigenModel)))
                                {
                                    int modalNumber = 0;
                                    for (int i = 0; i < model.Value.LoadCases.Count; i++)
                                    {
                                        Common.Models.Interface.ILoadModel ccc = model.Value.LoadCases[i];
                                        {
                                            if (ccc is ModalEigenModel modalEigenModel)
                                            {
                                                if (!primaryResultCases.ContainsKey(modalEigenModel))
                                                {
                                                    primaryResultCases.Add(modalEigenModel, index);
                                                    index++;
                                                    modalNumber++;
                                                }
                                            }
                                        }
                                    }
                                    if (modalNumber > 1)
                                    {
                                        AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"Only one modal case must be set.");
                                        _run = false;
                                        return;
                                    }
                                }
                                else
                                {
                                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"One Eigen modal must be set.");
                                    _run = false;
                                    return;
                                }
                            }

                            int iErr = St7.St7OpenFile(modelId, outputPath, Path.GetTempPath());

                            int st7_solver = 0;
                            string res_ext = "";
                            switch (solver)
                            {
                                case 0: // Linear solver
                                    st7_solver = St7.stLinearStatic;
                                    res_ext = "LSA";
                                    for (int i = 0; i < loadCases.Count; i++)
                                    {
                                        LoadCaseModel loadCase = loadCases[i];
                                        for (int j = 0; j < freedomCases.Count; j++)
                                        {
                                            FreedomCaseModel fc = freedomCases[j];
                                            if (requestedFreedomCase.Contains(fc) && requestedLoadCases.Contains(loadCase))
                                                St7.St7EnableLSALoadCase(modelId, loadCaseNameIdMap[loadCase.Name], freedomCasesIdMap[fc.Name]);
                                            else
                                                St7.St7DisableLSALoadCase(modelId, loadCaseNameIdMap[loadCase.Name], freedomCasesIdMap[fc.Name]);
                                        }
                                    }
                                    break;
                                case 1: // Nonlinear solver
                                    st7_solver = St7.stNonlinearStatic;
                                    res_ext = "NLA";
                                    for (int i = 0; i < loadCases.Count; i++)
                                    {
                                        LoadCaseModel loadCase = loadCases[i];
                                        for (int j = 0; j < freedomCases.Count; j++)
                                        {
                                            FreedomCaseModel fc = freedomCases[j];
                                            if (requestedFreedomCase.Contains(fc) && requestedLoadCases.Contains(loadCase))
                                                St7.St7EnableNLALoadCase(modelId, loadCaseNameIdMap[loadCase.Name], freedomCasesIdMap[fc.Name]);
                                            else
                                                St7.St7DisableNLALoadCase(modelId, loadCaseNameIdMap[loadCase.Name], freedomCasesIdMap[fc.Name]);
                                        }
                                    }
                                    break;
                                case 2: // Staged analysis
                                    st7_solver = St7.stNonlinearStatic;
                                    res_ext = "NLA";
                                    St7.St7SetNLAStagedAnalysis(modelId, St7.btTrue);
                                    if (requestedStage.Count > 0)
                                    {
                                        for (int k = 0; k < requestedStage.Count; k++)
                                        {
                                            StagedConstructionCombinationModel stg = requestedStage[k];
                                            St7.St7EnableNLAStage(modelId, stageConstrIdMap[stg.StagedModel.Name]);
                                        }
                                    }
                                    break;
                                case 3: // Natural Frequency solver
                                    st7_solver = St7.stNaturalFrequency;
                                    res_ext = "NFA";
                                    for (int j = 0; j < freedomCases.Count; j++)
                                    {
                                        FreedomCaseModel fc = freedomCases[j];
                                        if (requestedFreedomCase.Contains(fc))
                                            St7.St7SetSolverFreedomCase(modelId, freedomCasesIdMap[fc.Name]);
                                    }
                                    break;
                            }

                            try
                            {
                                if (St7.St7SaveFile(modelId) == 0)
                                {
                                    string result_path = Path.Combine(Path.GetDirectoryName(outputPath), Path.GetFileNameWithoutExtension(outputPath) + "." + res_ext);
                                    File.Delete(result_path);

                                    int ss = St7.St7RunSolver(modelId, st7_solver, St7.smNormalCloseRun, St7.btTrue);
                                    if (ss == 0)
                                    {
                                        // Create a deep copy of the model where to add the results
                                        _model = (GH_Model)model.Duplicate();
                                        if (_model.Value.Name == "")
                                            _model.Value.Name = Path.GetFileNameWithoutExtension(outputPath);

                                        int numPrimary = 0, numSecondary = 0;

                                        int openError = St7.St7OpenResultFile(modelId, result_path, null, St7.kGenerateNewCombinations, ref numPrimary, ref numSecondary);
                                        if (openError == 0)
                                        {
                                            if (solver == 0)
                                            {
                                                bool hasCombo = requestedCombs.Count > 0;
                                                bool hasStage = numbOfStage > 0;
                                                foreach (KeyValuePair<CaseModel, int> kvp in primaryResultCases)
                                                {
                                                    SetResults(modelId, kvp.Value, kvp.Key, hasCombo, hasStage, false);
                                                }
                                                foreach (KeyValuePair<CaseModel, int> kvp in secondaryResultCases)
                                                {
                                                    SetResults(modelId, kvp.Value, kvp.Key, hasCombo, hasStage, false);
                                                }
                                            }
                                            else if (solver == 1 || solver == 2)
                                            {
                                                bool hasCombo = requestedCombs.Count > 0;
                                                bool hasStage = numbOfStage > 0;
                                                foreach (KeyValuePair<CaseModel, int> kvp in primaryResultCases)
                                                {
                                                    SetResults(modelId, kvp.Value, kvp.Key, hasCombo, hasStage, true);
                                                }
                                                foreach (KeyValuePair<CaseModel, int> kvp in secondaryResultCases)
                                                {
                                                    SetResults(modelId, kvp.Value, kvp.Key, hasCombo, hasStage, true);
                                                }
                                            }
                                            else
                                            {

                                            }
                                            St7.St7CloseResultFile(modelId);
                                            St7.St7CloseFile(modelId);
                                            Common.Helpers.StrausR3Helper.ReleaseModelId(modelId);
                                            Message = "Done";
                                        }
                                        else
                                        {
                                            var stringBuilder = new StringBuilder();
                                            St7.St7GetSolverErrorString(openError, stringBuilder, St7.kMaxStrLen);
                                            string err = stringBuilder.ToString();

                                            AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, string.Format("Opening result error: {0}", err));

                                            try
                                            {
                                                St7.St7CloseResultFile(modelId);
                                            }
                                            catch (Exception) { }
                                            try
                                            {
                                                St7.St7CloseFile(modelId);
                                            }
                                            catch (Exception) { }

                                            try
                                            {
                                                Common.Helpers.StrausR3Helper.ReleaseModelId(modelId);
                                            }
                                            catch (Exception) { }
                                            Message = "Error";
                                            _run = false;
                                            return;
                                        }
                                    }
                                    else
                                    {
                                        var stringBuilder = new StringBuilder();
                                        St7.St7GetSolverErrorString(ss, stringBuilder, St7.kMaxStrLen);
                                        string err = stringBuilder.ToString();

                                        try
                                        {
                                            St7.St7CloseResultFile(modelId);
                                        }
                                        catch (Exception) { }
                                        try
                                        {
                                            St7.St7CloseFile(modelId);
                                        }
                                        catch (Exception) { }

                                        try
                                        {
                                            Common.Helpers.StrausR3Helper.ReleaseModelId(modelId);
                                        }
                                        catch (Exception) { }

                                        AddRuntimeMessage(GH_RuntimeMessageLevel.Error, string.Format("Solver error: {0}", err));
                                        Message = "Error";
                                        _run = false;
                                        return;
                                    }
                                }
                                else
                                {
                                    St7.St7CloseFile(modelId);
                                    Common.Helpers.StrausR3Helper.ReleaseModelId(modelId);
                                    Message = "Error";
                                    _run = false;
                                    return;
                                }
                            }
                            catch
                            {
                                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Fail to run the analysis or read the results");

                                St7.St7SaveFile(modelId);
                                St7.St7CloseFile(modelId);
                                Common.Helpers.StrausR3Helper.ReleaseModelId(modelId);
                                Message = "Error";
                                _run = false;
                                return;
                            }
                        }
                        catch
                        {
                            AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Fail to set the analysis");

                            St7.St7SaveFile(modelId);
                            St7.St7CloseFile(modelId);
                            Common.Helpers.StrausR3Helper.ReleaseModelId(modelId);
                            Message = "Error";
                            _run = false;
                            return;
                        }
                    }
                    else
                    {
                        St7.St7SaveFile(modelId);
                        St7.St7CloseFile(modelId);
                        Common.Helpers.StrausR3Helper.ReleaseModelId(modelId);
                        Message = "Error";
                        _run = false;
                        return;
                    }
                }
                catch
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Fail to create Straus file");

                    St7.St7SaveFile(modelId);
                    St7.St7CloseFile(modelId);
                    Common.Helpers.StrausR3Helper.ReleaseModelId(modelId);
                    Message = "Error";
                    _run = false;
                    return;
                }

                foreach (string warning in warnings)
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, warning);

                foreach (string error in errors)
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, error);

                _run = false;
            }

            DA.SetData(0, _model);
        }

        private string GetResultCaseName(int modelId, int resultCase)
        {
            var sb = new StringBuilder(St7.kMaxStrLen);
            St7.St7GetResultCaseName(modelId, resultCase, sb, sb.Capacity);
            string caseName = sb.ToString();
            return caseName.Substring(caseName.IndexOf(':') + 1).Trim();
        }

        private int GetResultCaseStage(int modelId, int resultCase)
        {
            int stageNumb = 0;
            St7.St7GetResultCaseStage(modelId, resultCase, ref stageNumb);
            return stageNumb;
        }

        private string GetResultFreedomCaseName(int modelId, int resultCase)
        {
            var sb = new StringBuilder(St7.kMaxStrLen);
            St7.St7GetResultFreedomCaseName(modelId, sb, sb.Capacity);
            string caseName = sb.ToString();
            return caseName.Substring(caseName.IndexOf(':') + 1).Trim();
        }

        private void SetResults(int modelId, int resultCase, CaseModel caseModel, bool hasCombo, bool hasStage, bool hasIncrement)
        {
            string resultName = GetResultCaseName(modelId, resultCase);
            string freedomCaseName = GetResultFreedomCaseName(modelId, resultCase);
            FreedomCaseModel freedomCase = _model.Value.FreedomCases.Where(i => i.Name == freedomCaseName).FirstOrDefault();
            if (freedomCase == null)
            {
                if (hasStage)
                {

                }
                else
                    throw new NotSupportedException("Error reading results of freedom case " + caseModel.Name);
            }
            // Sanity check
            string check = "";

            if (resultName.Contains("[Combination]"))
            {
                int startIndex = resultName.IndexOf(resultName.First(i => i == ' ')) + 1;
                int endIndex = resultName.IndexOf(resultName.First(i => i == ']'));
                check = resultName.Substring(startIndex, endIndex - startIndex);
            }
            else
            {
                if (hasIncrement)
                {
                    check = resultName;
                }
                else if (hasCombo)
                {
                    int startIndex = resultName.IndexOf(resultName.First(i => i == ' ')) + 1;
                    int endIndex = resultName.IndexOf(resultName.First(i => i == ']'));
                    check = resultName.Substring(startIndex, endIndex - startIndex);
                }
                else if (hasStage)
                {
                    int startIndex = 0;
                    int endIndex = resultName.IndexOf(resultName.First(i => i == ' '));
                    string increment = resultName.Substring(startIndex, endIndex - startIndex);

                    startIndex = resultName.IndexOf(resultName.First(i => i == '[')) + 1;
                    endIndex = resultName.IndexOf(resultName.First(i => i == ']'));
                    string stage = resultName.Substring(startIndex, endIndex - startIndex);

                    check = increment + " " + "[" + stage + "]";
                }
                else
                {
                    check = resultName;
                }
            }

            if (!check.Contains(caseModel.Name))
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Fail to read the results for " + caseModel.Name + " load case name");
            }

            for (int i = 0; i < _model.Value.Nodes.Count; i++)
            {
                NodeModel node = _model.Value.Nodes[i];
                double[] results = new double[6];
                if (St7.St7GetNodeResult(modelId, St7.rtNodeDisp, i + 1, resultCase, results) == 0)
                {
                    var displ = new NodeDisplResultModel(caseModel)
                    {
                        Displacement = new Vector3d(results[0], results[1], results[2]),
                        Rotation = new Vector3d(results[3], results[4], results[5]),
                        FreedomCase = freedomCase
                    };
                    node.Results.Add(displ);
                }

                if (St7.St7GetNodeResult(modelId, St7.rtNodeReact, i + 1, resultCase, results) == 0)
                {
                    var react = new NodeReactResultModel(caseModel)
                    {
                        Force = new Vector3d(results[0], results[1], results[2]),
                        Moment = new Vector3d(results[3], results[4], results[5]),
                        FreedomCase = freedomCase
                    };
                    node.Results.Add(react);
                }
            }

            for (int i = 0; i < _model.Value.Beams.Count; i++)
            {
                BeamModel beam = _model.Value.Beams[i];
                int ns = 0, nc = 0;
                double[] pos = new double[St7.kMaxBeamResult];
                double[] res = new double[St7.kMaxBeamResult];

                BeamOutputStationsModel.AttributeData modifier = BeamOutputStationsModel.GetModifiers(beam);
                int stationNumber = 5;
                if (modifier != null)
                    stationNumber = modifier.MinimumNumberOfStations;

                if (St7.St7GetBeamResultArray(modelId, St7.rtBeamForce, St7.stBeamPrincipal, i + 1, stationNumber, resultCase, ref ns, ref nc, pos, res) == 0)
                {
                    var listBuffer = new List<BeamForceResultModel>();
                    for (int s = 0; s < ns; s++)
                    {
                        double shear1 = res[s * nc + St7.ipBeamSF1];
                        double shear2 = res[s * nc + St7.ipBeamSF2];
                        double bending1 = res[s * nc + St7.ipBeamBM1];
                        double bending2 = res[s * nc + St7.ipBeamBM2];
                        if (Common.Helpers.StrausR3Helper.RotateOf90Deg(beam))
                        {
                            double buffer;
                            buffer = shear2;
                            shear2 = shear1;
                            shear1 = -buffer;
                            buffer = bending2;
                            bending2 = bending1;
                            bending1 = -buffer;
                        }
                        var result = new BeamForceResultModel(caseModel, pos[s], 0, "")
                        {
                            ShearForce = new Vector2d(shear1, shear2),
                            BendingMoment = new Vector2d(bending1, bending2),
                            AxialForce = res[s * nc + St7.ipBeamAxialF],
                            Torque = res[s * nc + St7.ipBeamTorque]
                        };
                        listBuffer.Add(result);
                    }

                    var ll = listBuffer.OrderBy(f => f.Station).ToArray();
                    for (int j = 0; j < ll.Length; j++)
                        beam.Results.Add(ll[j]);
                }
            }

            for (int j = 0; j < _model.Value.Plates.Count; j++)
            {
                PlateModel plate = _model.Value.Plates[j];
                int numPoints = 0;
                int numColumns = 0;
                double[] results = new double[St7.kMaxPlateResult];
                int average = St7.spNodesAverageNever;
                int plane = St7.psPlateMidPlane;
                int plateId = j + 1;
                int[] buffer = new int[St7.kMaxElementNode];

                St7.St7GetElementConnection(modelId, St7.tyPLATE, plateId, buffer);
                int[] nodes = new int[buffer[0]];

                for (int i = 0; i < nodes.Length; i++)
                {
                    nodes[i] = buffer[i + 1];
                }

                //Plate moment
                Vector3d[] m = new Vector3d[nodes.Length];
                if (St7.St7GetPlateResultArray(modelId, St7.rtPlateMoment, St7.stPlateLocal, plateId, resultCase, average, plane, 0, ref numPoints, ref numColumns, results) == 0)
                {
                    for (int i = 0; i < numPoints; i++)
                    {
                        m[i] = new Vector3d(results[i * numColumns + St7.ipPlateLocalxx], results[i * numColumns + St7.ipPlateLocalyy], results[i * numColumns + St7.ipPlateLocalxy]);
                    }

                    //Principal moments
                    double[] mMax = new double[nodes.Length];
                    double[] mMin = new double[nodes.Length];
                    double[] mAngle = new double[nodes.Length];
                    results = new double[St7.kMaxPlateResult];

                    if (St7.St7GetPlateResultArray(modelId, St7.rtPlateMoment, St7.stPlateCombined, plateId, resultCase, average, plane, 0, ref numPoints, ref numColumns, results) == 0)
                    {
                        for (int i = 0; i < numPoints; i++)
                        {
                            mMax[i] = results[i * numColumns + St7.ipPlateCombPrincipal11];
                            mMin[i] = results[i * numColumns + St7.ipPlateCombPrincipal22];
                            mAngle[i] = results[i * numColumns + St7.ipPlateCombPrincipalAngle];
                        }

                        //Axial forces
                        Vector3d[] f = new Vector3d[nodes.Length];
                        Vector2d[] shear = new Vector2d[nodes.Length];
                        results = new double[St7.kMaxPlateResult];

                        if (St7.St7GetPlateResultArray(modelId, St7.rtPlateForce, St7.stPlateLocal, plateId, resultCase, average, plane, 0, ref numPoints, ref numColumns, results) == 0)
                        {
                            for (int i = 0; i < numPoints; i++)
                            {
                                f[i] = new Vector3d(results[i * numColumns + St7.ipPlateLocalxx], results[i * numColumns + St7.ipPlateLocalyy], results[i * numColumns + St7.ipPlateLocalxy]);
                                shear[i] = new Vector2d(results[i * numColumns + St7.ipPlateLocalxz], results[i * numColumns + St7.ipPlateLocalyz]);
                            }

                            //Principal axial forces
                            double[] fMax = new double[nodes.Length];
                            double[] fMin = new double[nodes.Length];
                            double[] fAngle = new double[nodes.Length];
                            double[] fVM = new double[nodes.Length];
                            results = new double[St7.kMaxPlateResult];

                            if (St7.St7GetPlateResultArray(modelId, St7.rtPlateForce, St7.stPlateCombined, plateId, resultCase, average, plane, 0, ref numPoints, ref numColumns, results) == 0)
                            {
                                for (int i = 0; i < numPoints; i++)
                                {
                                    fMax[i] = results[i * numColumns + St7.ipPlateCombPrincipal11];
                                    fMin[i] = results[i * numColumns + St7.ipPlateCombPrincipal22];
                                    fAngle[i] = results[i * numColumns + St7.ipPlateCombPrincipalAngle];
                                    fVM[i] = results[i * numColumns + St7.ipPlateCombVonMises];
                                }

                                //Setting results
                                for (int i = 0; i < numPoints; i++)
                                {
                                    var result = new PlateForceResultModel(caseModel, nodes[i].ToString(), 0, "")
                                    {
                                        Force = f[i],
                                        ForceMax = fMax[i],
                                        ForceMin = fMin[i],
                                        ForceAngle = fAngle[i],
                                        ForceVonMises = fVM[i],
                                        Moment = m[i],
                                        MomentMax = mMax[i],
                                        MomentMin = mMin[i],
                                        MomentAngle = mAngle[i],
                                        TransverseShearForce = shear[i],
                                        TransverseShearForceMax = 0,
                                        TransverseShearForceAng = 0
                                    };
                                    plate.Results.Add(result);
                                }
                            }
                        }
                    }
                }
            }
        }

        protected override void AppendAdditionalComponentMenuItems(ToolStripDropDown menu)
        {
            base.AppendAdditionalComponentMenuItems(menu);
            Menu_AppendSeparator(menu);
            Menu_AppendItem(menu, "Reset", (s, e) => _model = new GH_Model());
        }

        public override bool Write(GH_IWriter writer)
        {
            bool success = base.Write(writer);
            if (!success)
                return false;

            //_model.Write(writer);

            return true;
        }

        public override bool Read(GH_IReader reader)
        {
            bool success = base.Read(reader);
            if (!success)
                return false;

            //_model.Read(reader);
            _just_loaded = true;

            return true;
        }

        protected override void BeforeSolveInstance()
        {
            base.BeforeSolveInstance();
            if (_just_loaded)
            {
                if (!Params.Input[0].VolatileData.IsEmpty)
                {
                    GH_Model input_model = (GH_Model)Params.Input[0].VolatileData.get_Branch(0)[0];
                    ModelHelper.RestoreModelGuids(input_model, ref _model);
                    _just_loaded = false;
                }
            }
        }

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

        /// <summary>
        /// Gets the unique ID for this component. Do not change this ID after release.
        /// </summary>
        public override Guid ComponentGuid => new("8c86c9fd-5896-4b07-a893-7d5a5fd955b8");
    }
}
303 files24 directories