//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// CommonHelpers satellite library | Author: Sergei Y.Kitáev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
using System;
using System.Reflection;
using System.Configuration;
using System.Runtime.CompilerServices;

namespace CommonHelpers {

//**************************************************************************************************
/// <summary>
/// </summary>
public partial class HApplicationSettingsBase: ApplicationSettingsBase {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

enum ValueSource { Default, Storage, Field }

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

public Exception InitializationException
{
   get { return _InitializationException_; }
}

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

public T GetValue<T>(MethodBase getMethod)
{
   if (_ReadActualValues_)
   {
      string propertyName =
         HPropertyInfo.ExtractNameByGetMethod( getMethod );
      object valueObject =
         this[ propertyName ];
      if (valueObject!=null)
         return (T)valueObject;
   }
   string defaultValueString =
      GetDefaultValueString( getMethod );
   return defaultValueString!=null ?
      (T)Parse<T>( getMethod, defaultValueString ) :
      default( T );
}

public void SetValue(MethodBase setMethod,object value)
{
   this[ HPropertyInfo.ExtractNameBySetMethod( setMethod ) ] = value;
}

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

[MethodImpl(MethodImplOptions.NoInlining)]
public void ProbeValue(object value)
{}

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

protected virtual Type ActualType
{
   get { throw new NotSupportedException(); }
}

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

protected virtual void ProbeValues()
{
   throw new NotSupportedException();
}

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

protected void Constructor(bool useDefaultValues)
{
   Prepare(true);
   if (!useDefaultValues)
      if (!Prepare(false))
         Prepare(true);
}

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

static HApplicationSettingsBase()
{
   CommonHelpers_Plus.Access();
}

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

bool Prepare(bool useDefaultValues)
{
   _ReadActualValues_ = !useDefaultValues;
   try
   {
      ProbeValues();
   }
   catch (Exception e)
   {
      if (useDefaultValues)
         throw;
      _InitializationException_ = e;
      return false;
   }
   return true;
}

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

string GetDefaultValueString(MethodBase getMethod)
{
   string
      propertyName = HPropertyInfo.ExtractNameByGetMethod( getMethod );
   var
      propertyInfo = ActualType.GetProperty( propertyName );
   var
      attributes = propertyInfo.GetCustomAttributes(
         typeof(DefaultSettingValueAttribute), false );
   if (attributes.Length>1)
      throw HOpFailedExceptionCreator.Create(
         "Ambigous default value of application settings property: \"{0}\".",
         propertyName );
   return attributes.Length>0 ?
      ((DefaultSettingValueAttribute)attributes[0]).Value :
      null;
}

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

static object Parse<T>(MethodBase getMethod,string valueString)
{
   MethodInfo method =
      typeof(T).GetMethod( "Parse",
         BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod,
         null, new Type[]{typeof(string)}, null );
   if (method==null)
      throw HOpFailedExceptionCreator.Create(
         "Necessary static method \"Parse\" of type \"{0}\" is not found.\n"+
         "(Application settings property: \"{1}\".)",
         typeof(T), HPropertyInfo.ExtractNameByGetMethod( getMethod ) );
   return
      method.Invoke(null,new object[]{valueString});
}

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

bool
   _ReadActualValues_;
Exception
   _InitializationException_;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HApplicationSettingsBase
//**************************************************************************************************

} // CommonHelpers
