// ReSharper disable StyleCop.SA1600
// ReSharper disable InheritdocConsiderUsage
namespace NURBS
{
    using System.Collections.Generic;
    using System.Globalization;
    using System.Linq;
    using System.Text.RegularExpressions;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;

    /// <summary>
    /// Interaction logic for KnotVectorDialog.xaml
    /// </summary>
    public partial class KnotVectorDialog : Window
    {
        private readonly int _degree;

        private readonly decimal[] _backup;

        private readonly decimal[] _autogenerated;

        // ReSharper disable PossibleNullReferenceException
        public KnotVectorDialog(decimal[] dCanvasKnotVector, int dCanvasDegree)
        {
            this.InitializeComponent();
            this.Owner = Application.Current.MainWindow;
            this._degree = dCanvasDegree;
            this.KnotVector = dCanvasKnotVector;
            this._backup = dCanvasKnotVector;
            this._autogenerated = NurbsLogic.GenerateKnotVector(((InputWindow)this.Owner).DCanvas.ControlPoints.Count, ((InputWindow)this.Owner).DCanvas.Degree);
            this.Bar();
        }

        public decimal[] KnotVector { get; private set; }

        private void Bar()
        {
            this.Grd.RowDefinitions.Clear();
            this.Grd.Children.Clear();

            for (var i = 0; i < this.KnotVector.Length; i++)
            {
                var knot = this.KnotVector[i];

                this.Grd.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
                var tb = new TextBox { Text = knot.ToString(CultureInfo.InvariantCulture), Tag = i };

                tb.PreviewTextInput += TbOnPreviewTextInput;

                if (knot.AlmostEquals(0M) || knot.AlmostEquals(1M))
                {
                    tb.IsEnabled = false;
                }

                this.Grd.Children.Add(tb);
                Grid.SetColumn(tb, 0);
                Grid.SetRow(tb, i);
            }
        }

        private static void TbOnPreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            var regex = new Regex("[^0-9.]+"); // regex that matches disallowed text
            var allowed = !regex.IsMatch(e.Text);
            e.Handled = !allowed;
        }

        private void OK_Click(object sender, RoutedEventArgs e)
        {
            var list = new List<decimal>();

            foreach (var tb in this.Grd.Children)
            {
                var i = (int)((TextBox)tb).Tag;
                var valid = decimal.TryParse(((TextBox)tb).Text, out var knot);

                list.Add(knot);

                var a = this._backup[i];
                if (knot.AlmostEquals(a))
                {
                    continue;
                }

                if (!valid || !(knot.GreaterThan(0M) && knot.LessThan(1M)))
                {
                    Keyboard.Focus((FrameworkElement)tb);
                    MessageBox.Show(
                        "Knot must be a number between 0 and 1.",
                        "Wrong input!",
                        MessageBoxButton.OK,
                        MessageBoxImage.Warning);
                    e.Handled = false;
                    return;
                }
            }

            foreach (var knot in list)
            {
                if (knot.AlmostEquals(0M) || knot.AlmostEquals(1M))
                {
                    continue;
                }

                if (list.Count(x => x == knot) > _degree && _degree > 0)
                {
                    MessageBox.Show(
                        "Multiplicity of a knot cannot be greater than degree.",
                        "Wrong input!",
                        MessageBoxButton.OK,
                        MessageBoxImage.Warning);
                    e.Handled = false;
                    return;
                }
            }

            var arr = list.ToArray();
            var ordered = list.OrderBy(x => x).ToArray();

            if (!arr.SequenceEqual(ordered))
            {
                MessageBox.Show(
                    "This knot vector is not a nondecreasing sequence.",
                    "Wrong input!",
                    MessageBoxButton.OK,
                    MessageBoxImage.Warning);
                e.Handled = false;
                return;
            }

            this.KnotVector = arr;
            this.DialogResult = true;
        }

        private void Reset_Click(object sender, RoutedEventArgs e)
        {
            this.KnotVector = this._autogenerated;
            this.Bar();
        }
    }
}
