using FeMM.Common.Helpers;
using FeMM.Common.Models;
using FeMM.Grasshopper.ComponentAttributes;
using FeMM.Grasshopper.Components.Parameters;
using FeMM.Grasshopper.DataTypes.FeMM;
using FeMM.Grasshopper.Helpers;
using GH_IO.Serialization;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Parameters;
using System;
using System.Runtime.Versioning;

namespace FeMM.Grasshopper.Components.Loads
{
#if NETCOREAPP
    [SupportedOSPlatform("windows")]
#endif
    public class BeamDistributedLoadComponent : GH_Component
    {
        /// <summary>
        /// Initializes a new instance of the BeamDistributedLoadComponent class.
        /// </summary>
        public BeamDistributedLoadComponent()
          : base("Beam Distributed Load", "BDL", "Assign a beam distributed load", CategoryNameConstants.CATEGORY_FEMM, CategoryNameConstants.SUBCATEGORY_LOADS)
        {
        }

        public override void CreateAttributes()
        {
            var attr = new ComponentWithImageAttributes(this, Properties.Resources.BeamDistributedLoadType1Image);
            attr.AddOverlappedBitmap(new System.Drawing.PointF(5, -65), Properties.Resources.LocalAxisImage);
            m_attributes = attr;
        }

        /// <summary>
        /// Registers all the input parameters for this component.
        /// </summary>
        protected override void RegisterInputParams(GH_InputParamManager pManager)
        {
            pManager.AddGenericParameter("Beam", "B", "The beam where add the distributed load", GH_ParamAccess.item);
            pManager.AddGenericParameter("LoadCase", "LC", "The load case", GH_ParamAccess.item);
            pManager.AddIntegerParameter("Type", "T", "Load Type", GH_ParamAccess.item, 0);
            Param_Integer type_param = (Param_Integer)pManager[2];
            Array values = Enum.GetValues(typeof(BeamDistributedLoadModel.LoadSchema));
            foreach (BeamDistributedLoadModel.LoadSchema val in values)
                type_param.AddNamedValue(val.GetDescription(), (int)val);

            var cs_param = new CoordinateSystemParam
            {
                Optional = true
            };
            cs_param.ObjectChanged += Param_CoordinateSystem_ObjectChanged;
            pManager.AddParameter(cs_param, "Coordinate System", "CS", "The coordinate system of the load. Default value: Global Coordinate System", GH_ParamAccess.item);

            pManager.AddIntegerParameter("Direction", "D", "The load direction", GH_ParamAccess.item);
            Param_Integer dir_param = (Param_Integer)pManager[4];
            dir_param.AddNamedValue("1", 0);
            dir_param.AddNamedValue("2", 1);
            dir_param.AddNamedValue("3", 2);
            dir_param.Optional = true;

            pManager.AddNumberParameter("P1", "P1", "The P1 value", GH_ParamAccess.item);
            pManager[5].Optional = true;
            pManager.AddNumberParameter("PA", "PA", "The PA value", GH_ParamAccess.item);
            pManager[6].Optional = true;
            pManager.AddNumberParameter("PB", "PB", "The PB value", GH_ParamAccess.item);
            pManager[7].Optional = true;
            pManager.AddNumberParameter("P2", "P2", "The P2 value", GH_ParamAccess.item);
            pManager[8].Optional = true;
            pManager.AddNumberParameter("a", "a", "The distance ratio (0-1) from the starting node", GH_ParamAccess.item, 0);
            pManager.AddNumberParameter("b", "b", "The distance ratio (0-1) from the ending node", GH_ParamAccess.item, 0);
        }

        private void Param_CoordinateSystem_ObjectChanged(IGH_DocumentObject sender, GH_ObjectChangedEventArgs e)
        {
            // When the user changes the coordinate system, we unset the Direction parameter input.
            Param_Integer dir_param = (Param_Integer)Params.Input[4];
            dir_param.PersistentData.ClearData();

            // Change the Direction input choices
            SetDirectionContextMenuChoices();
        }

