using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Windows.Forms;

namespace GFATask
{
    [Browsable(false), ToolboxItem(false)]
    public partial class GroupButton : AppListButton
    {
        private Collection<AppButton> _containedappbuttons = new Collection<AppButton>();
        public Collection<AppButton> ContainedAppButtons
        {
            get => _containedappbuttons;
            set
            {
                _containedappbuttons = value;
            }
        }


        private List<Models.App> _containedapps = new List<Models.App>();
        public List<Models.App> ContainedApps
        {
            get => _containedapps;
            set
            {
                _containedapps = value;
            }
        }


        private FormAppButtonGroup _appbuttongroup;
        public FormAppButtonGroup AppButtonGroup { get => _appbuttongroup; }


        private ContextMenuStrip _contextmenustrip = new ContextMenuStrip();
        new public ContextMenuStrip ContextMenuStrip
        {
            get
            {
                XObjects.ContextMenuStrip = _contextmenustrip;
                return _contextmenustrip;
            }
            set
            {
                _contextmenustrip = value;
                _contextmenustrip.Items.Clear();

                if (AppType == AppType.Favorites)
                {
                    _contextmenustrip.Items.Add(new ToolStripMenuItem("Umbennen", null, (sender, e) =>
                    {
                        var msgbox = XObjects.MessageBox($"{this.Text}", NotifyButtons.YesNo, NotifyType.TextBox, new Size(250, 150), $"{this.Text} umbenennen", this.Text);
                        if(msgbox.Result == DialogResult.Yes)
                        {
                            _containedapps.ForEach(app =>
                            {
                                app.Group = msgbox.Value.ToString();
                                Creator.ReplaceApp(AppType, app);
                            });

                            this.Text = msgbox.Value.ToString();
                            _contextmenustrip.Items["remove_applistbutton"].Text = $"{this.Text} entfernen";
                            this.Name = Cast.GroupButtonName(AppType, this.Text);
                        }
                    }, "rename_applistbutton"));
                    _contextmenustrip.Items.Add(new ToolStripMenuItem($"{this.Text} entfernen", null, (s, evt) =>
                    {
                        for (int i = _containedapps.Count - 1; i >= 0; i--)
                        {
                            Creator.RemoveApp(AppType, _containedapps[i]);
                        }
                        Accessor.GetAppListPanel(AppType).RemoveGroupButton(this.Name, true);
                    }, "remove_applistbutton"));
                }
                else
                {
                    _contextmenustrip.Items.Add(new ToolStripMenuItem($"{this.Text} zu Favoriten hinzufügen", null, (s, evt) =>
                    {
                        List<Models.App> clones = new List<Models.App>();
                        string[] usedicons = new string[0];
                        _containedapps.ForEach(app =>
                        {
                            app.ID = AppLists.Favorites.Apps.Max(listapp => listapp.ID) + 1;
                            try
                            {
                                if (!usedicons.ToList().Exists(icon => icon == app.Icon) && app.Icon != "" && app.Icon != null)
                                {
                                    File.Copy($@"{Paths.Icons.Directory}\{app.Icon}", Paths.Favorites.Icons.Directory + @"\" + app.Icon, true);
                                    Array.Resize(ref usedicons, usedicons.Length + 1);
                                    usedicons[usedicons.Length - 1] = app.Icon;
                                }
                            }
                            catch (Exception ex)
                            {
                                Log.EventLog.Write("Bild nicht gespeichert", LogClassification.LowError, ex);
                            }
                            clones.Add(app);
                            Creator.AddApp(AppType.Favorites, app);
                        });
                        usedicons = null;
                        Accessor.GetAppListPanel(AppType.Favorites).AddGroupButton(clones.ToArray());
                    }, "to_favorites"));
                }
            }
        }

        public override AppType AppType
        {
            get => base.AppType; set
            {
                base.AppType = value;
                this.ContextMenuStrip = _contextmenustrip;
            }
        }


        public GroupButton()
        {
            InitializeComponent();
            _containedappbuttons.CollectionChanged += _containedappbuttons_CollectionChanged;
            ContextMenuStrip.SetDefaultDesign();
            this.ToolTipText = "Apps: ";
        }


        public void RemoveApp(Models.App app)
        {
            if(_containedappbuttons.ToList().Exists(appbutton => appbutton.Name == Cast.AppButtonName(AppType, app)))
                _containedappbuttons.Remove(_containedappbuttons.First(appbutton => appbutton.Name == Cast.AppButtonName(AppType, app)));
            _containedapps.Remove(app);
            if(_appbuttongroup != null)
            {
                if(_appbuttongroup.MyGroupButton == this)
                {
                    _appbuttongroup.RemoveButton(app);
                }
            }
        }


        private void _containedappbuttons_CollectionChanged(object sender, System.Collections.Events.CollectionChangedEventArgs<AppButton> e)
        {

            if (e.ChangeType == CollectionChangeType.Add)
            {
                foreach (var adgroup in e.Element.ActiveDirectoryGroups != null ? e.Element.ActiveDirectoryGroups : new string[] { "" })
                {
                    if (!_activedirectorygroups.Contains(adgroup))
                    {
                        Array.Resize(ref _activedirectorygroups, _activedirectorygroups.Length + 1);
                        _activedirectorygroups[_activedirectorygroups.Length - 1] = adgroup;
                    }
                }
                e.Element.MouseDown += Element_MouseDown;
            }
            else if (e.ChangeType == CollectionChangeType.Remove)
            {
                e.Element.MouseDown -= Element_MouseDown;
                if (_containedappbuttons.Count == 1)
                {
                    Accessor.GetAppListPanel(AppType).RemoveGroupButtonIfNeeded(this.Name);
                    if (_appbuttongroup != null && _appbuttongroup.Visible)
                    {
                        _appbuttongroup.Close();
                    }
                }
            }

            if (Config.User.Prevalence)
                this.Image = _containedappbuttons
                    .Where(button => button.Visible)
                    .OrderBy(button => button.Prevalence.CountClicks)
                    .Take(4)
                    .Select(button => new Bitmap(button.Image)).ToArray()
                    .Merge(new Size(this.ImageSize.Width + 2, this.ImageSize.Height + 2), 2);
            else
                this.Image = _containedappbuttons
                    .Where(button => button.Visible)
                    .OrderBy(button => button.Text)
                    .Take(4)
                    .Select(button => new Bitmap(button.Image)).ToArray()
                    .Merge(new Size(this.ImageSize.Width + 2, this.ImageSize.Height + 2), 2);


            this.Invalidate();
        }

        private void Element_MouseDown(object sender, MouseEventArgs e)
        {
            Prevalence = Accessor.GetPrevalencia(AppType, _containedappbuttons.ToList().Find(app => app.Prevalence.CountClicks == _containedappbuttons.Max(appbutton => appbutton.Prevalence.CountClicks)).ID );
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            string appcountstring = _containedapps.Count(app => Cast.AppVisibility(app)).ToString();
            GraphicsPath appCountRect;
            appCountRect = Visualization.RoundedRectangle.Create(new Rectangle(
            new Point(ImageBounds.Right - (int)(e.Graphics.MeasureString(appcountstring, this.Font).Width / 4) - 3, this.BorderBounds.Y + this.BorderSize),
            new Size((int)e.Graphics.MeasureString(appcountstring, this.Font).Height - 1, (int)e.Graphics.MeasureString(appcountstring, this.Font).Height - 1)), 5);
            e.Graphics.SetClip(new Rectangle(this.TextBounds.Location, new Size(this.TextBounds.Width , this.TextBounds.Height)));
            e.Graphics.Clear(this.BackColor);
            
            e.Graphics.SetClip(this.ClientRectangle);
            e.Graphics.FillPath(Brushes.Red, appCountRect);
            e.Graphics.DrawString(appcountstring, this.Font, Brushes.White, appCountRect.GetBounds(), new StringFormat() { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center, FormatFlags = StringFormatFlags.NoClip | StringFormatFlags.NoWrap, Trimming = StringTrimming.None });


            if (!this.ImageOnly)
            {
                e.Graphics.DrawString(Text, this.Font, new SolidBrush(this.ForeColor), new Rectangle((int)appCountRect.GetBounds().Right, this.TextBounds.Y + this.BorderSize + this.Radius, this.BorderBounds.Right - (int)appCountRect.GetBounds().Right - this.BorderSize - this.Radius, this.TextBounds.Height - (this.Radius * 2) - (this.BorderSize * 2)), new StringFormat() { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Center, FormatFlags = StringFormatFlags.NoClip | StringFormatFlags.NoWrap, Trimming = StringTrimming.EllipsisCharacter });
                //e.Graphics.DrawString(Text, this.Font, new SolidBrush(this.ForeColor), new Rectangle((int)appCountRect.GetBounds().Right, this.TextBounds.Y + this.BorderSize + this.Radius, this.BorderBounds.Right - (int)appCountRect.GetBounds().Right - this.BorderSize - this.Radius, this.TextBounds.Height - (this.Radius * 2) - (this.BorderSize * 2)), new StringFormat() { Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Center, FormatFlags = StringFormatFlags.NoClip | StringFormatFlags.NoWrap, Trimming = StringTrimming.None });
            }
            else
            {
                this.Width = (int)appCountRect.GetBounds().Right;
            }
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
           
            this.ImageSize = new Size(this.BorderBounds.Height - this.Padding.Vertical - this.Margin.Vertical, this.BorderBounds.Height - this.Padding.Vertical - this.Margin.Vertical);
        }


        protected override void OnLocationChanged(EventArgs e)
        {
            base.OnLocationChanged(e);
            if (_appbuttongroup != null && _appbuttongroup.MyGroupButton == this)
            {
                // Wenn der obere Bereich des GroupButtons, oben aus dem AppListPanel austritt
                if (this.Top < 0)
                {
                    // Wenn der untere Bereich des GroupButtons, oben aus dem AppListPanel austritt
                    if (this.Bottom < 0)
                    {
                        _appbuttongroup.DesktopLocation = new Point(_appbuttongroup.Left, this.Parent.RectangleToScreen(this.Parent.Bounds).Top - this.Parent.Margin.Top - this.Parent.Parent.Padding.Top - _appbuttongroup.GripSize + 1);
                    }
                    // Oder, wenn der untere Bereich des GroupButtons noch sichtbar ist
                    else
                    {
                        _appbuttongroup.DesktopLocation = new Point(_appbuttongroup.Left, this.Parent.RectangleToScreen(this.Bounds).Bottom - _appbuttongroup.GripSize + 1);
                    }
                }
                // Wenn der obere Bereich des GroupButtons, im AppListPanel sichtbar ist
                else if (this.Top > 0)
                {
                    // Aber der untere Bereich des GroupButtons, unten aus dem AppListPanel austritt
                    if (this.Bottom > this.Parent.Bottom)
                        _appbuttongroup.DesktopLocation = new Point(_appbuttongroup.Left, this.Parent.RectangleToScreen(this.Parent.Bounds).Bottom - this.Parent.Padding.Vertical);
                    // Oder, wenn der untere Bereich des GroupButtons, unten aus dem GFATask austritt
                    else if (RectangleToScreen(this.DisplayRectangle).Bottom > Forms.Main.DesktopBounds.Bottom - Forms.Main.GripSize)
                        _appbuttongroup.DesktopLocation = new Point(_appbuttongroup.Left, Forms.Main.DesktopBounds.Bottom - Forms.Main.GripSize - _appbuttongroup.GripSize + 1 + Forms.Main.BorderWidth);
                    // Alle anderen Möglichkeiten korrigieren die Position des ButtonGroup-Fensters unterhalb des GroupButtons
                    else
                        _appbuttongroup.DesktopLocation = new Point(_appbuttongroup.Left, this.Parent.RectangleToScreen(this.Bounds).Bottom - _appbuttongroup.GripSize + 1);
                }
            }
        }


        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            if (e.Button == MouseButtons.Left && !Forms.AppButtonGroup.Visible)
            {
                _appbuttongroup = Forms.AppButtonGroup;
                _appbuttongroup.MyGroupButton = this;
                _appbuttongroup.Text = this.Text;
                _appbuttongroup.Icon = Icon.FromHandle(new Bitmap(this.Image).GetHicon());
                _appbuttongroup.DesktopLocation = this.PointToScreen(new Point(0 - _appbuttongroup.GripSize + 1, this.Height - _appbuttongroup.GripSize + 1));
                _appbuttongroup.TopMost = true;
                Accessor.OpenForm("AppButtonGroup", owner: Forms.Main, closeifopen: true);
            }
        }

        protected override void OnMouseEnter(EventArgs e)
        {
            this.ToolTipText = $"Apps:\n{string.Join("\n", _containedapps.OrderBy(app => app.Name).Select(app => app.Name))}";
            base.OnMouseEnter(e);
        }
     
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (this.ClientRectangle.Contains(e.Location) && e.Button == MouseButtons.Right )
            {
                try
                {
                    this.ContextMenuStrip.Show(this, new Point(this.Padding.Left, this.ClientRectangle.Bottom));
                }
                catch (Exception ex)
                {
                    Log.EventLog.Write($"Kontextmenü des GroupButtons {this.Text} fehlerhaft", LogClassification.LowError, ex);
                }
            }
        }
    }
}
