using System;
using System.Windows;
using System.Windows.Controls;

namespace CustomControls
{
    public class FormPanel : Grid
    {        
        private int _lastLayoutChildCount;
        private bool _loaded;
        public static readonly DependencyProperty IsLabeledProperty = DependencyProperty.RegisterAttached("IsLabeled", typeof(bool), typeof(FormPanel), new PropertyMetadata(true, OnLayoutAttachedPropertyChanged));
        public static readonly DependencyProperty IsStretchedProperty = DependencyProperty.RegisterAttached("IsStretched", typeof(bool), typeof(FormPanel), new PropertyMetadata(false, OnLayoutAttachedPropertyChanged));
        public static readonly DependencyProperty LabelAlignmentProperty = DependencyProperty.Register("LabelAlignment", typeof(FormPanelLabelAlignment), typeof(FormPanel), new PropertyMetadata(FormPanelLabelAlignment.Left, OnLayoutPropertyChanged));
        public static readonly DependencyProperty LabelPositionProperty = DependencyProperty.RegisterAttached("LabelPosition", typeof(FormPanelLabelPosition), typeof(FormPanel), new PropertyMetadata(FormPanelLabelPosition.Left, OnLayoutAttachedPropertyChanged));
        public static readonly DependencyProperty LabelSpacingProperty = DependencyProperty.Register("LabelSpacing", typeof(int), typeof(FormPanel), new PropertyMetadata(4, OnLayoutPropertyChanged));
        public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(FormPanel), new PropertyMetadata(Orientation.Vertical, OnLayoutPropertyChanged));
        public static readonly DependencyProperty SpacingModeProperty = DependencyProperty.RegisterAttached("SpacingMode", typeof(FormPanelSpacing), typeof(FormPanel), new PropertyMetadata(FormPanelSpacing.Normal, OnLayoutAttachedPropertyChanged));
        public static readonly DependencyProperty SpacingProperty = DependencyProperty.Register("Spacing", typeof(int), typeof(FormPanel), new PropertyMetadata(6, OnLayoutPropertyChanged));
        
        public FormPanel()
        {
            Loaded += OnLoaded;
            LayoutUpdated += OnLayoutUpdated;
        }

        public static bool GetIsLabeled(FrameworkElement element)
        {
            return (bool)element.GetValue(IsLabeledProperty);
        }

        public static bool GetIsStretched(FrameworkElement element)
        {
            return (bool)element.GetValue(IsStretchedProperty);
        }

        public static FormPanelLabelPosition GetLabelPosition(FormLabel element)
        {
            return (FormPanelLabelPosition)element.GetValue(LabelPositionProperty);
        }

        public static FormPanelSpacing GetSpacingMode(FrameworkElement element)
        {
            return (FormPanelSpacing)element.GetValue(SpacingModeProperty);
        }

