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

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

static partial class enum_val {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/// <exception cref="EGenericType" />
/// <exception cref="ArgumentException" />
/// <exception cref="EParseValue" />
public static EnumType Parse<EnumType>( string src, EnumType? def=null )
where EnumType: struct =>
   ParseX<EnumType>( src, def, 0 );

/// <exception cref="EGenericType" />
/// <exception cref="ArgumentException" />
/// <exception cref="EParseValue" />
public static EnumType Parse<EnumType>( string src, char? separator, EnumType? def=null )
where EnumType: struct =>
   ParseX<EnumType>( src, null, def, 0 );

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

/// <exception cref="EGenericType" />
/// <exception cref="ArgumentException" />
/// <exception cref="EParseValue" />
public static EnumType ParseX<EnumType>( string src, EnumType? def, u.enum_parse_options options )
where EnumType: struct
{
   Type type = typeof( EnumType );
   u.gtype_check.Enum( type, false );
   src = src.Trim();
   if ( src == "" && !def.HasValue )
      throw new ArgumentException(
         "Source string for nonflags enumeration parse is empty "+
         "and no default value is specified." );
   try {
      return (EnumType)Enum.Parse( type, src,
         (options & u.enum_parse_options.IgnoreCase) != 0 );
   }
   catch ( ArgumentException e ) {
      throw e_parse_value.New( e );
   }
}

/// <exception cref="EGenericType" />
/// <exception cref="ArgumentException" />
/// <exception cref="EParseValue" />
public static EnumType ParseX<EnumType>( string src, char? separator, EnumType? def,
                                         u.enum_parse_options options )
where EnumType: struct
{
   Type type = typeof( EnumType );
   u.gtype_check.Enum( type, true );

   string[] stringValues = src.Split( separator ?? '+',
      StringSplitOptions.RemoveEmptyEntries |
      StringSplitOptions.TrimEntries );

   if ( stringValues.Length == 0 )
      if ( def.HasValue )
         return def.Value;
      else
         throw new ArgumentException(
            "Source string for flags enumeration parse is empty "+
            "and no default value is specified." );

   var list = new List<string>();
   var sb = new StringBuilder();
   bool ignoreCase = (options & u.enum_parse_options.IgnoreCase) != 0;
   bool forbidDuplicates = (options & u.enum_parse_options.ForbidDuplicates) != 0;
   foreach ( string stringValue in stringValues ) {
      try {
         Enum.Parse( type, stringValue, ignoreCase );
      }
      catch ( ArgumentException e ) {
         throw e_parse_value.New( e );
      }
      if ( forbidDuplicates &&
           list.Exists(str => u.str.Equals( str, stringValue, ignoreCase )) )
         throw e_parse_value.New(
            "Dulplicate flag for enumeration value: “{0}”.",
            stringValue );
      if ( list.Count > 0 )
         sb.Append( ',' );
      sb.Append( stringValue );
      list.Add( stringValue );
   }

   try {
      return (EnumType)Enum.Parse( type, sb.ToString(), ignoreCase );
   }
   catch ( ArgumentException e ) {
      throw e_parse_value.New( e );
   }
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // enum_val

} // user_rtx (.wasm)
