using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;


namespace MaterialSkin.Controls
{
    public partial class MaterialUpDown : UserControl,INotifyPropertyChanged
    {
        private double _value;
        private bool _mouseDown;
        private int _direction;

        public MaterialUpDown()
        {
            InitializeComponent();
            textBox1.BackColor = SkinManager.GetApplicationBackgroundColor();

            AllowDecimal = false;
            AllowKeyboard=true;
        }
        [Browsable(false)]
        public MaterialSkinManager SkinManager => MaterialSkinManager.Instance;

        public bool AllowDecimal { get; set; }

        public bool AllowKeyboard
        {
            get { return _allowKeyboard; }
            set
            {
                _allowKeyboard = value;
                textBox1.ReadOnly = !_allowKeyboard || _readOnly;
            }
        }

        public bool HideControls
        {
            get { return _hideControls; }
            set
            {
                _hideControls = value;
                materialIcon1.Visible = !value;
                materialIcon2.Visible = !value;
            }
        }

        public double Value
        {
            get { return _value; }
            set
            {
                _value = value;
                if (_value>Max)
                {
                    _value = Max;
                }

                if (_value < Min)
                {
                    _value = Min;
                }

                if (!AllowDecimal)
                {
                    _value = Math.Floor(_value);
                }

                Action a = ()=> textBox1.Text = _value.ToString();
                if (textBox1.InvokeRequired)
                    textBox1.Invoke(a);
                else
                    a();
            }
        }

        public bool ReadOnly
        {
            get { return _readOnly; }
            set
            {
                _readOnly = value;
                materialIcon1.Enabled = !value;
                materialIcon2.Enabled = !value;
                textBox1.ReadOnly = !_allowKeyboard || _readOnly;
            }
        }

        public event PropertyChangedEventHandler PropertyChanged= delegate { };

        public double Max { get; set; }
        public double Min { get; set; }
        public double Step { get; set; }
        protected override void OnPaintBackground(PaintEventArgs e)
        {
            e.Graphics.Clear(SkinManager.GetApplicationBackgroundColor());
        }

        private void materialIcon2_Click(object sender, EventArgs e)
        {
            
        }

        private void materialIcon1_Click(object sender, EventArgs e)
        {
      
        }

        private async void HoldCountDown(CancellationToken cancellationSourceToken)
        {
            await Task.Delay(500);
            
            var startTime = DateTime.Now;
            while (_mouseDown&&!cancellationSourceToken.IsCancellationRequested)
            {
                Value += Step*_direction;
                await Task.Delay(100/(int)Math.Max(1,Math.Min(5,(DateTime.Now-startTime).TotalSeconds)));
            }
        }

        private CancellationTokenSource _cancellationSource;
        private bool _readOnly;
        private bool _allowKeyboard;

        private void materialIcon2_MouseDown(object sender, MouseEventArgs e)
        {
            
             _cancellationSource =new CancellationTokenSource();
            Value += Step;
           
            _mouseDown = true;
            _direction = 1;
            Task.Run(()=> HoldCountDown(_cancellationSource.Token));
        }

        private void materialIcon2_MouseUp(object sender, MouseEventArgs e)
        {
            if (_cancellationSource != null) 
            {
                _cancellationSource.Cancel();
                _cancellationSource = null;
            }
            _mouseDown = false;
            PropertyChanged(this,new PropertyChangedEventArgs(nameof(Value)));
        }

        private void materialIcon1_MouseDown(object sender, MouseEventArgs e)
        {
            _cancellationSource = new CancellationTokenSource();
            Value -= Step;
       
            _mouseDown = true;
            _direction = -1;
            Task.Run(() => HoldCountDown(_cancellationSource.Token));
        }

        private void materialIcon1_MouseUp(object sender, MouseEventArgs e)
        {
            if (_cancellationSource != null)
            {
                _cancellationSource.Cancel();
                _cancellationSource = null;
            }
            _mouseDown = false;
            PropertyChanged(this, new PropertyChangedEventArgs(nameof(Value)));
        }

        private void materialIcon2_MouseLeave(object sender, EventArgs e)
        {
            materialIcon2_MouseUp(null,null);
        }

        private void materialIcon1_MouseLeave(object sender, EventArgs e)
        {
            materialIcon1_MouseUp(null, null);
        }

        private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
        {
            

            if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) &&
                (e.KeyChar != '.'))
            {
                e.Handled = true;
                return;
            }

            // only allow one decimal point
            if ((e.KeyChar == '.') && ((sender as TextBox).Text.IndexOf('.') > -1))
            {
                e.Handled = true;
                return;
            }

            _validate = true;
        }

        

        private CancellationTokenSource _cancellationTokenSource = null;
        private bool _validate;
        private bool _hideControls;

        private void textBox1_Click(object sender, EventArgs e)
        {
            
            if (textBox1.ReadOnly) return;
            textBox1.SelectAll();
            
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            
        }

        private void textBox1_Leave(object sender, EventArgs e)
        {
            if (double.TryParse((sender as TextBox).Text, NumberStyles.AllowDecimalPoint, CultureInfo.GetCultureInfo("en-us"), out var value))
            {
                if (_cancellationTokenSource != null) _cancellationTokenSource.Cancel();
                _cancellationTokenSource = new CancellationTokenSource();
                Task.Run(async () =>
                {
                    var newValue = value;
                    var token = _cancellationTokenSource.Token;
                    if (token.IsCancellationRequested) throw new OperationCanceledException();
                    Value = newValue;
                    PropertyChanged(this, new PropertyChangedEventArgs(nameof(Value)));
                });

            }
        }

        private void textBox1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                
                textBox1_Leave(textBox1,null);
                e.Handled = true;
            }
        }
    }
}
