using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using SPC.Kiosk.Base;
namespace SPC.Kiosk.Common
{
    /// <summary>
    /// NumericCombo.xaml에 대한 상호 작용 논리
    /// </summary>
    public partial class NumericCombo : UserControl
    {

        #region [ Members ]
        /// <summary>
        /// Text Backgroung Brush
        /// </summary>
        public static readonly DependencyProperty BackgroungBrushProperty =
                 DependencyProperty.Register(nameof(BackgroungBrush), typeof(string), typeof(NumericCombo), new PropertyMetadata("White", new PropertyChangedCallback(OnBackgroungBrushPropertyChanged)));
        /// <summary>
        /// Text  Foregroung Brush
        /// </summary>
        public static readonly DependencyProperty ForegroungBrushProperty =
                 DependencyProperty.Register(nameof(ForegroungBrush), typeof(string), typeof(NumericCombo), new PropertyMetadata("Black", new PropertyChangedCallback(OnForegroungBrushPropertyChanged)));
        /// <summary>
        /// Selected Text BackgroundBrush
        /// </summary>
        public static readonly DependencyProperty SelectBackgroundBrushProperty =
                 DependencyProperty.Register(nameof(SelectBackgroundBrush), typeof(string), typeof(NumericCombo), new PropertyMetadata("DarkGray"));
        /// <summary>
        /// Selected Text ForegroundBrush
        /// </summary>
        public static readonly DependencyProperty SelectForegroundBrushProperty =
                 DependencyProperty.Register(nameof(SelectForegroundBrush), typeof(string), typeof(NumericCombo), new PropertyMetadata("Black"));
        /// <summary>
        /// Left Button AnimationButton Data
        /// </summary>
        public static readonly DependencyProperty LeftButtonDataProperty =
                 DependencyProperty.Register(nameof(LeftButtonData), typeof(M_AnimationButton), typeof(NumericCombo), new PropertyMetadata(null, new PropertyChangedCallback(OnLeftButtonDataPropertyChanged)));
        /// <summary>
        /// Right Button  AnimationButton Data
        /// </summary>
        public static readonly DependencyProperty RightButtonDataProperty =
                 DependencyProperty.Register(nameof(RightButtonData), typeof(M_AnimationButton), typeof(NumericCombo), new PropertyMetadata(null, new PropertyChangedCallback(OnRightButtonDataPropertyChanged)));
        /// <summary>
        /// Min Value
        /// </summary>
        public static readonly DependencyProperty MinValueProperty =
                 DependencyProperty.Register(nameof(MinValue), typeof(int), typeof(NumericCombo), new PropertyMetadata(1, new PropertyChangedCallback(OnMinValuePropertyChanged)));
        /// <summary>
        /// Max Value
        /// </summary>
        public static readonly DependencyProperty MaxValueProperty =
                 DependencyProperty.Register(nameof(MaxValue), typeof(int), typeof(NumericCombo), new PropertyMetadata(4, new PropertyChangedCallback(OnMaxValuePropertyPropertyChanged)));
        /// <summary>
        /// Selected Value
        /// </summary>
        public static readonly DependencyProperty SelectedValueProperty =
                 DependencyProperty.Register(nameof(SelectedValue), typeof(int), typeof(NumericCombo), new PropertyMetadata(-1, new PropertyChangedCallback(OnSelectedValuePropertyChanged)));
        /// <summary>
        /// Value Step
        /// </summary>
        public static readonly DependencyProperty ValueStepProperty =
                 DependencyProperty.Register(nameof(ValueStep), typeof(int), typeof(NumericCombo), new PropertyMetadata(1, new PropertyChangedCallback(OnValueStepPropertyChanged)));
        /// <summary>
        /// Value List
        /// </summary>
        public static readonly DependencyProperty ValueListProperty =
                 DependencyProperty.Register(nameof(ValueList), typeof(List<int>), typeof(NumericCombo), new PropertyMetadata(null, new PropertyChangedCallback(OnValueListPropertyChanged)));
        /// <summary>
        /// Drop Down Show Flag
        /// </summary>
        public static readonly DependencyProperty IsDropDownProperty =
                 DependencyProperty.Register(nameof(IsDropDown), typeof(bool), typeof(NumericCombo), new PropertyMetadata(false));
        /// <summary>
        /// Show DropDown Item Count
        /// </summary>
        public static readonly DependencyProperty DropDownCountProperty =
                 DependencyProperty.Register(nameof(DropDownCount), typeof(int), typeof(NumericCombo), new PropertyMetadata(0, new PropertyChangedCallback(OnDropDownCountPropertyChanged)));
        /// <summary>
        /// Text FontSize
        /// </summary>
        public static readonly DependencyProperty TextFontSizeProperty =
                 DependencyProperty.Register(nameof(TextFontSize), typeof(double), typeof(NumericCombo), new PropertyMetadata(0d, new PropertyChangedCallback(OnTextFontSizePropertyChanged)));
        /// <summary>
        /// Text Width
        /// </summary>
        public static readonly DependencyProperty TextWidthProperty =
                 DependencyProperty.Register(nameof(TextWidth), typeof(double), typeof(NumericCombo), new PropertyMetadata(20d, new PropertyChangedCallback(OnTextWidthPropertyChanged)));


