#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

#endregion
using System.Collections.Specialized;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace Danal.Layout
{

    public class Stretchables
    {
        StretchableControl[] stretchableControls;
        public Stretchables(Control control)
        {
            stretchableControls
                    = DialogItemStretchAttribute.AddStretchControls(control);
        }
        public void OnSizeChanged(Object sender, EventArgs e)
        {
            DialogItemStretchAttribute.StretchControls(stretchableControls);
        }
    }
    public struct StretchableControl
    {
        internal Control item;
        internal Control parent;
        internal StretchableControl(Control item, Control parent)
        {
            this.item = item;
            this.parent = parent;
        }
    }
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
    public class DialogItemStretchAttribute : Attribute
    {
        public DialogItemStretchAttribute(String name)
        {
            parent = String.Empty;
            this.name = name;
        }
        public DialogItemStretchAttribute(String name, String parent)
            : this(name)
        {
            this.parent = parent;
        }

        protected String name;
        protected String parent;
        public static void StretchControls(StretchableControl[] stretchableControls)
        {
            foreach (StretchableControl stretchableControl in stretchableControls)
            {
                Control parent = stretchableControl.parent;
                Control item = stretchableControl.item;
                item.Size = new Size(parent.ClientSize.Width - item.Left - 3, item.Height);
            }

        }
        static Control Find(String name, Control parent)
        {
            Control control = null;
            foreach (Control c in parent.Controls)
            {
                if (c.Name == name)
                {
                    control = c;
                    break;
                }
                else
                {
                    control = Find(name, c);
                }
            }
            return control;
        }
        // no two controls in dialog of same name, even a descentant
        public static StretchableControl[] AddStretchControls(Control control)
        {

            DialogItemStretchAttribute[] atrs
                    = (DialogItemStretchAttribute[])
                     control.GetType().GetCustomAttributes
                     (typeof(DialogItemStretchAttribute), true);
            StretchableControl[] stretchableControls
                    = new StretchableControl[atrs.Length];
            StringCollection names = new StringCollection();
            int ctlIndex = 0;
            foreach (DialogItemStretchAttribute a in atrs)
            {
                if (a.parent == String.Empty)
                {
                    stretchableControls[ctlIndex]
                            = new StretchableControl(Find(a.name, control), control);
                }
                else
                {
                    Control parent = Find(a.parent, control);
                    stretchableControls[ctlIndex]
                            = new StretchableControl(Find(a.name, parent), parent);
                }
                ctlIndex++;
            }
            return stretchableControls;
        }
    }

    public abstract class DialogExtent : Attribute
    {
        protected String name;
        public abstract int Extent(Control control);
        public static void SetBottom(Control control)
        {
            SetBottom(control, 3);
        }
        public static void SetBottom(Control control, int spacing)
        {
            int bottom =
                            DialogExtent.GetExtent(typeof(DialogBottomAttribute), control);
            if (bottom > 0)
            {
                bottom += spacing;
                control.ClientSize = new Size(control.ClientSize.Width, bottom);
            }
        }
        internal static Control Find(Control control, String name)
        {
            foreach (Control c in control.Controls)
            {
                if (c.Name == name)
                {
                    return c;
                }
            }
            return null;
        }
        static internal int GetExtent(Type type, Control control)
        {
            int length = -1;
            DialogExtent[] extent = (DialogExtent[])
            control.GetType().GetCustomAttributes(type, true);
            if (extent.Length > 0)
            {
                length = extent[0].Extent(control);
            }
            return length;
        }
    }
    [AttributeUsage(AttributeTargets.Class)]
    public class DialogRightAttribute : DialogExtent
    {
        public DialogRightAttribute(String name)
        {
            this.name = name;
        }
        public override int Extent(Control control)
        {
            Control item = DialogExtent.Find(control, name);
            if (item != null)
            {
                return item.Location.X + item.Size.Width;
            }
            return -1;
        }
    }
    [AttributeUsage(AttributeTargets.Class)]
    public class DialogBottomAttribute : DialogExtent
    {
        public DialogBottomAttribute(String name)
        {
            this.name = name;
        }
        public override int Extent(Control control)
        {
            Control item = DialogExtent.Find(control, name);
            if (item != null)
            {
                return item.Location.Y + item.Size.Height;
            }
            return -1;
        }
    }
}
