using FeMM.Common.Models;
using FeMM.Grasshopper.DataTypes.FeMM;
using FeMM.Grasshopper.Forms;
using FeMM.Grasshopper.Helpers;
using Grasshopper;
using Grasshopper.GUI;
using Grasshopper.GUI.Canvas;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Attributes;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.Versioning;
using System.Windows.Forms;

namespace FeMM.Grasshopper.Components.Parameters
{
#if NETCOREAPP
    [SupportedOSPlatform("windows")]
#endif
    public class LoadCombinationsParam : GH_PersistentParam<GH_Combination>
    {
        protected List<CaseModel> _loadCases;

        public List<CaseModel> LoadCaseList => _loadCases;

        public LoadCombinationsParam()
            : base("Load Combinations", "LCS", "The load combinations definition", CategoryNameConstants.CATEGORY_FEMM, CategoryNameConstants.SUBCATEGORY_PARAMETERS)
        {
            _loadCases = [];
        }

        public void UpdateLoadCases(IEnumerable<CaseModel> loadCases)
        {
            // Recreate the LoadCase names list
            _loadCases.Clear();
            loadCases = loadCases.Where(lc => lc.GetType() != typeof(LoadCaseCombinationModel));
            foreach (CaseModel loadCase in loadCases)
            {
                if (_loadCases.Count(lc => lc.Name == loadCase.Name) == 0)
                    _loadCases.Add(loadCase);
            }

            if (VolatileDataCount == 0)
                return;

            // Update the exiting combinations
            bool changed = false;
            List<GH_Combination> combinations = (List<GH_Combination>)VolatileData.get_Branch(0);

            for (int i = 0; i < combinations.Count; i++)
            {
                GH_Combination combo = combinations[i];
                // Remove the non existing values
                CaseModel[] to_remove = [.. combo.Value.Values.
                    Where(v => !loadCases.Contains(v.Key)).
                    Select(c => c.Key)];
                for (int j = 0; j < to_remove.Length; j++)
                {
                    CaseModel lc = to_remove[j];
                    combo.Value.Values.Remove(lc);
                }

                if (to_remove.Length > 0)
                    changed = true;

                foreach (CaseModel loadCase in loadCases)
                {
                    if (!combo.Value.Values.Keys.Contains(loadCase))
                        combo.Value.Values.Add(loadCase, 1);
                }
            }

            if (changed)
            {
                PersistentData.Clear();
                SetPersistentData(combinations);
                ExpireSolution(true);
            }
        }

        protected override GH_GetterResult Prompt_Plural(ref List<GH_Combination> values)
        {
            return GH_GetterResult.cancel;
        }

        protected override GH_GetterResult Prompt_Singular(ref GH_Combination value)
        {
            return GH_GetterResult.success;
        }

        public override void CreateAttributes()
        {
            m_attributes = new LoadCombinationsAttributes(this);
        }

        public override GH_Exposure Exposure => GH_Exposure.secondary;

        public override Guid ComponentGuid => new("0BE68174-01FC-4EA5-B9D9-7839A7F2C64B");

        protected override Bitmap Icon => Properties.Resources.LoadCombinationsParamIcon;
    }

#if NETCOREAPP
    [SupportedOSPlatform("windows")]
#endif
    internal class LoadCombinationsAttributes : GH_ResizableAttributes<LoadCombinationsParam>
    {
        private Rectangle _internalRect;

        protected override Size MinimumSize => new(120, 60);

        protected override Size MaximumSize { get { return new Size(730, 240); } }

        protected override Padding SizingBorders { get { return new Padding(10); } }

        public LoadCombinationsAttributes(LoadCombinationsParam owner)
            : base(owner)
        {
            Bounds = new RectangleF(Pivot, new Size(150, 80));
        }

        protected override void Layout()
        {
            base.Layout();
            _internalRect = GH_Convert.ToRectangle(Bounds);
            _internalRect.Inflate(-5, -5);
        }

