using FeMM.Grasshopper.DataTypes.F2R;
using FeMM.Grasshopper.Helpers;
using FemToRhino.Common;
using FemToRhino.CSI.ModelWrapper;
using Grasshopper.Kernel;
using Rhino;
using Rhino.Geometry;
using System;
using System.Collections.Generic;
using System.Runtime.Versioning;

namespace FeMM.Grasshopper.Components.F2R
{
#if NETCOREAPP
    [SupportedOSPlatform("windows")]
#endif
    public class InteractiveSap2GrasshopperComponent : GH_Component
    {
        private bool _run = false;

        /// <summary>
        /// Initializes a new instance of the MyComponent1 class.
        /// </summary>
        public InteractiveSap2GrasshopperComponent()
            : base("SAP2Grasshopper", "S2G", "Open interactive model of current open istance", CategoryNameConstants.CATEGORY_F2R, CategoryNameConstants.SUBCATEGORY_F2R_INTERACTIVEGRASSHOPPER)
        {
        }

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

            m_attributes = buttonAttributes;
        }

        /// <summary>
        /// Registers all the input parameters for this component.
        /// </summary>
        protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager)
        {
            pManager.AddTextParameter("Group", "G", "Sap2000 group for selection element. Default value: ALL", GH_ParamAccess.item, "ALL");
        }

        /// <summary>
        /// Registers all the output parameters for this component.
        /// </summary>
        protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager)
        {
            pManager.AddGeometryParameter("Joints", "J", "The Joints", GH_ParamAccess.list);
            pManager.AddGeometryParameter("Joint Attributes", "JA", "The data attached to each joints", GH_ParamAccess.list);
            pManager.AddGeometryParameter("Frames", "F", "The Frames with the data attached", GH_ParamAccess.list);
            pManager.AddGeometryParameter("Areas", "A", "The Areas with the data attached", GH_ParamAccess.list);
        }

        /// <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 groupName = "";

            DA.GetData(0, ref groupName);

            var joints = new List<GeometryBase>();
            var jointsAttributes = new List<GeometryBase>();
            var frames = new List<GeometryBase>();
            var areas = new List<GeometryBase>();

            if (_run)
            {

                var modelType = new GH_SAPInteractiveDatabaseModel();
                modelType.Value.Group = groupName;
                try
                {
                    modelType.Value.Process();
                }
                catch (Exception ex)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"Fail to process the model: {ex.Message}");
                }

                List<string> log = modelType.GetLog();
                if (log.Count > 0)
                {
                    foreach (string logItem in log)
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, logItem);
                    }
                }

                try
                {
                    BakeGeometryCustom(modelType, out joints, out jointsAttributes, out frames, out areas);
                }
                catch (Exception)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Fail to bake the model");
                }

                _run = false;
            }
            DA.SetDataList(0, joints);
            DA.SetDataList(1, jointsAttributes);
            DA.SetDataList(2, frames);
            DA.SetDataList(3, areas);
        }

        public void BakeGeometryCustom(GH_SAPInteractiveDatabaseModel gH_SAPInteractiveDatabaseModel, out List<GeometryBase> joints, out List<GeometryBase> jointsAttribute,
            out List<GeometryBase> frames, out List<GeometryBase> areas)
        {
            FemToRhino.CSI.SapInteractiveDatabaseModel model = gH_SAPInteractiveDatabaseModel.Value;

            joints = [];
            jointsAttribute = [];
            frames = [];
            areas = [];

            RhinoDoc doc = RhinoDoc.ActiveDoc;

            #region Dictionary

            var jointGroupsDictionary = new Dictionary<string, int>();
            var frameGroupsDictionary = new Dictionary<string, int>();
            var areaGroupsDictionary = new Dictionary<string, int>();

            int countGroups = 1;
            FemToRhino.Common.F2RModelHelper.GetGroupDictionaryAssociation(model.Joints, ref jointGroupsDictionary, ref countGroups);
            FemToRhino.Common.F2RModelHelper.GetGroupDictionaryAssociation(model.Frames, ref frameGroupsDictionary, ref countGroups);
            FemToRhino.Common.F2RModelHelper.GetGroupDictionaryAssociation(model.Areas, ref areaGroupsDictionary, ref countGroups);

            #endregion

            #region Joints

            for (int i = 0; i < model.Joints.Length; i++)
            {
                Joint joint = model.Joints[i];
                try
                {
                    var sphere = new Circle(joint.Location, 1);
                    var point = new Point(joint.Location);
                    GeometryBase geometry = GH_Convert.ToGeometryBase(sphere);
                    GeometryBase new_geometry = geometry.Duplicate();

                    new_geometry.UserDictionary.Set("F2R_ID", joint.Id);
                    new_geometry.UserDictionary.Set("F2R_SPECIALJOINT", joint.SpecialJoint.ToString());
                    new_geometry.UserDictionary.Set("F2R_GUID", joint.Guid.ToString());

                    if (joint.Groups.Count > 0)
                    {
                        for (int k = 0; k < joint.Groups.Count; k++)
                        {
                            new_geometry.UserDictionary.Set("F2R_GROUP_" + jointGroupsDictionary[joint.Groups[k].Name], joint.Groups[k].Name);
                        }
                    }

                    jointsAttribute.Add(new_geometry);
                    joints.Add(point);
                }
                catch (Exception ex)
                {
                    AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, $"Fail to bake joint {joint.Id}. Exception: {ex}");
                }
            }

            #endregion

            #region Frames

            for (int i = 0; i < model.Frames.Length; i++)
            {
                if (model.Frames[i] != null)
                {
                    Frame frame = (Frame)model.Frames[i];
                    try
                    {
                        GeometryBase geometry = GH_Convert.ToGeometryBase(frame.Line);
                        GeometryBase new_geometry = geometry.Duplicate();

                        new_geometry.UserDictionary.Set("F2R_ID", frame.Id);
                        new_geometry.UserDictionary.Set("F2R_JOINT1", frame.StartNode.Id);
                        new_geometry.UserDictionary.Set("F2R_JOINT2", frame.EndNode.Id);
                        new_geometry.UserDictionary.Set("F2R_GUID", frame.Guid.ToString());
                        new_geometry.UserDictionary.Set("F2R_PROPERTY", frame.Property.Name);
                        new_geometry.UserDictionary.Set("F2R_PROPERTY_MATERIAL", frame.Property.Material.Name);

                        if (frame.Groups.Count > 0)
                        {
                            for (int j = 0; j < frame.Groups.Count; j++)
                            {
                                new_geometry.UserDictionary.Set("F2R_GROUP_" + frameGroupsDictionary[frame.Groups[j].Name], frame.Groups[j].Name);
                            }
                        }
                        frames.Add(new_geometry);
                    }
                    catch (Exception ex)
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, $"Fail to bake frame {frame.Id}. Exception: {ex}");
                    }
                }
            }

            #endregion

            #region Areas					

            for (int i = 0; i < model.Areas.Length; i++)
            {
                if (model.Areas[i] != null)
                {
                    Area area = (Area)model.Areas[i];

                    try
                    {
                        GeometryBase geometry = GH_Convert.ToGeometryBase(area.Shape);
                        GeometryBase new_geometry = geometry.Duplicate();

                        new_geometry.UserDictionary.Set("F2R_ID", area.Id);
                        new_geometry.UserDictionary.Set("F2R_GUID", area.Guid.ToString());
                        new_geometry.UserDictionary.Set("F2R_PROPERTY", area.Property.Name);
                        new_geometry.UserDictionary.Set("F2R_VERTICESCOUNT", area.GetPoints.Length.ToString());
                        for (int n = 0; n < area.GetPoints.Length; n++)
                            new_geometry.UserDictionary.Set($"F2R_JOINT{n + 1}", area.GetPoints[n].Id);

                        if (((AreaProperty)area.Property).IsNone)
                            new_geometry.UserDictionary.Set("F2R_ISNONE", true.ToString());

                        if (area.Groups.Count > 0)
                        {
                            for (int j = 0; j < area.Groups.Count; j++)
                            {
                                new_geometry.UserDictionary.Set("F2R_GROUP_" + areaGroupsDictionary[area.Groups[j].Name], area.Groups[j].Name);
                            }
                        }
                        areas.Add(new_geometry);
                    }
                    catch (Exception ex)
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, $"Fail to bake area {area.Id}. Exception: {ex}");
                    }
                }
            }

            #endregion
        }

        protected override System.Drawing.Bitmap Icon => Properties.Resources.F2RSAP2Grasshopper;

        public override Guid ComponentGuid => new("291ae773-3e91-4731-b464-7045e2b7f57e");
    }
}
303 files24 directories