using FeMM.Common.Helpers;
using FeMM.Common.Models;
using FeMM.Grasshopper.DataTypes.FeMM;
using FeMM.Grasshopper.Helpers;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Data;
using Grasshopper.Kernel.Parameters;
using Grasshopper.Kernel.Types;
using Maffeis.Utilities.Units;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Versioning;

namespace FeMM.Grasshopper.Components.Checks
{
#if NETCOREAPP
    [SupportedOSPlatform("windows")]
#endif
    public class RCFrameChecksComponent : GH_Component
    {

        /// <summary>
        /// Initializes a new instance of the BeamComponent class.
        /// </summary>
        public RCFrameChecksComponent()
          : base("RC frame checks", "RCFC", "Check RC frames", CategoryNameConstants.CATEGORY_CHECKS, CategoryNameConstants.SUBCATEGORY_MECHECK)
        {
        }

        /// <summary>
        /// Registers all the input parameters for this component.
        /// </summary>
        protected override void RegisterInputParams(GH_InputParamManager pManager)
        {
            int n;
            pManager.AddGenericParameter("RC Beams", "B", "Beams", GH_ParamAccess.list);
            pManager[pManager.ParamCount - 1].Optional = true;
            pManager.AddNumberParameter("B,Ascissas", "B,Ls", "Location of sections of beams", GH_ParamAccess.tree);
            pManager[pManager.ParamCount - 1].Optional = true;
            pManager.AddGenericParameter("RC Pillars", "P", "Pillars", GH_ParamAccess.list);
            pManager[pManager.ParamCount - 1].Optional = true;
            pManager.AddNumberParameter("P,Ascissas", "P,Ls", "Location of sections of pillars", GH_ParamAccess.tree);
            pManager[pManager.ParamCount - 1].Optional = true;
            pManager.AddNumberParameter("Long As", "LAs", "Longitudinal reinforcement area of pillars in all sections", GH_ParamAccess.tree);
            pManager[pManager.ParamCount - 1].Optional = true;
            pManager.AddNumberParameter(char.ConvertFromUtf32(0x3B3) + "s", char.ConvertFromUtf32(0x3B3) + "s", "Partial safety factor of rebar", GH_ParamAccess.item, 1.15);
            pManager.AddNumberParameter(char.ConvertFromUtf32(0x3B3) + "c", char.ConvertFromUtf32(0x3B3) + "c", "Partial safety factor of concrete", GH_ParamAccess.item, 1.5);
            pManager.AddNumberParameter(char.ConvertFromUtf32(0x3B1) + "cc", char.ConvertFromUtf32(0x3B1) + "cc", char.ConvertFromUtf32(0x3B1) + "cc factor of concrete", GH_ParamAccess.item, 0.85);
            pManager.AddNumberParameter("fyk", "fyk", "Caratheristic yield resistance of rebar", GH_ParamAccess.item);
            n = pManager.AddIntegerParameter("Length unit", "LU", "Units of the length", GH_ParamAccess.item);
            Param_Integer length_param = (Param_Integer)pManager[n];
            foreach (SteelFrameChecksComponent.LengthUnits value in Enum.GetValues(typeof(SteelFrameChecksComponent.LengthUnits)))
                length_param.AddNamedValue(value.GetDescription(), (int)value);
            n = pManager.AddIntegerParameter("Force unit", "FU", "Units of the forces", GH_ParamAccess.item);
            Param_Integer force_param = (Param_Integer)pManager[n];
            foreach (SteelFrameChecksComponent.ForceUnits value in Enum.GetValues(typeof(SteelFrameChecksComponent.ForceUnits)))
                force_param.AddNamedValue(value.GetDescription(), (int)value);
            //pManager.AddNumberParameter("MinDeflectionFactor", "MDF", "Minimum deflection factor (L/factor) for deflection checks", GH_ParamAccess.item, 400);
        }

        /// <summary>
        /// Registers all the output parameters for this component.
        /// </summary>
        protected override void RegisterOutputParams(GH_OutputParamManager pManager)
        {
            pManager.AddGenericParameter("Beams", "B", "Beams", GH_ParamAccess.list);
            pManager.AddNumberParameter("Beams ascissas", "BAsc", "Ascissas of RC beams", GH_ParamAccess.tree);
            pManager.AddNumberParameter("Beam resistance URs", "BRUR", "The maximum resistance utilization ratios, one for each beam", GH_ParamAccess.tree);
            pManager.AddGenericParameter("Pillars", "P", "Pillars", GH_ParamAccess.list);
            pManager.AddNumberParameter("Pillar ascissas", "PAsc", "Ascissas of RC pillars", GH_ParamAccess.tree);
            pManager.AddNumberParameter("Pillar resistance URs", "PRUR", "The maximum resistance utilization ratios, one for each pillar", GH_ParamAccess.tree);
        }