        /// <summary>
        /// Scroll Offset
        /// </summary>
        public static readonly DependencyProperty VerticalOffsetProperty =
                 DependencyProperty.Register(nameof(VerticalOffset), typeof(double), typeof(NumericCombo), new PropertyMetadata(0d, new PropertyChangedCallback(OnVerticalOffsetPropertyChanged)));
        /// <summary>
        /// Text Area Width
        /// </summary>
        public double TextWidth
        {
            get { return (double)GetValue(TextWidthProperty); }
            set { SetValue(TextWidthProperty, value); }
        }
        /// <summary>
        /// Text Area FontSize
        /// </summary>
        public double TextFontSize
        {
            get { return (double)GetValue(TextFontSizeProperty); }
            set { SetValue(TextFontSizeProperty, value); }
        }
        /// <summary>
        /// Scroll Offset
        /// </summary>
        public double VerticalOffset
        {
            get { return (double)GetValue(VerticalOffsetProperty); }
            set { SetValue(VerticalOffsetProperty, value); }
        }
        /// <summary>
        /// Show DropDown Item Count
        /// </summary>
        public int DropDownCount
        {
            get { return (int)GetValue(DropDownCountProperty); }
            set { SetValue(DropDownCountProperty, value); }
        }
        /// <summary>
        /// Drop Down Show Flag
        /// </summary>
        public bool IsDropDown
        {
            get { return (bool)GetValue(IsDropDownProperty); }
            set { SetValue(IsDropDownProperty, value); }
        }
        /// <summary>
        /// Value List
        /// </summary>
        public List<int> ValueList
        {
            get { return (List<int>)GetValue(ValueListProperty); }
            set { SetValue(ValueListProperty, value); }
        }
        /// <summary>
        /// Right Button AnimationButton Data
        /// </summary>
        public M_AnimationButton RightButtonData
        {
            get { return (M_AnimationButton)GetValue(RightButtonDataProperty); }
            set { SetValue(RightButtonDataProperty, value); }
        }
        /// <summary>
        /// Left Button AnimationButton Data
        /// </summary>
        public M_AnimationButton LeftButtonData
        {
            get { return (M_AnimationButton)GetValue(LeftButtonDataProperty); }
            set { SetValue(LeftButtonDataProperty, value); }
        }
        /// <summary>
        /// Min Value
        /// </summary>
        public int MinValue
        {
            get { return (int)GetValue(MinValueProperty); }
            set { SetValue(MinValueProperty, value); }
        }
        /// <summary>
        /// Max Value
        /// </summary>
        public int MaxValue
        {
            get { return (int)GetValue(MaxValueProperty); }
            set { SetValue(MaxValueProperty, value); }
        }
        /// <summary>
        /// Selected Value
        /// </summary>
        public int SelectedValue
        {
            get { return (int)GetValue(SelectedValueProperty); }
            set
            {
                SetValue(SelectedValueProperty, value);
                RaiseSelectChangeEvent(value);
            }
        }
        /// <summary>
        /// Value Step
        /// </summary>
        public int ValueStep
        {
            get { return (int)GetValue(ValueStepProperty); }
            set { SetValue(ValueStepProperty, value); }
        }
        /// <summary>
        /// Text ForegroungBrush
        /// </summary>
        public string ForegroungBrush
        {
            get { return (string)GetValue(ForegroungBrushProperty); }
            set { SetValue(ForegroungBrushProperty, value); }
        }
        /// <summary>
        /// Text BackgroungBrush
        /// </summary>
        public string BackgroungBrush
        {
            get { return (string)GetValue(BackgroungBrushProperty); }
            set { SetValue(BackgroungBrushProperty, value); }
        }
        /// <summary>
        /// Selected Text ForegroundBrush
        /// </summary>
        public string SelectForegroundBrush
        {
            get { return (string)GetValue(SelectForegroundBrushProperty); }
            set { SetValue(SelectForegroundBrushProperty, value); }
        }
        /// <summary>
        /// Selected Text BackgroundBrush
        /// </summary>
        public string SelectBackgroundBrush
        {
            get { return (string)GetValue(SelectBackgroundBrushProperty); }
            set { SetValue(SelectBackgroundBrushProperty, value); }
        }