        private void SetDirectionContextMenuChoices()
        {
            CoordinateSystemParam cs_param = (CoordinateSystemParam)Params.Input[3];
            Param_Integer dir_param = (Param_Integer)Params.Input[4];
            dir_param.ClearNamedValues();
            if (cs_param.PersistentData.Branches.Count == 0)
            {
                dir_param.AddNamedValue("1", 0);
                dir_param.AddNamedValue("2", 1);
                dir_param.AddNamedValue("3", 2);
            }
            else
            {
                string[] options = Enum.GetNames(typeof(BeamDistributedLoadModel.LoadDirection));
                for (int i = 0; i < options.Length; i++)
                    dir_param.AddNamedValue(options[i].Replace('_', ' '), i);
            }
        }

        private void SetSchemaImage()
        {
            Param_Integer type_param = (Param_Integer)Params.Input[2];
            switch (type_param.PersistentData.Branches[0][0].Value)
            {
                case 0:
                    ((ComponentWithImageAttributes)m_attributes).Bitmap = Properties.Resources.BeamDistributedLoadType1Image;
                    break;
                case 1:
                    ((ComponentWithImageAttributes)m_attributes).Bitmap = Properties.Resources.BeamDistributedLoadType2Image;
                    break;
                case 2:
                    ((ComponentWithImageAttributes)m_attributes).Bitmap = Properties.Resources.BeamDistributedLoadType3Image;
                    break;
                case 3:
                    ((ComponentWithImageAttributes)m_attributes).Bitmap = Properties.Resources.BeamDistributedLoadType4Image;
                    break;
                case 4:
                    ((ComponentWithImageAttributes)m_attributes).Bitmap = Properties.Resources.BeamDistributedLoadType5Image;
                    break;
                case 5:
                    ((ComponentWithImageAttributes)m_attributes).Bitmap = Properties.Resources.BeamDistributedLoadType6Image;
                    break;
            }
        }

        /// <summary>
        /// Registers all the output parameters for this component.
        /// </summary>
        protected override void RegisterOutputParams(GH_OutputParamManager pManager)
        {
            pManager.AddGenericParameter("Beam", "B", "The modified beam", 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)
        {
            GH_Beam beam = null;
            GH_Case lc = null;
            GH_FunctionDefinition cs = null;
            int schema = 0;
            int dir = 0;
            double p1 = 0, pa = 0, pb = 0, p2 = 0;
            double a = 0, b = 0;

            if (!DA.GetData("Beam", ref beam))
                return;
            if (!DA.GetData("LoadCase", ref lc))
                return;
            if (!DA.GetData("Type", ref schema))
                return;
            bool has_cs = DA.GetData("Coordinate System", ref cs);
            bool has_dir = DA.GetData("Direction", ref dir);
            bool p1_has_value = DA.GetData("P1", ref p1);
            bool pa_has_value = DA.GetData("PA", ref pa);
            bool pb_has_value = DA.GetData("PB", ref pb);
            bool p2_has_value = DA.GetData("P2", ref p2);
            if (!DA.GetData("a", ref a))
                return;
            if (!DA.GetData("b", ref b))
                return;

            LoadCaseModel loadCaseModel = null;
            if (lc.Value != null && lc.Value is LoadCaseModel lccc)
                loadCaseModel = new LoadCaseModel(lccc);
            else
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Input case must be a load case");
                return;
            }

            Message = string.Format("Coordinate System: {0}\nDirection: {1}", cs == null ? "Global" : cs.Value.Name, cs != null ?
                string.Format("Local axis {0}", dir + 1) :
                Enum.GetName(typeof(BeamDistributedLoadModel.LoadDirection), dir).Replace('_', ' '));

            if (loadCaseModel.NonStructuralMassAcceleration)
                AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "The connected LoadCase have the Non-structural mass flag set to on");

            bool input_errors = false;
            if (!has_dir)
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Input parameter Direction failed to collect data");
                input_errors = true;
            }

