﻿using System;

namespace Cegl
{
    /// <summary>
    /// Represents global helpers.
    /// </summary>
    public static class GlobalHelpers
    {
        /// <summary>
        /// Indicates whether two floating point values <see cref='System.Double'/> are approximately equal.
        /// </summary>
        /// <param name="value1"> First value.</param>
        /// <param name="value2"> Second value.</param>
        /// <param name="epsilon"> Accuracy (by default 1e-10).</param>
        /// <returns>
        /// Returns true if <paramref name="value1"/> and <paramref name="value2"/> are equal
        /// with <paramref name="epsilon"/> accuracy; otherwise, false.
        /// </returns>
        public static Boolean ApproxEqual(this Double value1, Double value2, Double epsilon = GlobalConstants.Epsilon)
        {
            var absValue1 = Math.Abs(value1);
            var absValue2 = Math.Abs(value2);
            var diff = Math.Abs(value1 - value2);
            if (value1.Equals(value2)) return true;
            if (value1.Equals(0) || value2.Equals(0) || diff < Double.Epsilon) return diff < epsilon;
            return diff/(absValue1 + absValue2) < epsilon;
        }

        /// <summary>
        /// Indicates whether second value <see cref='System.Double'/> is approximately grater then this <see cref='System.Double'/> value.
        /// </summary>
        /// <param name="value1"> First value.</param>
        /// <param name="value2"> Second value.</param>
        /// <param name="epsilon"> Accuracy (by default 1e-10).</param>
        /// <returns>
        /// Returns true if <paramref name="value2"/> grater then <paramref name="value1"/>
        /// with <paramref name="epsilon"/> accuracy; otherwise, false.
        /// </returns>
        public static Boolean ApproxGraterThan(this Double value1, Double value2, Double epsilon = GlobalConstants.Epsilon)
            => value1 > value2 + epsilon;

        /// <summary>
        /// Indicates whether second value <see cref='System.Double'/> is approximately less then this <see cref='System.Double'/> value.
        /// </summary>
        /// <param name="value1"> First value.</param>
        /// <param name="value2"> Second value.</param>
        /// <param name="epsilon"> Accuracy (by default 1e-10).</param>
        /// <returns>
        /// Returns true if <paramref name="value2"/> less then <paramref name="value1"/>
        /// with <paramref name="epsilon"/> accuracy; otherwise, false.
        /// </returns>
        public static Boolean ApproxLessThan(this Double value1, Double value2, Double epsilon = GlobalConstants.Epsilon)
            => value1 + epsilon < value2 ;

        /// <summary>
        /// Extension adapter for <see cref='System.Double.IsNaN'/> method.
        /// </summary>
        /// <param name="value"> Value to check.</param>
        /// <returns>Returns a value that indicates whether the specified value is not a number (<see cref='System.Double.NaN'/>).</returns>
        public static Boolean IsNaN(this Double value) => Double.IsNaN(value);

        /// <summary>
        /// Extension adapter for <see cref='System.Double.IsInfinity'/> method.
        /// </summary>
        /// <param name="value"> Value to check.</param>
        /// <returns> Returns a value indicating whether the specified number evaluates to negative or positive infinity.</returns>
        public static Boolean IsInf(this Double value) => Double.IsInfinity(value);

        /// <summary>
        /// Extension adapter for <see cref='System.Math.Round(Double,Int32)'/> method.
        /// </summary>
        /// <param name="value"> A double-precision floating-point number to be rounded.</param>
        /// <param name="dights"> The number of fractional digits in the return value.</param>
        /// <returns> Returns number nearest to value that contains a number of fractional digits equal to digits.</returns>
        public static Double Round(this Double value, Int32 dights) => Math.Round(value, dights);
    }
}