        private double mouseDownYposition = -1;
        private bool MoseDown = false;
        private bool CurrentMoseDown = false;
        #region [ RoutedEvent 'SelectChange' ]

        /// <summary>
        /// MouseClicked Event
        /// </summary>
        public static readonly RoutedEvent SelectChangeEvent = EventManager.RegisterRoutedEvent(nameof(SelectChange), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(NumericCombo));
        /// <summary>
        /// MouseClicked Routed Event Handler
        /// </summary>
        public event RoutedEventHandler SelectChange
        {
            add { AddHandler(SelectChangeEvent, value); }
            remove { RemoveHandler(SelectChangeEvent, value); }
        }
        #endregion RoutedEvent 'MouseClicked'

        #endregion Members

        #region [  Ctor ]
        /// <summary>
        /// Ctor
        /// </summary>
        public NumericCombo()
        {
            InitializeComponent();
            this.NumericButtonCanvas.Visibility = Visibility.Collapsed;
            this.NumericButtonStack.MouseDown += NumericButtonStack_MouseDown;
            this.NumericButtonStack.MouseUp += NumericButtonStack_MouseUp;
            this.LeftButton.MouseClicked += LeftButton_MouseClicked;
            this.RightButton.MouseClicked += RightButton_MouseClicked;
            this.CurrentNumberText.MouseDown += CurrentNumberText_MouseDown;
            this.CurrentNumberText.MouseUp += CurrentNumberText_MouseUp;
        }
        #endregion Ctor
        
