//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// CommonHelpers satellite library | Author: Sergei Y.Kitáev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
using System;
using System.Collections.Generic;

#if !WASM
namespace CommonHelpers {
#else
namespace CommonHelpers.WASM {
#endif

//**************************************************************************************************
/// <summary>
/// </summary>
public static partial class HArray {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public static bool IsNullOrEmpty(Array array)
{
   return array==null || array.Length==0;
}

public static bool IsNullOrEmpty<T>(T[] array)
{
   return array==null || array.Length==0;
}

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

public static int RelativeIndex<T>(T[] array,int zeroBazedIdx)
{
   return array.GetLowerBound(0)+zeroBazedIdx;
}

public static int RelativeIndex<T>(T[] array,int zeroBazedIdx,bool accountNotFoundIndexValue)
{
   return accountNotFoundIndexValue && zeroBazedIdx==-1 ?
      NotFoundElementIndexOf(array) : RelativeIndex(array,zeroBazedIdx);
}

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

public static int ZeroBasedIndex<T>(T[] array,int relativeIdx)
{
   return relativeIdx - array.GetLowerBound(0);
}

public static int ZeroBasedIndex<T>(T[] array,int relativeIdx,bool accountNotFoundIndexValue)
{
   return accountNotFoundIndexValue && relativeIdx==NotFoundElementIndexOf(array) ?
      -1 : ZeroBasedIndex(array,relativeIdx);
}

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

public static bool IsIndexInValidBounds<T>(T[] array,int index)
{
   HArgChecking.VerifyNotNull( array );
   return HOps.IsBetween( index, array.GetLowerBound(0), array.GetUpperBound(0) );
}

public static bool IsIndexInValidBounds(Array array,int dimension,int index)
{
   HArgChecking.VerifyNotNull( array );
   HArrayArgChecking.VerifyDimension( array, dimension );
   return HOps.IsBetween( index,
      array.GetLowerBound( dimension ),
      array.GetUpperBound( dimension ) );
}

public static bool IsValidDimension(Array array,int dimension)
{
   HArgChecking.VerifyNotNull( array );
   return HOps.IsBetween(dimension,0,array.Rank-1);
}

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

public static int NotFoundElementIndex<T>(int baseIndex)
{
   return baseIndex>int.MinValue ? baseIndex-1 : int.MaxValue;
}

public static int NotFoundElementIndexOf<T>(T[] array)
{
   HArgChecking.VerifyNotNull( array );
   return NotFoundElementIndex<T>( array.GetLowerBound(0) );
}

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

/// <exception cref="System.ArgumentNullException" />
/// <exception cref="HElementNotFoundException" />
public static void VerifyElementFound<T>(T[] array,int index)
{
   if (!IsIndexInValidBounds(array,index))
      throw new HElementNotFoundException();
}

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

public static T GetAtZeroBasedIndex<T>(T[] array,int zeroBazedIdx)
{
   return array[ RelativeIndex(array,zeroBazedIdx) ];
}

public static void SetAtZeroBasedIndex<T>(T[] array,int zeroBazedIdx,T value)
{
   array[ RelativeIndex(array,zeroBazedIdx) ] = value;
}

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

public static bool Contains<T>(T[] array,T value)
{
   return IsIndexInValidBounds( array, Array.IndexOf( array, value ) );
}

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

/// <exception cref="ArgumentNullException" />
public static T[] Duplicate<T>(T[] array)
{
   HArgChecking.VerifyNotNull( array );
   return (T[])array.Clone();
}

[HOptionalResult]
public static T[] DuplicateOrNull<T>([HOptional] T[] array)
{
   return array!=null ? Duplicate( array ) : null;
}

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

public static T[] CreateInit<T>(int length,T uniformValue)
{
   return SetUniformValue( new T[ length ], uniformValue );
}

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

[HOptionalResult]
public static T[] SetUniformValue<T>([HOptional] T[] array,T value)
{
   if ( array == null )
      return null;
   for (int idx=array.GetLowerBound(0); idx<=array.GetUpperBound(0); idx++)
      array[ idx ] = value;
   return array;
}

[HOptionalResult]
public static T[] SetDefaultValueForAll<T>([HOptional] T[] array)
{
   return SetUniformValue( array, default(T) );
}

[HOptionalResult]
public static T[] SetNullForAll<T>([HOptional] T[] array) where T: class
{
   return SetDefaultValueForAll( array );
}

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

public static T[] SetValue<T>(T[] array,T value,int startIdx)
{
   HArrayArgChecking.VerifyIndex( array, startIdx );
   return SetValue( array, value, startIdx, array.Length - startIdx );
}

public static T[] SetValue<T>(T[] array,T value,int startIdx,int count)
{
   HArrayArgChecking.VerifyIndex( array, startIdx );
   if ( count <= 0 )
      throw new ArgumentOutOfRangeException();
   int endIdx = startIdx + count - 1;
   if ( endIdx > array.GetUpperBound(0) )
      throw new ArgumentOutOfRangeException();
   for (int idx=startIdx; idx<=endIdx; idx++)
      array[ idx ] = value;
   return array;
}

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

public static T[] SetDefaultValue<T>(T[] array,int startIdx)
{
   return SetValue( array, default(T), startIdx );
}

public static T[] SetDefaultValue<T>(T[] array,int startIdx,int count)
{
   return SetValue( array, default(T), startIdx, count );
}

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

public static T[] Copy<T>(T[] source,T[] destination)
{
   HArgChecking.VerifyNotNulls( source, destination );
   if ( source.Length != destination.Length )
      throw new ArgumentException();
   source.CopyTo( destination, destination.GetLowerBound(0) );
   return destination;
}

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

public static string[] ToStrings<T>(T[] array)
{
   HArrayArgChecking.VerifyOneDimensional( array );
   var list = new List<string>( array.GetLength(0) );
   foreach (T element in array)
      list.Add( element.ToString() );
   return list.ToArray();
}

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

[HOptionalResult]
public static object SyncRootOrNull(Array array)
{
   return array!=null ? array.SyncRoot : null;
}

/// <exception cref="ArgumentNullException" />
public static object[] SyncRoots(params Array[] arrays)
{
   HArgChecking.VerifyNotNull( arrays );
   int cnt = 0;
   foreach (var array in arrays)
      if ( array != null ) cnt++;
   var rslt = new Array[ cnt ];
   int i = 0;
   foreach (var array in arrays)
      if ( array != null )
         rslt[ i++ ] = array;
   return rslt;
}

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

static HArray()
{
   CommonHelpers_Core.Access();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HArray
//**************************************************************************************************

} // CommonHelpers (.WASM)
