using FeMM.Common.Helpers;
using FeMM.Common.Models;
using FeMM.Grasshopper.Components.Parameters;
using FeMM.Grasshopper.DataTypes;
using FeMM.Grasshopper.DataTypes.FeMM;
using FeMM.Grasshopper.DataTypes.MeCheck2;
using FeMM.Grasshopper.Helpers;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Data;
using Grasshopper.Kernel.Parameters;
using Maffeis.Checkers.Concrete.Results;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;

namespace FeMM.Grasshopper.Components.MeCheck2
{
    public abstract class PrintCheckImageMeCheckResultComponentBase : GH_Component
    {
        protected bool _run;

        protected const double FROMNTOKN = 0.001;
        protected const double FROMNMTOKNM = 0.000001;

        protected Color[] ComboColors =
        [
            Color.Red,
            Color.Green,
            Color.Blue,
            Color.Orange,
            Color.Magenta,
            Color.Yellow,
            Color.Purple,
            Color.Orchid,
            Color.Aquamarine,
        ];

        protected readonly List<string> _forceComponent =
        [
            "σ1 concrete",
            "σ2 rebar",
            "σ3 rebar",
            "σ4 concrete",
            "σ5 steel",
            "σ6 steel",
            "σ7 steel",
            "σ8 steel",
            "τ6",
            "τ7",
            "σ6 id",
            "σ7 id",
            "ε1 concrete",
            "ε8 steel",
        ];

        /// <summary>
        /// Initializes a new instance of the MyComponent1 class.
        /// </summary>
        public PrintCheckImageMeCheckResultComponentBase()
          : base("Print MeCheck Results", "PI", "Create the check image of super element check", CategoryNameConstants.CATEGORY_CHECKS, CategoryNameConstants.SUBCATEGORY_MECHECK2)
        {
        }

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

        protected abstract void RegisterInputMarks(GH_InputParamManager pManager);

        protected abstract void GetInputMarks(IGH_DataAccess DA, ref int nnn, ref bool showMarks, List<double> customMarks);

        /// <summary>
        /// Registers all the input parameters for this component.
        /// </summary>
        protected override void RegisterInputParams(GH_InputParamManager pManager)
        {
            pManager.AddGenericParameter("FeMM Model", "FM", "The FEM models (more than one for stages)", GH_ParamAccess.item);
            pManager.AddGenericParameter("Super-Element Beam", "SE", "The Super-Element Beam", GH_ParamAccess.list);
            pManager.AddParameter(new StressAnalysisResultMeCheckParam(), "Results", "R", "The MeCheck Results", GH_ParamAccess.tree);
            pManager.AddIntegerParameter("Result component", "FC", "The force component to print", GH_ParamAccess.item, 4);
            Param_Integer param = (Param_Integer)pManager[pManager.ParamCount - 1];
            for (int i = 0; i < _forceComponent.Count; i++)
                param.AddNamedValue(_forceComponent[i], i);
            pManager.AddTextParameter("Combinations", "C", "The list of the combinations to draw", GH_ParamAccess.list);
            pManager[pManager.ParamCount - 1].Optional = true;
            pManager.AddBooleanParameter("Show Min/Max Combo", "SMM", "If true, show the combinations that maximize and minimize the envelop", GH_ParamAccess.item, true);
            pManager.AddGenericParameter("Additional values", "AV", "List of curves ​​to add to the graph", GH_ParamAccess.list);
            pManager[pManager.ParamCount - 1].Optional = true;
            pManager.AddNumberParameter("Reference Values", "RV", "List of reference values ​​to add to the graph", GH_ParamAccess.list);
            pManager[pManager.ParamCount - 1].Optional = true;
            pManager.AddTextParameter("File Path", "P", "The path of the file", GH_ParamAccess.item);
            pManager.AddTextParameter("Graphic Title", "T", "The title of the graphic", GH_ParamAccess.item, "");
            pManager.AddIntegerParameter("Significant digits", "SD", "Significant digits of ascissas", GH_ParamAccess.item, 2);
            pManager.AddBooleanParameter("Keep Running", "KR", "Run", GH_ParamAccess.item, false);
            RegisterInputMarks(pManager);
        }

