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.Types;
using System;
using System.Collections.Generic;

namespace FeMM.Grasshopper.Components.ElementProperties
{
    public class BeamPropertyComponent : GH_Component
    {
        protected Dictionary<int, string> _propertyTypeOptions = new() {
            { 0, "SpringDamper [0]" },
            { 1, "Cable [1]" },
            { 2, "Truss [2]" },
            { 3, "Cutoff Bar [3]" },
            { 5, "Beam [5]" },
            { 8, "Connection [8]" } };

        private bool _disableSolution;
        private BeamPropertyType? _prevType;

        /// <summary>
        /// Initializes a new instance of the BeamPropertyComponent class.
        /// </summary>
        public BeamPropertyComponent()
          : base("Beam Property", "BP", "Beam properties", CategoryNameConstants.CATEGORY_FEMM, CategoryNameConstants.SUBCATEGORY_PROPERTIES)
        {
            _disableSolution = false;
            _prevType = null;
        }

        public override void ExpireSolution(bool recompute)
        {
            if (!_disableSolution)
            {
                try
                {
                    _disableSolution = true;
                    IGH_Param typeParam = Params.Input[1];
                    typeParam.CollectData();
                    if (typeParam.Name == "Type" && typeParam.VolatileDataCount > 0)
                    {
                        BeamPropertyType? type = null;
                        for (int i = 0; i < typeParam.VolatileData.StructureProxy.Count; i++)
                        {
                            System.Collections.IList path = typeParam.VolatileData.StructureProxy[i];
                            for (int k = 0; k < path.Count; k++)
                            {
                                GH_Integer obj = (GH_Integer)path[k];
                                if (obj != null)
                                {
                                    Message = _propertyTypeOptions[obj.Value];
                                    type = (BeamPropertyType)obj.Value;
                                    break;
                                }
                            }
                            if (type != null) 
                                break;
                        }

                        if (type != _prevType && Params.Input.Count > 4)
                        {
                            for (int i = Params.Input.Count - 1; i > 3; i--)
                                Params.UnregisterInputParameter(Params.Input[i]);
                            Params.OnParametersChanged();
                        }

                        if (type == BeamPropertyType.SpringDamper)
                        {
                            if (Params.Input.Count == 4)
                            {
                                Param_GenericObject number;
                                number = new Param_GenericObject
                                {
                                    Access = GH_ParamAccess.item,
                                    Name = "Spring Damper Data",
                                    NickName = "SDD",
                                    Description = "Spring Damper beam property data"
                                };
                                Params.RegisterInputParam(number);

                                Params.OnParametersChanged();
                            }
                        }
                        else if (type == BeamPropertyType.CutoffBar)
                        {
                            if (Params.Input.Count == 4)
                            {
                                Param_Number number;
                                number = new Param_Number
                                {
                                    Access = GH_ParamAccess.item,
                                    Name = "Max tension",
                                    NickName = "MT",
                                    Description = "Maximum tension for cutoff bars"
                                };
                                Params.RegisterInputParam(number);

                                number = new Param_Number
                                {
                                    Access = GH_ParamAccess.item,
                                    Name = "Max compression",
                                    NickName = "MC",
                                    Description = "Maximum compression for cutoff bars"
                                };
                                Params.RegisterInputParam(number);

                                Param_Integer integer;
                                integer = new Param_Integer
                                {
                                    Access = GH_ParamAccess.item,
                                    Name = "Cut off type",
                                    NickName = "T",
                                    Description = "Type of cutoff bar"
                                };
                                AddNamedValuesCutOffType(integer);
                                Params.RegisterInputParam(integer);

                                Param_Boolean boolean;
                                boolean = new Param_Boolean
                                {
                                    Access = GH_ParamAccess.item,
                                    Name = "Keep mass",
                                    NickName = "KM",
                                    Description = "Keep mass option for cutoff bars"
                                };
                                Params.RegisterInputParam(boolean);

                                Params.OnParametersChanged();
                            }
                        }

                        _prevType = type;

                        //i fullname non sono visibili e non lo saranno, vedi
                        //https://discourse.mcneel.com/t/changing-input-parameter-names-always-shows-nickname/54071
                    }
                    base.ExpireSolution(recompute);
                }
                catch (Exception)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Invalid property type");
                }
                finally
                {
                    _disableSolution = false;
                }
            }
        }