            switch (schema)
            {
                case 0:
                    ((ComponentWithImageAttributes)m_attributes).Bitmap = Properties.Resources.BeamDistributedLoadType1Image;
                    if (!pa_has_value)
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Input parameter 'PA' failed to collect data");
                        input_errors = true;
                    }
                    break;
                case 1:
                    ((ComponentWithImageAttributes)m_attributes).Bitmap = Properties.Resources.BeamDistributedLoadType2Image;
                    if (!pa_has_value || !pb_has_value)
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Input parameters 'PA', 'PB' failed to collect data");
                        input_errors = true;
                    }
                    break;
                case 2:
                    ((ComponentWithImageAttributes)m_attributes).Bitmap = Properties.Resources.BeamDistributedLoadType3Image;
                    if (!p1_has_value || !pa_has_value || !p2_has_value)
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Input parameters 'P1', 'PA', 'P2' failed to collect data");
                        input_errors = true;
                    }
                    if (a == 0)
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Input parameter 'a' must be greater than 0");
                        input_errors = true;
                    }
                    break;
                case 3:
                    ((ComponentWithImageAttributes)m_attributes).Bitmap = Properties.Resources.BeamDistributedLoadType4Image;
                    if (!p1_has_value || !pa_has_value || !pb_has_value)
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Input parameters 'P1', 'PA', 'PB' failed to collect data");
                        input_errors = true;
                    }
                    if (a == 0)
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Input parameter 'a' must be greater than 0");
                        input_errors = true;
                    }
                    break;
                case 4:
                    ((ComponentWithImageAttributes)m_attributes).Bitmap = Properties.Resources.BeamDistributedLoadType5Image;
                    if (!pa_has_value || !pb_has_value || !p2_has_value)
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Input parameters 'PA', 'PB', 'P2' failed to collect data");
                        input_errors = true;
                    }
                    if (b == 0)
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Input parameter 'b' must be greater than 0");
                        input_errors = true;
                    }
                    break;
                case 5:
                    ((ComponentWithImageAttributes)m_attributes).Bitmap = Properties.Resources.BeamDistributedLoadType6Image;
                    if (!p1_has_value || !pa_has_value || !pb_has_value || !p2_has_value)
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Input parameters 'P1', 'PA', 'PB', 'P2' failed to collect data");
                        input_errors = true;
                    }
                    if (a == 0 || b == 0)
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Input parameters 'a' and 'b' must be greater than 0");
                        input_errors = true;
                    }
                    break;
            }
            if (a >= 1)
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "The 'a' value must be lower than 1");
                input_errors = true;
            }
            if (b >= 1)
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "The 'b' value must be lower than 1");
                input_errors = true;
            }
            if (a + b >= 1)
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "The sum of a+b must less than 1");
                input_errors = true;
            }


            if (input_errors)
                return;

            BeamDistributedLoadModel.LoadSchema load_schema = (BeamDistributedLoadModel.LoadSchema)schema;
            var load_value = new BeamDistributedLoadModel.LoadData()
            {
                LoadSchema = load_schema,
                LoadDirection = (BeamDistributedLoadModel.LoadDirection)dir,
                P1 = p1,
                PA = pa,
                PB = pb,
                P2 = p2,
                A = a,
                B = b
            };
            if (cs != null && cs.Value is CoordinateSystemModel css)            
                load_value.CoordinateSystem = css;

            var load = new BeamDistributedLoadModel(loadCaseModel, load_value, BeamDistributedLoadModel.LoadType.Force)
            {
                CoordinateSystem = load_value.CoordinateSystem
            };
            var newBeam = new GH_Beam(beam);
            newBeam.Value.Loads.Add(load);
            DA.SetData(0, newBeam);
        }

        public override bool Read(GH_IReader reader)
        {
            bool success = base.Read(reader);
            // After the document was read, we have to set the right Direction input choices.
            SetDirectionContextMenuChoices();
            SetSchemaImage();

            return success;
        }

        public override GH_Exposure Exposure => GH_Exposure.secondary;

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

        /// <summary>
        /// Gets the unique ID for this component. Do not change this ID after release.
        /// </summary>
        public override Guid ComponentGuid => new("3203a9e1-c15b-4761-a81d-682c8da941ce");
    }
}
303 files24 directories