        /// <summary>
        /// Registers all the output parameters for this component.
        /// </summary>
        protected override void RegisterOutputParams(GH_OutputParamManager pManager)
        {
        }

        /// <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 = "";
            var model = new GH_Model();
            var beams = new List<GH_CompositeBeam>();
            var comboToDraw = new List<string>();
            int resultComponent = 0;
            bool showMinMax = true;
            var additionalValue = new List<GraphicCreator.Curve>();
            var referenceValues = new List<double>();
            string savePath = "";
            string title = "";
            int significantDigits = 0;
            bool keepRunning = false;

            int nnn = 0;

            if (!DA.GetData(nnn++, ref model))
                return;
            if (!DA.GetDataList(nnn++, beams))
                return;
            if (!DA.GetDataTree(nnn++, out GH_Structure<GH_StressAnalysisResultMeCheck> inputTree))
                return;
            if (!DA.GetData(nnn++, ref resultComponent))
                return;
            DA.GetDataList(nnn++, comboToDraw);
            DA.GetData(nnn++, ref showMinMax);
            DA.GetDataList(nnn++, additionalValue);
            DA.GetDataList(nnn++, referenceValues);
            DA.GetData(nnn++, ref savePath);
            DA.GetData(nnn++, ref title);
            DA.GetData(nnn++, ref significantDigits);
            if (!DA.GetData(nnn++, ref keepRunning))
                return;

            bool showMarks = true;
            var customMarks = new List<double>();
            GetInputMarks(DA, ref nnn, ref showMarks, customMarks);

            if (_run || keepRunning)
            {
                if (model.Value == null)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Null model");
                    Message = "Error";
                    _run = false;
                    return;
                }

