using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Linq;

using C1.Silverlight.Extended;
using C1.Silverlight.Gauge;
using C1.Silverlight;


namespace GaugeBuilder
{
    public partial class Page 
        : UserControl
    {
        public Page()
        {
            InitializeComponent();

            // initialize property grid
            InitializePropertyGrid();

            // initialize the gauge combo
            comboGaugeType.SelectedIndex = 1;
         }

        // -----------------------------------------------------------------------------
        #region ** property grid

        private void InitializePropertyGrid() 
        {
            //set custom editors
            pgGeneral.AvailableEditors.Add(new SizeEditor());
            pgGeneral.AvailableEditors.Add(new PointEditor());

            // load decorators properties
            pgGeneral.PropertyAttributes.Add(CreateResourceBasedDecorator<Style>("DefaultTextStyle", "Appareance", "LabelStyles.xaml"));
            pgGeneral.PropertyAttributes.Add(CreateResourceBasedDecorator<DataTemplate>("DefaultBigMarkTemplate", "Appareance", "Marks.xaml"));
            pgGeneral.PropertyAttributes.Add(CreateResourceBasedDecorator<DataTemplate>("DefaultMiddleMarkTemplate", "Appareance", "Marks.xaml"));
            pgGeneral.PropertyAttributes.Add(CreateResourceBasedDecorator<DataTemplate>("DefaultSmallMarkTemplate", "Appareance", "Marks.xaml"));

            // load visual properties
            pgGeneral.PropertyAttributes.AddRange(GenerateDecorators("Appareance", "FaceVisibility"));
            pgGeneral.PropertyAttributes.Add(CreateResourceBasedDecorator<DataTemplate>("FaceTemplate", "Appareance", "RadialFaces.xaml"));
            pgGeneral.PropertyAttributes.AddRange(GenerateDecorators("Appareance", "CoverVisibility"));
            pgGeneral.PropertyAttributes.Add(CreateResourceBasedDecorator<DataTemplate>("CoverTemplate", "Appareance", "RadialCovers.xaml"));

            // initialize editors
            pgGeneral.PropertyBoxChanged += (s, a) =>
            {
                // value
                Configure<C1NumericBox>(pgGeneral, (e) =>
                {
                    e.Minimum = CurrentGauge.Minimum;
                    e.Maximum = CurrentGauge.Maximum;
                }, "Value");

                // integer number
                Configure<C1NumericBox>(pgGeneral, (e) =>
                {
                    e.Increment = 1;
                    e.Format = "n0";
                    e.RangeValidationMode = RangeValidationMode.AlwaysTruncate;
                }, "Appareance", "Value", "Minimum", "Maximum", "StartAngle", "SweepAngle", "OffAngle", "LogarithmicBase");

                // relative numbers
                Configure<C1NumericBox>(pgGeneral, (e) =>
                {
                    e.Increment = 0.05;
                    e.Format = "f2";
                }, "Radius", "XAxisLocation", "XAxisLength", "YAxisLocation", "OffLocation", 
                   "PointerLength", "PointerWidth", "PointerOffset", "PointerOrigin");                                        
            };

            // keep range values
            pgGeneral.ValueChanged += (s, a) => 
            {
                if (a.PropertyName == "Minimum" || a.PropertyName == "Maximum")
                {
                    // value
                    var editorValue = GetEditor<C1NumericBox>(pgGeneral, "Scale", "Value");
                    if (editorValue != null)
                    {
                        editorValue.Minimum = CurrentGauge.Minimum;
                        editorValue.Maximum = CurrentGauge.Maximum;
                        editorValue.Value = Math.Min(editorValue.Maximum, Math.Max(editorValue.Minimum, editorValue.Value));
                    }
                }

                if (a.PropertyName == "Orientation")
                {
                    var tmp = CurrentGauge.Height;
                    CurrentGauge.Height = CurrentGauge.Width;
                    CurrentGauge.Width = tmp;
                }
            };
        }

        private void Configure<T>(C1PropertyGrid pGrid, Action<T> configuration, string categoryName, params string[] propertyNames)
            where T: Control
        {
            foreach (var propertyName in propertyNames)
            {
                var editor = GetEditor<T>(pGrid, categoryName, propertyName);
                if (editor != null)
                {
                    configuration(editor);
                }
            }
        }


        private T GetEditor<T>(C1PropertyGrid pGrid, string categoryName, string propertyName) 
            where T: Control
        {
            var presenter = pGrid.GetPropertyPresenter(propertyName);
            if (presenter != null) 
            {
                return (presenter.CurrentEditor as T);
            }
            return null;
        }


        private PropertyAttribute CreateCollectionDecorator<T>(string propertyName, string caption, string categoryName, params string[] removeProperties)
            where T : C1GaugeDecorator
        {
            var editor = new CollectionEditor<T>();

            // remove some inner property decorators
            foreach (var pRemoveName in removeProperties)
            {
                editor.InnerPropertyAttributes.Add(new PropertyAttribute()
                {
                    MemberName = pRemoveName,
                    Browsable = false
                });
            }
            return new PropertyAttribute()
            {
                Category = categoryName,
                MemberName = propertyName,
                DisplayName = caption,
                Editor = editor,
                Browsable = true
            };
        }

        private PropertyAttribute CreateResourceBasedDecorator<T>(string propertyName, string categoryName, params string[] resourcesUris)
            where T : DependencyObject
        {
            var editor = new DependencyObjectEditor<T>();
            editor.ItemsSource = ResourcesHelper.GetResources<T>(true, resourcesUris);
            return new PropertyAttribute()
            { 
                Category = categoryName.ToString(),
                MemberName = propertyName,
                DisplayName = propertyName.SplitUpperCaseToString(),
                Editor = editor,
                Browsable = true
            };
        }

        private IList<PropertyAttribute> GenerateDecorators(string categoryName, params string[] names)
        {
            var dec = new List<PropertyAttribute>();
            foreach (var propertyName in names)
            {
                dec.Add(new PropertyAttribute()
                {
                    Category = categoryName,
                    MemberName = propertyName,
                    DisplayName = propertyName.SplitUpperCaseToString(),
                    Browsable = true
                });
            }
            return dec;
        }

        #endregion

        // -----------------------------------------------------------------------------
        #region ** combo

        private C1Gauge CurrentGauge 
        {
            get 
            {
                if (comboGaugeType.SelectedIndex == 0)
                    return radialGauge;
                else if (comboGaugeType.SelectedIndex == 1)
                    return linearGauge;
                else if (comboGaugeType.SelectedIndex == 2)
                    return knobGauge;
                else
                    return null;
            }
        }

        private void comboGaugeType_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // update property grid
            pgGeneral.SelectedObject = CurrentGauge;

            // show only current gauge
            foreach (var gauge in new C1Gauge[] { radialGauge, linearGauge, knobGauge})
            {
                gauge.Visibility = (CurrentGauge == gauge) 
                                    ? Visibility.Visible 
                                    : Visibility.Collapsed;
            }
        }

        #endregion
    }
}
