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

namespace CommonHelpers {

//**************************************************************************************************
static partial class HDB {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/// <exception cref="ArgumentNullException" />
/// <exception cref="InvalidCastException" />
/// <exception cref="HDatabaseException" />
[HOptionalResult]
public static T GetFieldValue<T>( [HOptional] string? procedureName,
                                  SqlDataReader dataReader, string fieldName,
                                  [HOptional] IDictionary<string,int>? fieldIndexer,
                                  bool treatNullAsDefaultValue = false )
{
   int fieldIdx = GetFieldIndex( procedureName, dataReader, fieldName, fieldIndexer, true );
   object value = dataReader[ fieldIdx ];
   var type = typeof(T);
   if (!( value is DBNull ))
      try { return (T)value; }
      catch (Exception e)
      {
         throw new InvalidCastException(HString.FormatAsText(HLocal.TEXT(
            "Can not cast value of result-set field \"{0}\" to type \"{1}\".{2}\n"+
            "{3}",
            "Не удаётся привести значение поля резалт-сета \"{0}\" к типу \"{1}\".{2}\n"+
            "{3}"
         ), fieldName, type, LFnStoredProcOrEmpty( procedureName ), e.Message ));
      }
   if ( treatNullAsDefaultValue || HType.IsNullable( type ) )
      return default(T)!;
   throw new InvalidCastException(HString.FormatAsText(HLocal.TEXT(
      "Result-set field \"{0}\" of type \"{1}\" has null value.{2}",
      "Поле резалт-сета \"{0}\" типа \"{1}\" содержит нул-значение.{2}"
   ), fieldName, type, LFnStoredProcOrEmpty( procedureName ) ));
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="ArgumentException" />
/// <exception cref="InvalidCastException" />
/// <exception cref="HDatabaseException" />
[HOptionalResult]
public static T GetOutputParameterValue<T>( string procedureName,
                                            SqlParameter parameter,
                                            bool treatNullAsDefaultValue = false )
{
   HArgChecking.VerifyNotNulls( procedureName, parameter );
   string paramName = parameter.ParameterName;
   if ( !HOps.IsOneOf( parameter.Direction,
                       ParameterDirection.Output,
                       ParameterDirection.InputOutput ) )
      throw new ArgumentException(HString.FormatAsText(HLocal.TEXT(
         "Parameter \"{0}\" is not output or input-output parameter.{1}",
         "Параметр \"{0}\" не является выходным либо входным-выходным параметром.{1}"
      ), paramName, LFnStoredProcOrEmpty( procedureName ) ));
   object value = parameter.Value;
   var type = typeof(T);
   if (!( value is DBNull ))
      try { return (T)value; }
      catch (Exception e)
      {
         throw new InvalidCastException(HString.FormatAsText(HLocal.TEXT(
            "Can not cast value of \"{0}\"-parameter to type \"{1}\".{2}\n"+
            "{3}",
            "Не удаётся привести значение параметра \"{0}\" к типу \"{1}\".{2}\n"+
            "{3}"
         ), paramName, type, LFnStoredProcOrEmpty( procedureName ), e.Message ));
      }
   if ( treatNullAsDefaultValue || HType.IsNullable( type ) )
      return default(T)!;
   throw new InvalidCastException(HString.FormatAsText(HLocal.TEXT(
      "Output parameter \"{0}\" of type \"{1}\" has null value.{2}",
      "Выходной параметр \"{0}\" типа \"{1}\" содержит нул-значение.{2}"
   ), paramName, type, LFnStoredProcOrEmpty( procedureName ) ));
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="InvalidCastException" />
[HOptionalResult]
public static T GetSPReturnValue<T>(string procedureName,SqlParameter returnValueParam)
{
   HArgChecking.VerifyNotNulls( procedureName, returnValueParam );
   var rv = returnValueParam.Value;
   if ( rv == null )
      return default(T)!;
   try { return (T)rv; }
   catch (Exception e)
   {
      throw new InvalidCastException(HString.FormatAsText(HLocal.TEXT(
         "Can not cast return value stored procedure [{0}] to type \"{1}\".\n"+
         "{2}",
         "Не удаётся привести возвратное значение хранимой процедуры [{0}] к типу \"{1}\".\n"+
         "{2}"
      ), procedureName, typeof(T), e.Message ));
   }
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HDB
//**************************************************************************************************

} // CommonHelpers