                try
                {
                    var map = new Dictionary<int, Dictionary<int, List<StressAnalysisResultMeCheck>>>();

                    foreach (var path in inputTree.Paths)
                    {
                        if (path.Indices.Length != 2)
                            continue;

                        int beam = path.Indices[0];
                        int section = path.Indices[1];

                        if (!map.TryGetValue(beam, out var sectionMap))
                        {
                            sectionMap = [];
                            map[beam] = sectionMap;
                        }

                        if (!sectionMap.TryGetValue(section, out var list))
                        {
                            list = [];
                            sectionMap[section] = list;
                        }

                        foreach (var goo in inputTree.get_Branch(path))
                        {
                            if (goo is GH_StressAnalysisResultMeCheck meCheck)
                                if (meCheck.IsValid)
                                    list.Add(meCheck.Value);
                        }
                    }

                    int beamCount = beams.Count;
                    var meCheckResults = new StressAnalysisResultMeCheck[beamCount][][];

                    for (int i = 0; i < beamCount; i++)
                    {
                        if (!map.TryGetValue(i, out var sections))
                        {
                            meCheckResults[i] = [];
                            continue;
                        }

                        int maxSection = sections.Keys.Max() + 1;
                        meCheckResults[i] = new StressAnalysisResultMeCheck[maxSection][];

                        foreach (var kv in sections)
                            meCheckResults[i][kv.Key] = [.. kv.Value];
                    }

                    var gc = new GraphicCreator(1500.0F, 900.0F, true)
                    {
                        Title = title,
                        CustomMarkPositions = customMarks
                    };

                    List<string> comboName = [.. model.Value.Combinations.Select(j => j.Name)];
                    double x = 0;
                    int absoluteMinIndex = 0;
                    int absoluteMaxIndex = 0;
                    double absoluteMinValue = 0;
                    double absoluteMaxValue = 0;

                    x = 0;
                    // Set the minimum/maximum values
                    for (int i = 0; i < beams.Count; i++)
                    {
                        var stationBuffer = new HashSet<double>();
                        for (int k = 0; k < beams[i].Value.Results.Count; k++)
                        {
                            BeamForceResultModel force = (BeamForceResultModel)beams[i].Value.Results[k];
                            double dist = Math.Round(force.NormalizedLength ? force.Station * beams[i].Value.Length : force.Station, 15);
                            stationBuffer.Add(dist);
                        }
                        double[] dists = [.. stationBuffer];

                        var v = new List<(double dist, double max, double min)>();
                        for (int n = 0; n < dists.Length; n++)
                        {
                            StressAnalysisResultMeCheck[] fff = meCheckResults[i][n];
                            double min = 0;
                            double max = 0;
                            switch (resultComponent)
                            {
                                case 0:
                                    for (int j = 0; j < fff.Length; j++)
                                    {
                                        double combonentBuffer = fff[j].Point1_ConcreteSigma;
                                        GraphicCreator.MinMax(j, combonentBuffer, true, ref absoluteMaxValue, ref absoluteMinValue, ref absoluteMaxIndex, ref absoluteMinIndex, ref max, ref min);
                                    }
                                    break;

                                case 1:
                                    for (int j = 0; j < fff.Length; j++)
                                    {
                                        double combonentBuffer = fff[j].Point2_RebarSigma;
                                        GraphicCreator.MinMax(j, combonentBuffer, true, ref absoluteMaxValue, ref absoluteMinValue, ref absoluteMaxIndex, ref absoluteMinIndex, ref max, ref min);
                                    }
                                    break;

                                case 2:
                                    for (int j = 0; j < fff.Length; j++)
                                    {
                                        double combonentBuffer = fff[j].Point3_RebarSigma;
                                        GraphicCreator.MinMax(j, combonentBuffer, true, ref absoluteMaxValue, ref absoluteMinValue, ref absoluteMaxIndex, ref absoluteMinIndex, ref max, ref min);
                                    }
                                    break;

                                case 3:
                                    for (int j = 0; j < fff.Length; j++)
                                    {
                                        double combonentBuffer = fff[j].Point4_ConcreteSigma;
                                        GraphicCreator.MinMax(j, combonentBuffer, true, ref absoluteMaxValue, ref absoluteMinValue, ref absoluteMaxIndex, ref absoluteMinIndex, ref max, ref min);
                                    }
                                    break;

                                case 4:
                                    for (int j = 0; j < fff.Length; j++)
                                    {
                                        double combonentBuffer = fff[j].Point5_SteelSigma;
                                        GraphicCreator.MinMax(j, combonentBuffer, true, ref absoluteMaxValue, ref absoluteMinValue, ref absoluteMaxIndex, ref absoluteMinIndex, ref max, ref min);
                                    }
                                    break;

                                case 5:
                                    for (int j = 0; j < fff.Length; j++)
                                    {
                                        double combonentBuffer = fff[j].Point6_SteelSigma;
                                        GraphicCreator.MinMax(j, combonentBuffer, true, ref absoluteMaxValue, ref absoluteMinValue, ref absoluteMaxIndex, ref absoluteMinIndex, ref max, ref min);
                                    }
                                    break;

                                case 6:
                                    for (int j = 0; j < fff.Length; j++)
                                    {
                                        double combonentBuffer = fff[j].Point7_SteelSigma;
                                        GraphicCreator.MinMax(j, combonentBuffer, true, ref absoluteMaxValue, ref absoluteMinValue, ref absoluteMaxIndex, ref absoluteMinIndex, ref max, ref min);
                                    }
                                    break;

                                case 7:
                                    for (int j = 0; j < fff.Length; j++)
                                    {
                                        double combonentBuffer = fff[j].Point8_SteelSigma;
                                        GraphicCreator.MinMax(j, combonentBuffer, true, ref absoluteMaxValue, ref absoluteMinValue, ref absoluteMaxIndex, ref absoluteMinIndex, ref max, ref min);
                                    }
                                    break;

                                case 8:
                                    for (int j = 0; j < fff.Length; j++)
                                    {
                                        double combonentBuffer = fff[j].Point6_SteelTau;
                                        GraphicCreator.MinMax(j, combonentBuffer, true, ref absoluteMaxValue, ref absoluteMinValue, ref absoluteMaxIndex, ref absoluteMinIndex, ref max, ref min);
                                    }
                                    break;

                                case 9:
                                    for (int j = 0; j < fff.Length; j++)
                                    {
                                        double combonentBuffer = fff[j].Point7_SteelTau;
                                        GraphicCreator.MinMax(j, combonentBuffer, true, ref absoluteMaxValue, ref absoluteMinValue, ref absoluteMaxIndex, ref absoluteMinIndex, ref max, ref min);
                                    }
                                    break;

                                case 10:
                                    for (int j = 0; j < fff.Length; j++)
                                    {
                                        double combonentBuffer = fff[j].Point6_SteelSigmaId;
                                        GraphicCreator.MinMax(j, combonentBuffer, true, ref absoluteMaxValue, ref absoluteMinValue, ref absoluteMaxIndex, ref absoluteMinIndex, ref max, ref min);
                                    }
                                    break;

                                case 11:
                                    for (int j = 0; j < fff.Length; j++)
                                    {
                                        double combonentBuffer = fff[j].Point7_SteelSigmaId;
                                        GraphicCreator.MinMax(j, combonentBuffer, true, ref absoluteMaxValue, ref absoluteMinValue, ref absoluteMaxIndex, ref absoluteMinIndex, ref max, ref min);
                                    }
                                    break;

                                case 12:
                                    for (int j = 0; j < fff.Length; j++)
                                    {
                                        double combonentBuffer = fff[j].Point1_ConcreteEpsilon;
                                        GraphicCreator.MinMax(j, combonentBuffer, true, ref absoluteMaxValue, ref absoluteMinValue, ref absoluteMaxIndex, ref absoluteMinIndex, ref max, ref min);
                                    }
                                    break;

                                case 13:
                                    for (int j = 0; j < fff.Length; j++)
                                    {
                                        double combonentBuffer = fff[j].Point8_SteelEpsilon;
                                        GraphicCreator.MinMax(j, combonentBuffer, true, ref absoluteMaxValue, ref absoluteMinValue, ref absoluteMaxIndex, ref absoluteMinIndex, ref max, ref min);
                                    }
                                    break;
                            }

                            double mod = 0;
                            if (n == dists.Length - 1)
                                mod = -1;
                            v.Add((x + dists[n] - mod, max, min));
                        }

                        var sorted = v.OrderBy(a => a.dist).ToList();
                        for (int k = 0; k < sorted.Count; k++)
                            gc.AddMaximumValues(sorted[k].dist, sorted[k].min, sorted[k].max);

                        x += dists.Max();
                        gc.FrameLenths.Add(dists.Max());
                    }

                    if (referenceValues.Count > 0)
                    {
                        for (int i = 0; i < referenceValues.Count; i++)
                        {
                            gc.AddReferenceLine(referenceValues[i], Color.FromArgb(100, 100, 100));
                            gc.AddMaxValue(referenceValues[i]);
                            gc.AddMinValue(referenceValues[i]);
                        }
                    }

                    if (additionalValue.Count > 0)
                    {
                        for (int i = 0; i < additionalValue.Count; i++)
                        {
                            gc.AddCurve(additionalValue[i].Name, additionalValue[i].Color, additionalValue[i].Thickness);
                            for (int j = 0; j < additionalValue[i].Values.Count; j++)
                                gc.AddCurveValue(additionalValue[i].Name, additionalValue[i].Values[j][0], additionalValue[i].Values[j][1]);
                        }
                    }

                    if (showMinMax)
                    {
                        comboToDraw.Insert(0, comboName[absoluteMaxIndex]);
                        comboToDraw.Insert(1, comboName[absoluteMinIndex]);
                    }

                    if (comboToDraw.Count > 0)
                    {
                        for (int c = 0; c < comboToDraw.Count; c++)
                        {
                            int comboIndex = comboName.IndexOf(comboToDraw[c]);

                            Color color = ComboColors[c % ComboColors.Length];
                            gc.AddCurve(comboToDraw[c], color);

                            x = 0;

                            for (int i = 0; i < beams.Count; i++)
                            {
                                var stationBuffer = new HashSet<double>();
                                var cc = new List<(string combo, double delta, double value)>();

                                for (int k = 0; k < beams[i].Value.Results.Count; k++)
                                {
                                    BeamForceResultModel force = (BeamForceResultModel)beams[i].Value.Results[k];
                                    double dist = Math.Round(force.NormalizedLength ? force.Station * beams[i].Value.Length : force.Station, 15);
                                    stationBuffer.Add(dist);
                                }
                                double[] dists = [.. stationBuffer];

                                for (int n = 0; n < dists.Length; n++)
                                {
                                    StressAnalysisResultMeCheck[] fff = meCheckResults[i][n];
                                    double vv = 0;
                                    switch (resultComponent)
                                    {
                                        case 0:
                                            vv = fff[comboIndex].Point1_ConcreteSigma;
                                            break;
                                        case 1:
                                            vv = fff[comboIndex].Point2_RebarSigma;
                                            break;
                                        case 2:
                                            vv = fff[comboIndex].Point3_RebarSigma;
                                            break;
                                        case 3:
                                            vv = fff[comboIndex].Point4_ConcreteSigma;
                                            break;
                                        case 4:
                                            vv = fff[comboIndex].Point5_SteelSigma;
                                            break;
                                        case 5:
                                            vv = fff[comboIndex].Point6_SteelSigma;
                                            break;
                                        case 6:
                                            vv = fff[comboIndex].Point7_SteelSigma;
                                            break;
                                        case 7:
                                            vv = fff[comboIndex].Point8_SteelSigma;
                                            break;
                                        case 8:
                                            vv = fff[comboIndex].Point6_SteelTau;
                                            break;
                                        case 9:
                                            vv = fff[comboIndex].Point7_SteelTau;
                                            break;
                                        case 10:
                                            vv = fff[comboIndex].Point6_SteelSigmaId;
                                            break;
                                        case 11:
                                            vv = fff[comboIndex].Point7_SteelSigmaId;
                                            break;
                                        case 12:
                                            vv = fff[comboIndex].Point1_ConcreteEpsilon;
                                            break;
                                        case 13:
                                            vv = fff[comboIndex].Point8_SteelEpsilon;
                                            break;
                                    }

                                    double mod = 0;
                                    if (n == dists.Length - 1)
                                        mod = -1;
                                    cc.Add((comboToDraw[c], x + dists[n] - mod, vv));
                                }

                                var sorted = cc.OrderBy(a => a.delta).ToList();

                                for (int k = 0; k < sorted.Count; k++)
                                    gc.AddCurveValue(sorted[k].combo, sorted[k].delta, sorted[k].value);

                                x += dists.Max();
                            }
                        }
                    }

                    switch (resultComponent)
                    {
                        case 0:
                        case 1:
                        case 2:
                        case 3:
                        case 4:
                        case 5:
                        case 6:
                        case 7:
                        case 8:
                        case 9:
                        case 10:
                        case 11:
                            gc.YAxisTitle = "MPa";
                            break;

                        case 12:
                        case 13:
                            gc.YAxisTitle = "";
                            break;
                    }

                    gc.XAxisTitle = "m";

                    double _valuesScaleRatio = 1.0;
                    Bitmap _graphicImage = gc.Create(true, (float)_valuesScaleRatio, significantDigits, showMarks);

                    _graphicImage.Save(savePath, ImageFormat.Png);
                    _run = false;
                }
                catch (Exception e)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"Fail to create the image: {e}");
                    _run = false;
                }
            }
        }

        /// <summary>
        /// Provides an Icon for the component.
        /// </summary>
        protected override Bitmap Icon => Properties.Resources.PrintCompositeSectionResultsIcon;
    }
}
303 files24 directories