        /// <summary>
        /// Registers all the input parameters for this component.
        /// </summary>
        protected override void RegisterInputParams(GH_InputParamManager pManager)
        {
            pManager.AddTextParameter("Name", "N", "Property name", GH_ParamAccess.item);
            int i = pManager.AddIntegerParameter("Type", "T", "The property type", GH_ParamAccess.item);
            Param_Integer mtParam = pManager[i] as Param_Integer;
            foreach (KeyValuePair<int, string> v in _propertyTypeOptions)
                mtParam.AddNamedValue(v.Value, v.Key);
            pManager.AddGenericParameter("Section", "S", "Section", GH_ParamAccess.item);
            pManager.AddGenericParameter("Material", "M", "Material", GH_ParamAccess.item);
        }

        /// <summary>
        /// Registers all the output parameters for this component.
        /// </summary>
        protected override void RegisterOutputParams(GH_OutputParamManager pManager)
        {
            pManager.AddGenericParameter("Beam Property", "BP", "Beam property", GH_ParamAccess.item);
        }

        private void AddNamedValuesCutOffType(Param_Integer integer)
        {
            Array arr = Enum.GetValues(typeof(CutoffType));
            for (int i = 0; i < arr.Length; i++)
            {
                if ((CutoffType)arr.GetValue(i) != CutoffType.Undefined)
                {
                    integer.AddNamedValue(Enum.GetName(typeof(CutoffType), arr.GetValue(i)), (int)(CutoffType)arr.GetValue(i));
                }
            }
        }

        /// <summary>
        /// This is the method that actually does the work.
        /// </summary>
        /// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            string name = "";
            int type = 0;
            GH_BeamSection section = null;
            DataTypes.FeMM.GH_Material material = null;

            if (!DA.GetData("Name", ref name))
                return;
            if (!DA.GetData("Type", ref type))
                return;
            if (!DA.GetData("Section", ref section))
                return;
            if (!DA.GetData("Material", ref material))
                return;

            var sectionModel = new SectionModel();

            if (section.SectionType != SectionModel.SectionTypes.Generic)
            {
                sectionModel.SectionType = section.SectionType;
                sectionModel.Name = section.Name;
                sectionModel.MaffeisName = section.MaffeisName;
                sectionModel.IsDBSection = section.IsDBSection;
                sectionModel.D = section.D;
                sectionModel.B = section.B;
                sectionModel.B1 = section.B1;
                sectionModel.B2 = section.B2;
                sectionModel.L = section.L;
                sectionModel.T = section.T;
                sectionModel.T1 = section.T1;
                sectionModel.T2 = section.T2;
                sectionModel.T3 = section.T3;
                sectionModel.R = section.R;
                sectionModel.Mirror = section.MirrorType;
                sectionModel.MirrorGapA = section.MirrorGapA;
                sectionModel.MirrorGapB = section.MirrorGapB;
                sectionModel.GenericShapes = section.GenericShapes;
                sectionModel.CalculateSection();
                sectionModel.I11 = section.I11;
                sectionModel.I22 = section.I22;
                sectionModel.W11 = section.W11;
                sectionModel.W22 = section.W22;
                sectionModel.SectionArea = section.SectionArea;
                sectionModel.J = section.J;
                sectionModel.Centroid = section.Centroid;

                if (section.IsDBSection)
                {
                    sectionModel.ShearL1 = section.SL1;
                    sectionModel.ShearL2 = section.SL2;
                    sectionModel.ShearA1 = section.SA1;
                    sectionModel.ShearA2 = section.SA2;
                    sectionModel.AngleX1Rad = section.AngleX1;
                }
            }
            else
            {
                sectionModel.SectionType = SectionModel.SectionTypes.Generic;
                sectionModel.Name = section.Name;
                sectionModel.MaffeisName = section.MaffeisName;
                sectionModel.IsDBSection = section.IsDBSection;                
                sectionModel.SectionArea = section.SectionArea;
                sectionModel.I11 = section.I11;
                sectionModel.I22 = section.I22;
                sectionModel.J = section.J;
                sectionModel.ShearL1 = section.SL1;
                sectionModel.ShearL2 = section.SL2;
                sectionModel.ShearA1 = section.SA1;
                sectionModel.ShearA2 = section.SA2;
                sectionModel.W11 = section.W11;
                sectionModel.W22 = section.W22;
                sectionModel.Centroid = section.Centroid;
                sectionModel.AngleX1Rad = section.AngleX1;
            };