        #region  [ Methods ]
        private void RaiseSelectChangeEvent(object _sender)
        {
            RoutedEventArgs newEventArgs = new RoutedEventArgs(NumericCombo.SelectChangeEvent, _sender);
            RaiseEvent(newEventArgs);
        }
        protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
        {
            this.LeftButton.Width = sizeInfo.NewSize.Height;
            this.LeftButton.Height = sizeInfo.NewSize.Height;
            this.RightButton.Width = sizeInfo.NewSize.Height;
            this.RightButton.Height = sizeInfo.NewSize.Height;
            SetNumericData(this);
            base.OnRenderSizeChanged(sizeInfo);
            
        }
        private static void SetNumericData(NumericCombo _target)
        {
            try
            {
                _target.CurrentNumberText.Width = _target.TextWidth;
                _target.CurrentNumberText.Height = _target.Height;
                if (_target.ValueList is List<int> valueList)
                {
                    _target.NumericButtonStack.Children.Clear();
                    foreach (var i in valueList)
                    {
                        var newTextBlock = new TextBlock
                        {
                            Name = string.Format("NumberText{0}", i),
                            Text = i.ToString(),
                            Width = _target.CurrentNumberText.Width,
                            Height = _target.Height,
                            HorizontalAlignment = HorizontalAlignment.Center,
                            VerticalAlignment = VerticalAlignment.Center,
                            TextAlignment = TextAlignment.Center,
                            FontSize = _target.TextFontSize,
                            FontWeight = _target.CurrentNumberText.FontWeight,
                            Foreground = _target.CurrentNumberText.Foreground,

                        };
                        _target.NumericButtonStack.Children.Add(newTextBlock);
                        _target.ReregisterName(string.Format("NumberText{0}", i), newTextBlock);
                    }
                }
                else if (_target.MaxValue > _target.MinValue && _target.MaxValue >= _target.ValueStep)
                {
                    _target.NumericButtonStack.Children.Clear();
                    for (int i = _target.MinValue; i <= _target.MaxValue; i += _target.ValueStep)
                    {
                        var newTextBlock = new TextBlock
                        {
                            Name = string.Format("NumberText{0}", i),
                            Text = i.ToString(),
                            Width = _target.CurrentNumberText.Width,
                            Height = _target.Height,
                            HorizontalAlignment = HorizontalAlignment.Center,
                            VerticalAlignment = VerticalAlignment.Center,
                            TextAlignment = TextAlignment.Center,
                            FontSize = _target.TextFontSize,
                            FontWeight = _target.CurrentNumberText.FontWeight,
                            Foreground = _target.CurrentNumberText.Foreground

                        };
                        _target.NumericButtonStack.Children.Add(newTextBlock);
                        _target.ReregisterName(string.Format("NumberText{0}", i), newTextBlock);
                    }
                }
                else
                {
                    return;
                }
                _target.NumericButtonCanvas.Width = _target.CurrentNumberText.Width;
                _target.NumericButtonCanvas.Height = _target.Height
                                                   * (_target.DropDownCount > 0 ? _target.DropDownCount
                                                                               : _target.NumericButtonStack.Children.Count);
            }
            catch (Exception ex)
            {
                CommonLog.ErrorLogWrite(_target, "SetNumericData()", "Fail !!", string.Format("{0}\n{1}", ex.Message, ex.StackTrace));
            }
            
        }

        #endregion Methods