        /// <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)
        {
            var beams = new List<GH_Beam>();
            GH_Structure<GH_Number> beamAscissas = null;
            var pillars = new List<GH_Beam>();
            GH_Structure<GH_Number> pillarAscissas = null;
            GH_Structure<GH_Number> pillarLongAs = null;
            double gammaS = 0;
            double gammaC = 0;
            double alfaCC = 0;
            double fyk = 0;
            int lengthValue = -1;
            int forceValue = -1;
            //double minDeflectionFactor = 0;

            DA.GetDataList(0, beams);
            DA.GetDataTree(1, out beamAscissas);
            DA.GetDataList(2, pillars);
            DA.GetDataTree(3, out pillarAscissas);
            DA.GetDataTree(4, out pillarLongAs);
            if (!DA.GetData(5, ref gammaS))
                return;
            if (!DA.GetData(6, ref gammaC))
                return;
            if (!DA.GetData(7, ref alfaCC))
                return;
            if (!DA.GetData(8, ref fyk))
                return;
            if (!DA.GetData(9, ref lengthValue))
                return;
            if (!DA.GetData(10, ref forceValue))
                return;

            if (pillars.Count == 0 && beams.Count == 0)
            {
                return;
            }


            if (pillars.Count > 0)
            {
                if (pillars.Count != pillarAscissas.Branches.Count ||
                    pillars.Count != pillarLongAs.Branches.Count)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid data dimension");
                    return;
                }
                for (int i = 0; i < pillars.Count; i++)
                {
                    if (pillarAscissas[i].Count != pillarLongAs[i].Count)
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid data dimension");
                        return;
                    }
                }
            }
            if (beams.Count > 0)
            {
                if (beams.Count != beamAscissas.Branches.Count)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid data dimension");
                    return;
                }
            }

            Dictionary<BeamModel, List<double>> beamAscissasList, pillarAscissasList;
            Dictionary<BeamModel, List<double>> pillarLongAsList;
            var beamURs = new Dictionary<BeamModel, List<double>>();
            var pillarURs = new Dictionary<BeamModel, List<double>>();
            SteelFrameChecksComponent.LengthUnits lengthUnits;
            SteelFrameChecksComponent.ForceUnits forceUnits;
            double fyd;
            double toll;
            List<double> bufferURs;

            lengthUnits = (SteelFrameChecksComponent.LengthUnits)lengthValue;
            forceUnits = (SteelFrameChecksComponent.ForceUnits)forceValue;

            UnitsConvert.ForceUnits utilsForceCode;
            UnitsConvert.LengthUnits utilsLengthCode;
            switch (forceUnits)
            {
                case SteelFrameChecksComponent.ForceUnits.N:
                    utilsForceCode = UnitsConvert.ForceUnits.N;
                    break;
                case SteelFrameChecksComponent.ForceUnits.daN:
                    utilsForceCode = UnitsConvert.ForceUnits.daN;
                    break;
                case SteelFrameChecksComponent.ForceUnits.kN:
                    utilsForceCode = UnitsConvert.ForceUnits.kN;
                    break;
                default:
                    throw new NotSupportedException();
            }

            switch (lengthUnits)
            {
                case SteelFrameChecksComponent.LengthUnits.mm:
                    utilsLengthCode = UnitsConvert.LengthUnits.mm;
                    break;
                case SteelFrameChecksComponent.LengthUnits.cm:
                    utilsLengthCode = UnitsConvert.LengthUnits.cm;
                    break;
                case SteelFrameChecksComponent.LengthUnits.m:
                    utilsLengthCode = UnitsConvert.LengthUnits.m;
                    break;
                default:
                    throw new NotSupportedException();
            }

            beamAscissasList = [];
            for (int i = 0; i < beams.Count; i++)
            {
                List<double> ascissas;
                ascissas = [];
                for (int j = 0; j < beamAscissas[i].Count; j++)
                {
                    ascissas.Add(beamAscissas[i][j].Value);
                }
                beamAscissasList.Add(beams[i].Value, ascissas);
            }

            pillarAscissasList = [];
            pillarLongAsList = [];
            for (int i = 0; i < pillars.Count; i++)
            {
                List<double> ascissas, longAs;
                ascissas = [];
                for (int j = 0; j < pillarAscissas[i].Count; j++)
                {
                    ascissas.Add(pillarAscissas[i][j].Value);
                }
                pillarAscissasList.Add(pillars[i].Value, ascissas);

                longAs = [];
                for (int j = 0; j < pillarLongAs[i].Count; j++)
                {
                    longAs.Add(pillarLongAs[i][j].Value);
                }
                pillarLongAsList.Add(pillars[i].Value, longAs);
            }


            switch (lengthUnits)
            {
                case SteelFrameChecksComponent.LengthUnits.cm:
                    toll = 0.01;
                    break;
                case SteelFrameChecksComponent.LengthUnits.m:
                    toll = 0.0001;
                    break;
                case SteelFrameChecksComponent.LengthUnits.mm:
                    toll = 0.1;
                    break;
                default:
                    throw new NotSupportedException();
            }

            fyd = fyk / gammaS;

            //Beam Resistance
            for (int counter = 0; counter < beams.Count; counter++)
            {
                List<double> ascissas;
                GH_Beam beam;
                BeamPropertyModel pp;
                double aCls, w11Cls, w22Cls, fck, fcd;

                beam = beams[counter];
                ascissas = beamAscissasList[beam.Value];
                pp = beam.Value.BeamProperty;

                aCls = pp.SectionArea;
                w11Cls = pp.W11;
                w22Cls = pp.W22;

                fck = UnitsConvert.ConvertFromDefaultUnits(pp.Material.SpecificCompressiveStrength, utilsForceCode, 1, utilsLengthCode, -2);
                //switch (lengthCode)
                //{
                //    case SteelFrameChecksComponent.LengthUnits.cm:
                //        fck /= 10000;
                //        break;
                //    case SteelFrameChecksComponent.LengthUnits.m:
                //        break;
                //    case SteelFrameChecksComponent.LengthUnits.mm:
                //        fck /= 1000000;
                //        break;
                //    default:
                //        throw new NotSupportedException();
                //}
                //switch (forceCode)
                //{
                //    case SteelFrameChecksComponent.ForceUnits.daN:
                //        fck /= 10;
                //        break;
                //    case SteelFrameChecksComponent.ForceUnits.kN:
                //        fck /= 1000;
                //        break;
                //    case SteelFrameChecksComponent.ForceUnits.N:
                //        break;
                //    default:
                //        throw new NotSupportedException();
                //}
                fcd = fck * alfaCC / gammaC;

                if (!beamURs.TryGetValue(beam.Value, out bufferURs))
                {
                    bufferURs = [];
                    for (int ascCount = 0; ascCount < ascissas.Count; ascCount++)
                    {
                        bufferURs.Add(0);
                    }
                    beamURs.Add(beam.Value, bufferURs);
                }

                BeamForceResultModel[] results = [.. beam.Value.Results.
                        Where(r => r.GetType() == typeof(BeamForceResultModel)).Cast<BeamForceResultModel>()];
                for (int resCounter = 0; resCounter < results.Length; resCounter++)
                {
                    double n, m11, m22;
                    int ascissaIndex;
                    BeamForceResultModel res;
                    double sigmaC;

                    res = results[resCounter];

                    n = res.AxialForce;
                    m11 = res.BendingMoment.Y;
                    m22 = res.BendingMoment.X;

                    ascissaIndex = -1;
                    for (int i = 0; i < ascissas.Count; i++)
                    {
                        if (Math.Abs(ascissas[i] - res.Station) < toll)
                        {
                            ascissaIndex = i;
                            break;
                        }
                    }
                    if (ascissaIndex < 0)
                    {
                        throw new NotSupportedException("Ascissa not found");
                    }

                    //determining max sigma compression on cls
                    sigmaC = -Math.Abs(m11) / w11Cls - Math.Abs(m22) / w22Cls + n / aCls;

                    if (sigmaC < 0)
                    {
                        bufferURs[ascissaIndex] = Math.Max(bufferURs[ascissaIndex], Math.Abs(sigmaC) / fcd);
                    }
                }
            }

            //Pillars Resistance
            for (int counter = 0; counter < pillars.Count; counter++)
            {
                List<double> ascissas;
                GH_Beam pillar;
                double dimension11, dimension22;
                BeamPropertyModel pp;
                double aCls, fck, fcd;

                pillar = pillars[counter];
                ascissas = pillarAscissasList[pillar.Value];
                pp = pillar.Value.BeamProperty;

                switch (pp.SectionType)
                {
                    case SectionModel.SectionTypes.SolidRectangle:
                        {
                            dimension11 = pp.B;
                            dimension22 = pp.D;
                            break;
                        }
                    default:
                        throw new NotImplementedException("Section not supported");
                }

                aCls = dimension11 * dimension22;
                fck = UnitsConvert.ConvertFromDefaultUnits(pp.Material.SpecificCompressiveStrength, utilsForceCode, 1, utilsLengthCode, -2);

                fcd = fck * alfaCC / gammaC;

                if (!pillarURs.TryGetValue(pillar.Value, out bufferURs))
                {
                    bufferURs = [];
                    for (int ascCount = 0; ascCount < ascissas.Count; ascCount++)
                    {
                        bufferURs.Add(0);
                    }
                    pillarURs.Add(pillar.Value, bufferURs);
                }

                BeamForceResultModel[] results = [.. pillar.Value.Results.
                        Where(r => r.GetType() == typeof(BeamForceResultModel)).Cast<BeamForceResultModel>()];
                for (int resCounter = 0; resCounter < results.Length; resCounter++)
                {
                    double n;
                    double aS;
                    double nRd;
                    int ascissaIndex;
                    BeamForceResultModel res;

                    res = results[resCounter];

                    n = res.AxialForce;

                    ascissaIndex = -1;
                    for (int i = 0; i < ascissas.Count; i++)
                    {
                        if (Math.Abs(ascissas[i] - res.Station) < toll)
                        {
                            ascissaIndex = i;
                            break;
                        }
                    }
                    if (ascissaIndex < 0)
                    {
                        throw new NotSupportedException("Ascissa not found");
                    }

                    aS = pillarLongAsList[pillar.Value][ascissaIndex];

                    nRd = aCls * fcd + aS * fyd;

                    //Longitudinal URs
                    bufferURs[ascissaIndex] = Math.Max(bufferURs[ascissaIndex], Math.Abs(n) / nRd);
                }
            }

            ////Beams Deflection
            //List<CreateBeamReinforcementComponent.BeamData> disjoinedBeams;
            //disjoinedBeams = new List<CreateBeamReinforcementComponent.BeamData>();
            //foreach (GH_Beam beam in beams)
            //{
            //    disjoinedBeams.Add(new CreateBeamReinforcementComponent.BeamData(beam.Value));
            //}
            ////attaching subsequent beams
            //List<CreateBeamReinforcementComponent.BeamDataSequence> seqs;
            //seqs = CreateBeamReinforcementComponent.BeamDataSequence.GetSequences(disjoinedBeams, model.Value);
            //foreach (int beam in beamList)
            //{
            //    beamDeformationURs.Add(beam, 0);
            //}
            //if (cases == 2 || cases == 0)
            //{
            //    //LoadCases
            //    for (int caseCounter = 1; caseCounter <= primary; caseCounter++)
            //    {
            //        if (model.Value.LoadCases[caseCounter - 1].Name.StartsWith(CombinationComponent.SLS_PREFIX))
            //        {
            //            Straus7St7SteelFrameCheckComponent.GetDeformationChecks(seqs, model, modelId, caseCounter, minDeflectionFactor,
            //                                                                    beamAscissasList, ref beamDeformationURs);
            //        }
            //    }
            //}

            //if (cases == 2 || cases == 1)
            //{
            //    //Combs
            //    for (int caseCounter = primary + 1; caseCounter <= primary + secondary; caseCounter++)
            //    {
            //        int combinationNumber;
            //        combinationNumber = caseCounter - primary - 1;
            //        if (model.Value.LoadCaseCombinations[combinationNumber].Name.StartsWith(CombinationComponent.SLS_PREFIX))
            //        {
            //            Straus7St7SteelFrameCheckComponent.GetDeformationChecks(seqs, model, modelId, caseCounter, minDeflectionFactor,
            //                                                                    beamAscissasList, ref beamDeformationURs);
            //        }
            //    }
            //}

            List<GH_Beam> beamList, pillarList;

            beamList = [];
            foreach (KeyValuePair<BeamModel, List<double>> kvp in beamURs)
            {
                beamList.Add(new GH_Beam(kvp.Key));
            }
            pillarList = [];
            foreach (KeyValuePair<BeamModel, List<double>> kvp in pillarURs)
            {
                pillarList.Add(new GH_Beam(kvp.Key));
            }

            DA.SetDataList(0, beamList);
            DA.SetDataTree(1, beamAscissas);
            DA.SetDataTree(2, SteelFrameChecksComponent.GetStructure(beamURs));
            DA.SetDataList(3, pillarList);
            DA.SetDataTree(4, pillarAscissas);
            DA.SetDataTree(5, SteelFrameChecksComponent.GetStructure(pillarURs));
        }


        public override GH_Exposure Exposure => GH_Exposure.tertiary;

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

        /// <summary>
        /// Gets the unique ID for this component. Do not change this ID after release.
        /// </summary>
        public override Guid ComponentGuid => new("9CDB25D6-C9B5-4487-84F2-D093F6C6B08C");
    }
}
303 files24 directories