        private static void OnLayoutAttachedPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            var parent = (FormPanel)((FrameworkElement)o).Parent;
            if (parent != null)
            {
                parent.UpdateLayout(false);
            }
        }

        private static void OnLayoutPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            ((FormPanel)o).UpdateLayout(e.Property == OrientationProperty);
        }

        private void OnLayoutUpdated(object sender, EventArgs e)
        {
            Action a = null;
            if (!_loaded || (_lastLayoutChildCount == Children.Count))
            {
                return;
            }
            if (a == null)
            {
                a = () => UpdateLayout(false);
            }
            Dispatcher.BeginInvoke(a);
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            _loaded = true;
            UpdateLayout(false);
        }

        public static void SetIsLabeled(FrameworkElement element, bool labeled)
        {
            element.SetValue(IsLabeledProperty, labeled);
        }

        public static void SetIsStretched(FrameworkElement element, bool stretched)
        {
            element.SetValue(IsStretchedProperty, stretched);
        }

        public static void SetLabelPosition(FormLabel element, FormPanelLabelPosition labelPosition)
        {
            element.SetValue(LabelPositionProperty, labelPosition);
        }

        public static void SetSpacingMode(FrameworkElement element, FormPanelSpacing spacingMode)
        {
            element.SetValue(SpacingModeProperty, spacingMode);
        }

        private void UpdateLayout(bool orientationChanged)
        {
            if (!_loaded)
            {
                return;
            }
            _lastLayoutChildCount = Children.Count;
            if (orientationChanged)
            {
                ColumnDefinitions.Clear();
                RowDefinitions.Clear();
            }
            if (Orientation == Orientation.Horizontal)
            {
                UpdateLayoutHorizontal();
            }
            else
            {
                UpdateLayoutVertical();
            }
        }

        private static void UpdateLayoutHorizontal()
        {
        }

        private void UpdateLayoutVertical()
        {
            ColumnDefinitionCollection columnDefinitions = ColumnDefinitions;
            if (columnDefinitions.Count == 0)
            {
                var definition = new ColumnDefinition {Width = new GridLength(0.0, GridUnitType.Auto)};
                columnDefinitions.Add(definition);
                var definition2 = new ColumnDefinition {Width = new GridLength(LabelSpacing, GridUnitType.Pixel)};
                columnDefinitions.Add(definition2);
                var definition3 = new ColumnDefinition {Width = new GridLength(1.0, GridUnitType.Star)};
                columnDefinitions.Add(definition3);
            }
            var rowDefinitions = RowDefinitions;
            rowDefinitions.Clear();
            var spacing = Spacing;
            var labelSpacing = LabelSpacing;
            var flag = false;
            var flag2 = false;
            var flag3 = true;
            var flag4 = false;
            var num3 = spacing;
            var left = HorizontalAlignment.Left;
            if (LabelAlignment == FormPanelLabelAlignment.Right)
            {
                left = HorizontalAlignment.Right;
            }
            for (var i = 0; i < Children.Count; i++)
            {
                var element = (FrameworkElement)Children[i];
                var label = element as FormLabel;
                if (!flag3 && ((label == null) || (i == 0)))
                {
                    goto Label_014D;
                }
                if (!flag4 || (i == 0))
                {
                    goto Label_0127;
                }
                switch (GetSpacingMode(element))
                {
                    case FormPanelSpacing.Ignore:
                        goto Label_0124;

                    case FormPanelSpacing.Extra:
                        num3 += num3;
                        break;
                }
                var definition4 = new RowDefinition {Height = new GridLength(num3, GridUnitType.Pixel)};
                rowDefinitions.Add(definition4);
            Label_0124:
                flag4 = false;
            Label_0127:
                var definition5 = new RowDefinition {Height = new GridLength(0.0, GridUnitType.Auto)};
                rowDefinitions.Add(definition5);
            Label_014D:
                SetRow(element, rowDefinitions.Count - 1);
                if (label != null)
                {
                    if (GetLabelPosition(label) == FormPanelLabelPosition.Top)
                    {
                        label.HorizontalAlignment = HorizontalAlignment.Left;
                        SetColumnSpan(label, 3);
                        flag2 = true;
                        flag3 = true;
                        num3 = labelSpacing;
                        flag4 = true;
                    }
                    else
                    {
                        label.HorizontalAlignment = left;
                        if (label.VerticalAlignment != VerticalAlignment.Top)
                        {
                            label.VerticalAlignment = VerticalAlignment.Center;
                        }
                        flag2 = false;
                        flag3 = false;
                        num3 = spacing;
                    }
                }
                else
                {
                    if (flag2 || !GetIsLabeled(element))
                    {
                        SetColumnSpan(element, 3);
                        flag2 = false;
                    }
                    else
                    {
                        SetColumn(element, 2);
                        if (!double.IsNaN(element.Width))
                        {
                            element.HorizontalAlignment = HorizontalAlignment.Left;
                        }
                    }
                    if (!flag && GetIsStretched(element))
                    {
                        rowDefinitions[rowDefinitions.Count - 1].Height = new GridLength(1.0, GridUnitType.Star);
                        flag = true;
                        element.VerticalAlignment = VerticalAlignment.Stretch;
                    }
                    else
                    {
                        element.VerticalAlignment = VerticalAlignment.Center;
                    }
                    flag3 = true;
                    num3 = spacing;
                    flag4 = true;
                }
            }
            if (flag)
            {
                return;
            }
            var definition6 = new RowDefinition {Height = new GridLength(1.0, GridUnitType.Star)};
            rowDefinitions.Add(definition6);
        }
        
        public FormPanelLabelAlignment LabelAlignment
        {
            get { return (FormPanelLabelAlignment)GetValue(LabelAlignmentProperty); }
            set { SetValue(LabelAlignmentProperty, value); }
        }

        public int LabelSpacing
        {
            get { return (int)GetValue(LabelSpacingProperty); }
            set { SetValue(LabelSpacingProperty, value); }
        }

        public Orientation Orientation
        {
            get { return (Orientation)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }

        public int Spacing
        {
            get { return (int)GetValue(SpacingProperty); }
            set { SetValue(SpacingProperty, value); }
        }
    }
}
