using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace Earthblend.Nts.Common
{
    public class RelayCommand<T> : ICommand
    {
        readonly Action<T> _targetExecuteMethod;
        readonly Func<T, Boolean> _targetCanExecuteMethod;
        public RelayCommand(Action<T> executeMethod)
        {
            _targetExecuteMethod = executeMethod;
        }
        public RelayCommand(Action<T> executeMethod, Func<T, Boolean> canExecuteMethod)
        {
            _targetExecuteMethod = executeMethod;
            _targetCanExecuteMethod = canExecuteMethod;
        }
        public void RaiseCanExecuteChanged()
        {
            CanExecuteChanged(this, System.EventArgs.Empty);
        }
        #region ICommand Members
        Boolean ICommand.CanExecute(Object parameter)
        {
            if (_targetCanExecuteMethod == null) return _targetExecuteMethod != null;
            T tparm = (T)parameter;
            return _targetCanExecuteMethod(tparm);
        }
        public event EventHandler CanExecuteChanged = delegate { };
        void ICommand.Execute(Object parameter)
        {
            _targetExecuteMethod?.Invoke((T)parameter);
        }
        #endregion
    }

    public class Shape3DFormulaAttribute : Attribute
    {
        public String Name { get; set; }
    }

    public class Mesh3DFormulaAttribute : Attribute
    {
        public String Name { get; set; }
    }

    public class VariableNameAttribute : Attribute
    {
        public String Name { get; set; }
    }

    public static class MathExt
    {
        public static Double ReduceFracNum(Double wholePart, Double numerator, Double denominator)
        {
            return new FractionReducer(wholePart, numerator, denominator).Numerator;
        }

        public static Double ReduceFracDen(Double wholePart, Double numerator, Double denominator)
        {
            return new FractionReducer(wholePart, numerator, denominator).Denominator;
        }

        public static Double Frac(Double value)
        {
            StringBuilder sb = new StringBuilder();
            String str = value.ToString();
            int index = str.IndexOf(".");
            StringBuilder sbDecimals = new StringBuilder();
            int pos = 0;
            foreach (var c in str)
            {
                if (pos > index) sbDecimals.Append(c);
                pos++;
            }
            String val = sbDecimals.ToString();
            sb.Append("1");
            for (int i = 1; i <= val.Length; i++)
                if (i != 0) sb.Append("0");
            return Convert.ToDouble(sb.ToString());
        }

        public static int Dec(Double value)
        {
            String str = value.ToString();
            Boolean startCount = false;
            if (!str.Contains(".")) return 0;
            int decimalCount = -1;
            foreach (Char c in str)
            {
                if (c == '.')
                {
                    startCount = true;
                }
                if (startCount) decimalCount++;
            }
            return decimalCount;
        }
    }
    public class FractionReducer
    {
        public FractionReducer(Double wholePart, Double numerator, Double denominator)
        {
            WholePart = wholePart;
            Numerator = numerator;
            Denominator = denominator;
            Normalize();
        }
        public Double WholePart { get; private set; }
        public Double Numerator { get; private set; }
        public Double Denominator { get; private set; }
        private Double GCD(Double a, Double b)
        {
            while (b != 0)
            {
                Double t = b;
                b = a % b;
                a = t;
            }
            return a;
        }
        private void Reduce(Double x)
        {
            Numerator /= x;
            Denominator /= x;
        }
        private void Normalize()
        {
            Numerator += WholePart * Denominator;
            Reduce(GCD(Numerator, Denominator));
            Reduce(Math.Sign(Denominator));
            WholePart = Numerator / Denominator;
            Numerator %= Denominator;
        }
        override public String ToString()
        {
            return String.Format("{0} {1}/{2}", WholePart, Numerator, Denominator);
        }
    }

}