            if (section.Value.UseEquivalent) {
                sectionModel.UseEquivalent = true;
                sectionModel.EquivalentArea = section.Value.EquivalentArea;
                sectionModel.EquivalentDensity = section.Value.EquivalentDensity;
                sectionModel.EquivalentDiameter = section.Value.EquivalentDiameter;
                sectionModel.EquivalentModulus = section.Value.EquivalentModulus;
            }

            var bp = new BeamPropertyModel
            {
                Name = name,
                Material = material.Value,
                Section = sectionModel,
                PropertyType = (BeamPropertyType)type,
            };

            // Uses extra input values
            if (bp.PropertyType == BeamPropertyType.SpringDamper)
            {
                GH_SpringDamperData springDumperData = null;
                if (!DA.GetData(4, ref springDumperData))
                    return;

                bp.SpringDamperData = new(springDumperData.Value);
            }
            else if (bp.PropertyType == BeamPropertyType.CutoffBar)
            {
                double maxTensionCB = 0;
                double maxCompressionCB = 0;
                int cutOffTypeCB = 0;
                bool keepMassCB = false;
                if (!DA.GetData(4, ref maxTensionCB))
                    return;
                if (!DA.GetData(5, ref maxCompressionCB))
                    return;
                if (!DA.GetData(6, ref cutOffTypeCB))
                    return;
                if (!DA.GetData(7, ref keepMassCB))
                    return;

                bp.MaxTension = maxTensionCB;//10.0E8;
                bp.MaxCompression = maxCompressionCB;// 0;
                bp.CutoffType = (CutoffType)cutOffTypeCB;// CutoffType.Ductile;
                bp.KeepMass = keepMassCB;// true;
            }

            var gh_bp = new GH_FunctionDefinition(bp);
            DA.SetData(0, gh_bp);
        }

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

        /// <summary>
        /// Gets the unique ID for this component. Do not change this ID after release.
        /// </summary>
        public override Guid ComponentGuid => new("dfa97707-eae3-465a-84d6-90b240e1e972");

        public override bool Write(GH_IWriter writer)
        {
            //https://www.grasshopper3d.com/forum/topics/creating-a-component-with-a
            writer.SetInt32("Release", 2);
            Params.WriteAllParameterData(writer);
            return base.Write(writer);
        }

        public override bool Read(GH_IReader reader)
        {
            //Very important, we must make sure all parameters exist before we 
            //start with the main deserialization.
            int release = 0;
            if (reader.TryGetInt32("Release", ref release))
            {
                if (release >= 1)
                {
                    Params.Clear();
                    Params.ReadAllParameterData(reader);

                    //fix the number parameters
                    Param_Integer mtParam = Params.Input[1] as Param_Integer;
                    foreach (KeyValuePair<int, string> v in _propertyTypeOptions)
                        mtParam.AddNamedValue(v.Value, v.Key);

                    if (Params.Input.Count == 8)
                    {
                        AddNamedValuesCutOffType((Param_Integer)Params.Input[6]);
                    }
                }
            }
            return base.Read(reader);
        }
    }
}
303 files24 directories