//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// UserRTX.NET satellite library | Author: Sergei Y.Kitáev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
using System;

#if !WASM
namespace user_rtx { using u = user_rtx;
#else
namespace user_rtx.wasm { using u = user_rtx.wasm;
#endif

/// <summary>
/// Arithmetical operations with integers
/// </summary>
public static class int_math {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public static bool IsOdd( int n ) =>
   n % 2 != 0;

public static bool IsEven( int n ) =>
   n % 2 == 0;

//--------------------------------------------------------------------------------------------------

public static int Sign( int n )
{
   if ( n > 0 ) return  1;
   if ( n < 0 ) return -1;
   return 0;
}

public static bool HaveSameSign( int m, int n ) =>
   Sign( m ) * Sign( n ) >= 0;

//==================================================================================================

public static int ConfinePositiveOrZero( int n ) =>
   Math.Max( n, 0 );
public static int ConfineNegativeOrZero( int n ) =>
   Math.Min( n, 0 );

//--------------------------------------------------------------------------------------------------

[CLSCompliant(false)]
public static int ConfinePositiveOrZero( ref int n ) =>
   n = ConfinePositiveOrZero( n );
[CLSCompliant(false)]
public static int ConfineNegativeOrZero( ref int n ) =>
   n = ConfineNegativeOrZero( n );

//--------------------------------------------------------------------------------------------------

/// <exception cref="ArgumentOutOfRangeException" />
public static int Confine( int n, int min, int max ) =>
   min <= max ?
      Math.Min( Math.Max( n, min ), max ) :
      throw math_argcheck_errors.INCORRECT_MIN_MAX( nameof(min), nameof(max) );

/// <exception cref="ArgumentOutOfRangeException" />
[CLSCompliant(false)]
public static int Confine( ref int n, int min, int max ) =>
   n = Confine( n, min, max );

//--------------------------------------------------------------------------------------------------

/// <exception cref="ArgumentOutOfRangeException" />
public static int UpConfine( ref int n, int max ) =>
   n = Math.Min( n, max );
/// <exception cref="ArgumentOutOfRangeException" />
public static int DownConfine( ref int n, int min ) =>
   n = Math.Max( n, min );

//==================================================================================================

/// <exception cref="ArgumentOutOfRangeException" />
/// <exception cref="OverflowException" />
public static int RoundDiv( int m, int n )
{
   int div = m / u.arg_check.NotZero( n, nameof(n) );
   return
      Math.Abs( m % n * 2 ) >= Math.Abs( n ) ?
      ( Math.Abs( div ) + 1 ) * Sign( m ) * Sign( n ) :
      div;
}

/// <exception cref="ArgumentOutOfRangeException" />
/// <exception cref="OverflowException" />
public static int UpperDiv( int m, int n )
{
   u.arg_check.NotZero( n, nameof(n) );
   return m / n + ( m % n != 0 ? Sign(m)*Sign(n) : 0 );
}

//--------------------------------------------------------------------------------------------------

/// <exception cref="ArgumentOutOfRangeException" />
/// <exception cref="OverflowException" />
public static int Power( int m, int n )
{
   u.arg_check.NotZero( n, nameof(n) );
   int result = 1;
   for ( int i=0; i<n; i++ )
      result *= m;
   return result;
}

//==================================================================================================

/// <exception cref="ArgumentException" />
public static int Min( params int[] values )
{
   u.array_argcheck.NotEmpty( values, nameof(values) );
   int? min = null;
   foreach ( var val in values )
      if ( min == null || val < min )
         min = val;
   return min.V();
}

/// <exception cref="OverflowException" />
public static int Sum( params int[] values )
{
   int sum = 0;
   foreach ( int val in values )
      sum += val;
   return sum;
}

/// <exception cref="ArgumentException" />
/// <exception cref="OverflowException" />
public static int Avg( params int[] values )
{
   u.array_argcheck.NotEmpty( values, nameof(values) );
   return RoundDiv( Sum( values ), values.Length );
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // int_math

} // user_rtx (.wasm)