        protected override void Render(GH_Canvas canvas, Graphics graphics, GH_CanvasChannel channel)
        {
            if (channel == GH_CanvasChannel.Objects)
            {
                GH_Palette palette = GH_Palette.Normal;

                // Adjust palette based on the Owner's worst case messaging level.
                switch (Owner.RuntimeMessageLevel)
                {
                    case GH_RuntimeMessageLevel.Warning:
                        palette = GH_Palette.Warning;
                        break;

                    case GH_RuntimeMessageLevel.Error:
                        palette = GH_Palette.Error;
                        break;
                }

                var capsuleBox = new RectangleF(Bounds.Location, Bounds.Size);

                GH_Capsule capsule = GH_Capsule.CreateCapsule(capsuleBox, palette);
                capsule.AddOutputGrip(OutputGrip.Y);
                capsule.Render(graphics, Selected, Owner.Locked, false);
                capsule.Dispose();

                using (var pen = new Pen(Color.Black))
                    graphics.DrawRectangle(pen, _internalRect);

                var format = new StringFormat
                {
                    Alignment = StringAlignment.Center,
                    LineAlignment = StringAlignment.Center,
                    Trimming = StringTrimming.EllipsisCharacter
                };
                RectangleF textRectangle = _internalRect;
                textRectangle.Y += 2;
                textRectangle.Height = 20;
                textRectangle.Inflate(-2, 0);
                graphics.DrawString("Combinations", GH_FontServer.Standard, Brushes.Black, textRectangle, format);

                format.Alignment = StringAlignment.Near;
                textRectangle.X += 2;
                if (!Owner.VolatileData.IsEmpty)
                {
                    IList<GH_Combination> list = (IList<GH_Combination>)Owner.VolatileData.get_Branch(0);
                    for (int i = 0; i < list.Count; i++)
                    {
                        if (list[i] == null)
                            continue;

                        textRectangle.Y += textRectangle.Height;
                        int textLen = GH_FontServer.StringWidth(list[i].ToString(), GH_FontServer.Standard);
                        if (textLen <= textRectangle.Width)
                            textRectangle.Height = 20;
                        else
                            textRectangle.Height = GH_FontServer.Standard.Height * (float)Math.Ceiling(textLen / textRectangle.Width);

                        if (textRectangle.Y + textRectangle.Height + (i < list.Count - 1 ? 20 : 0) > Bounds.Y + Bounds.Height)
                        {
                            textRectangle.Height = 20;
                            graphics.DrawString($"{list.Count - i} more...", GH_FontServer.Standard, Brushes.Black, textRectangle, format);
                            break;
                        }

                        graphics.DrawString(list[i].ToString(), GH_FontServer.Standard, Brushes.Black, textRectangle, format);
                    }
                }
                else
                {
                    textRectangle.Y += textRectangle.Height;
                    graphics.DrawString("No combination defined...", GH_FontServer.Standard, Brushes.Black, textRectangle, format);
                }
            }
            else
            {
                base.Render(canvas, graphics, channel);
            }
        }

        public override GH_ObjectResponse RespondToMouseDoubleClick(GH_Canvas sender, GH_CanvasMouseEvent e)
        {
            if (e.Button == MouseButtons.Left)
            {
                List<GH_Combination> list = null;
                if (!Owner.VolatileData.IsEmpty)
                    list = (List<GH_Combination>)Owner.VolatileData.get_Branch(0);
                var form = new LoadCombinationsForm([.. Owner.LoadCaseList], list);
                GH_WindowsFormUtil.CenterFormOnCursor(form, true);
                if (form.ShowDialog(Instances.DocumentEditor) == DialogResult.OK)
                {
                    Owner.PersistentData.Clear();
                    Owner.SetPersistentData(form.Values);
                    Owner.ExpireSolution(true);
                }
                return GH_ObjectResponse.Handled;
            }
            return base.RespondToMouseDoubleClick(sender, e);
        }
    }
}
303 files24 directories