        #region [ Event Handlers ]
        private static void OnTextFontSizePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != e.OldValue)
            {
                var target = d as NumericCombo;
                target.CurrentNumberText.FontSize = (double)e.NewValue;
            }
        }
        private static void OnTextWidthPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != e.OldValue)
            {
                var target = d as NumericCombo;
                target.CurrentNumberText.Width = (double)e.NewValue;
            }
        }

        private static void OnVerticalOffsetPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != e.OldValue)
            {
                var target = d as NumericCombo;
                target.NumericScroll.ScrollToVerticalOffset((double)e.NewValue);
            }
        }
        private static void OnDropDownCountPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null && !e.NewValue.Equals(e.OldValue))
            {
                var target = d as NumericCombo;
                target.NumericButtonCanvas.Height = target.Height
                                                  * (target.DropDownCount > 0 ? target.DropDownCount
                                                                             : target.NumericButtonStack.Children.Count);
            }
        }

        private static void OnValueListPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null && !e.NewValue.Equals(e.OldValue))
            {
                var target = d as NumericCombo;
                SetNumericData(target);

            }
        }
        private static void OnMinValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null && !e.NewValue.Equals(e.OldValue))
            {
                var target = d as NumericCombo;
                SetNumericData(target);
            }
        }
        private static void OnMaxValuePropertyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null && !e.NewValue.Equals(e.OldValue))
            {
                var target = d as NumericCombo;
                SetNumericData(target);
            }
        }
        private static void OnSelectedValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null && !e.NewValue.Equals(e.OldValue))
            {
                var target = d as NumericCombo;
                var selectValue = (int)e.NewValue;
                if (selectValue >= target.MinValue && selectValue <= target.MaxValue)
                {
                    target.CurrentNumberText.Text = selectValue.ToString();
                }
                else
                {
                    target.SelectedValue = (int)e.OldValue;
                }
            }

        }
        private static void OnValueStepPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null && !e.NewValue.Equals(e.OldValue))
            {
                var target = d as NumericCombo;
                SetNumericData(target);
            }
        }
        private static void OnRightButtonDataPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null && !e.NewValue.Equals(e.OldValue))
            {
                var target = d as NumericCombo;
                var newData = e.NewValue as M_AnimationButton; ;
                target.Height = newData.Height;
                target.RightButton.DataParameter = newData;
                if (!target.Height.Equals(double.NaN))
                {
                    target.NumericStackGrid.Margin = new Thickness(0, target.Height, 0, 0);
                    SetNumericData(target);
                }
            }
        }
        private static void OnLeftButtonDataPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null && !e.NewValue.Equals(e.OldValue))
            {
                var target = d as NumericCombo;
                var newData = e.NewValue as M_AnimationButton; ;
                target.Height = newData.Height;
                target.LeftButton.DataParameter = newData;
                if (!target.Height.Equals(double.NaN))
                {
                    target.NumericStackGrid.Margin = new Thickness(0, target.Height, 0, 0);
                    SetNumericData(target);
                }
            }
        }
        private static void OnForegroungBrushPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null && !e.NewValue.Equals(e.OldValue))
            {
                var target = d as NumericCombo;
                ResourceManager.SetBrush(target.CurrentNumberGrid, "Background", (string)e.NewValue);
                SetNumericData(target);
            }
        }
        private static void OnBackgroungBrushPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null && !e.NewValue.Equals(e.OldValue))
            {
                var target = d as NumericCombo;
                ResourceManager.SetBrush(target.CurrentNumberGrid, "Background", (string)e.NewValue, Stretch.Fill);
                ResourceManager.SetBrush(target.NumericButtonCanvas, "Background", (string)e.NewValue, Stretch.Fill);
            }
        }
        private void CurrentNumberText_MouseDown(object sender, MouseButtonEventArgs e)
        {
            CurrentMoseDown = true;
        }

        private void CurrentNumberText_MouseUp(object sender, MouseButtonEventArgs e)
        {
            if (!CurrentMoseDown) return;
            if (sender is TextBlock currentText)
            {
                if (this.NumericButtonCanvas.Visibility.Equals(Visibility.Visible))
                {
                    this.NumericButtonCanvas.Visibility = Visibility.Collapsed;
                }
                else
                {
                    if (this.IsDropDown)
                    {
                        this.NumericButtonCanvas.Visibility = Visibility.Visible;
                        foreach (var aNumber in this.NumericButtonStack.Children)
                        {
                            var findNumber = aNumber as TextBlock;

                            if (aNumber != null)
                            {
                                if (aNumber != null && findNumber.Text.Equals(this.CurrentNumberText.Text))
                                {
                                    ResourceManager.SetBrush(findNumber, "Background", this.SelectBackgroundBrush);
                                    ResourceManager.SetBrush(findNumber, "Foreground", this.SelectForegroundBrush);
                                }
                                else
                                {
                                    ResourceManager.SetBrush(findNumber, "Background", this.BackgroungBrush);
                                    ResourceManager.SetBrush(findNumber, "Foreground", this.ForegroungBrush);
                                } 
                            }
                        }
                    }
                }
            }
            CurrentMoseDown = false;
        }
        private void NumericButtonStack_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (sender is StackPanel numStack)
            {
                mouseDownYposition = e.GetPosition(numStack).Y;
                MoseDown = true;
            }
        }
        private void NumericButtonStack_MouseUp(object sender, MouseButtonEventArgs e)
        {
            if (sender is StackPanel numStack)
            {
                if (!MoseDown) return;
                var curMouseYposition = e.GetPosition(numStack).Y;
                var fromOffset = this.NumericScroll.VerticalOffset;
                var toOffset = 0d;
                var totalTime = 0.3;
                Storyboard scrollAnimation = null; 
                if (!mouseDownYposition.Equals(-1) && (mouseDownYposition - curMouseYposition) > 14)
                {
                    if (this.DropDownCount > 0 && this.NumericButtonStack.Children.Count > this.DropDownCount)
                    {
                        toOffset = fromOffset + this.CurrentNumberText.Height * DropDownCount;
                        scrollAnimation = Animations.GetScrollAnimation(this, Orientation.Vertical, fromOffset, toOffset, totalTime);
                    }

                }
                else if (!mouseDownYposition.Equals(-1) && (mouseDownYposition - curMouseYposition) < -14)
                {
                    if (this.DropDownCount > 0 && this.NumericButtonStack.Children.Count > this.DropDownCount)
                    {
                        toOffset = fromOffset - this.CurrentNumberText.Height * DropDownCount;
                        scrollAnimation = Animations.GetScrollAnimation(this, Orientation.Vertical, fromOffset, toOffset, totalTime);

                    }
                }
                else
                {
                    foreach (var aNumber in numStack.Children)
                    {
                        if (aNumber is TextBlock findNumber && findNumber.IsMouseOver)
                        {
                            var findIndex = this.NumericButtonStack.Children.IndexOf(findNumber);
                            this.SelectedValue = int.Parse(findNumber.Text);
                            this.NumericScroll.ScrollToVerticalOffset(findIndex * this.CurrentNumberText.Height);
                            this.NumericButtonCanvas.Visibility = Visibility.Collapsed;
                            break;
                        }
                    }
                }
                mouseDownYposition = curMouseYposition;
                MoseDown = false;
                if (scrollAnimation != null)
                {
                    scrollAnimation.Begin();
                }
            }
        }


        private void RightButton_MouseClicked(object sender, RoutedEventArgs e)
        {
            if (sender is AnimationButton rightButton)
            {
                foreach (var aNumber in this.NumericButtonStack.Children)
                {
                    if (aNumber is TextBlock findNumber)
                    {
                        if (findNumber.Text.Equals(this.CurrentNumberText.Text))
                        {
                            var findIndex = this.NumericButtonStack.Children.IndexOf(findNumber);
                            if (findIndex < this.NumericButtonStack.Children.Count - 1)
                            {
                                this.SelectedValue = int.Parse((this.NumericButtonStack.Children[findIndex + 1] as TextBlock).Text);
                                this.NumericScroll.ScrollToVerticalOffset((findIndex + 1) * this.CurrentNumberText.Height);
                                break;
                            }
                        }
                    }
                }
            }
            this.NumericButtonCanvas.Visibility = Visibility.Collapsed;
        }
        private void LeftButton_MouseClicked(object sender, RoutedEventArgs e)
        {
            if (sender is AnimationButton LeftButton)
            {
                foreach (var aNumber in this.NumericButtonStack.Children)
                {
                    if (aNumber is TextBlock findNumber)
                    {
                        if (findNumber.Text.Equals(this.CurrentNumberText.Text))
                        {
                            var findIndex = this.NumericButtonStack.Children.IndexOf(findNumber);
                            if (findIndex > 0)
                            {
                                this.SelectedValue = int.Parse((this.NumericButtonStack.Children[findIndex - 1] as TextBlock).Text);
                                this.NumericScroll.ScrollToVerticalOffset((findIndex -1) * this.CurrentNumberText.Height);
                                break;
                            }
                        }
                    }
                }
            }
            this.NumericButtonCanvas.Visibility = Visibility.Collapsed;
        }
        #endregion Event Handlers
    }
}
