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

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

//**************************************************************************************************
/// <summary>
/// </summary>
public partial class HSimpleDictionary<TKey,TValue>: IEnumerable<KeyValuePair<TKey,TValue>> {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[HLockFree]
public bool IsStrictReadonly
{
   get { return _IsStrictReadonly_; }
}

public bool CanBeMadeStrictReadonly
{
   get { return _CanBeMadeStrictReadonly_; }
}

[HLockFree]
public bool IsSynchronized
{
   get { return _IsSynchronized_; }
}

public object SyncRoot
{
   get { return _SyncRoot_; }
}

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

/// <exception cref="HReadonlyObjectAccessException" />
public virtual TValue this[TKey key]
{
   get { return Access(delegate{
      return _Dictionary_[ key ];
   });}
   set { Access(true,delegate{
      _Dictionary_[ key ] = value;
   });}
}

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

public IEqualityComparer<TKey> Comparer
{
   get { return Access(delegate{
      return _Dictionary_.Comparer;
   });}
}

public int Count
{
   get { return Access(delegate{
      return _Dictionary_.Count;
   });}
}

public Dictionary<TKey,TValue>.KeyCollection Keys
{
   get { return Access(delegate{
      return _Dictionary_.Keys;
   });}
}
public Dictionary<TKey,TValue>.ValueCollection Values
{
   get { return Access(delegate{
      return _Dictionary_.Values;
   });}
}

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

public HSimpleDictionary(): this ( true )
{}
public HSimpleDictionary(bool canBeMadeStrictReadonly)
{
   _Dictionary_ = new DictionaryWrapper<TKey,TValue>();
   _CanBeMadeStrictReadonly_ = canBeMadeStrictReadonly;
}

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

public HSimpleDictionary(IEqualityComparer<TKey> comparer)
   :this ( comparer, true )
{}
public HSimpleDictionary(IEqualityComparer<TKey> comparer,bool canBeMadeStrictReadonly)
{
   _Dictionary_ = new DictionaryWrapper<TKey,TValue>( comparer );
   _CanBeMadeStrictReadonly_ = canBeMadeStrictReadonly;
}

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

public HSimpleDictionary( IDictionary<TKey,TValue> initialContent,
                          IEqualityComparer<TKey> comparer )
   :this ( initialContent, comparer, true )
{}
public HSimpleDictionary( IDictionary<TKey,TValue> initialContent,
                          IEqualityComparer<TKey> comparer,
                          bool canBeMadeStrictReadonly )
{
   _Dictionary_ = new DictionaryWrapper<TKey,TValue>( initialContent, comparer );
   _CanBeMadeStrictReadonly_ = canBeMadeStrictReadonly;
}

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

/// <exception cref="InvalidOperationException" />
[HReadonlyObject]
public HSimpleDictionary<TKey,TValue> MakeStrictReadonly()
{
   if ( !CanBeMadeStrictReadonly )
      throw new InvalidOperationException( "The collection can not be made strict readonly." );
   lock ( SyncRoot )
      _IsStrictReadonly_ = true;
   return this;
}

/// <exception cref="HReadonlyObjectAccessException" />
public HSimpleDictionary<TKey,TValue> MakeSynchronized()
{
   Access(true,delegate{ _IsSynchronized_ = true; });
   return this;
}

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

/// <exception cref="HReadonlyObjectAccessException" />
public Dictionary<TKey,TValue> GetBaseDictionary()
{
   return Access(true,delegate{ return BaseDictionary; });
}

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

public HSimpleDictionary<TKey,TValue> GetShallowReadonlyInstance()
{
   var instance = (HSimpleDictionary<TKey,TValue>)MemberwiseClone();
   return instance.MakeStrictReadonly();
}

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

public IEnumerator<KeyValuePair<TKey,TValue>> GetEnumerator()
{
   return Access(delegate{ return BaseDictionary.GetEnumerator(); });
}

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

public List<TKey> GetKeyList(bool ordered=true)
{
   return Access(delegate{
      return _Dictionary_.GetKeyList( ordered );
   });
}
public List<TValue> GetValueList(bool orderedByKey=true)
{
   return Access(delegate{
      return _Dictionary_.GetValueList( orderedByKey );
   });
}

public TKey[] GetKeyArray(bool ordered=true)
{
   return GetKeyList( ordered ).ToArray();
}
public TValue[] GetValueArray(bool orderedByKey=true)
{
   return GetValueList( orderedByKey ).ToArray();
}

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

/// <exception cref="HGenericTypeException" />
public List<TValue> GetOrderedValueList()
{
   return Access(delegate{
      return _Dictionary_.GetOrderedValueList();
   });
}
/// <exception cref="HGenericTypeException" />
public TValue[] GetOrderedValueArray()
{
   return GetOrderedValueList().ToArray();
}

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

protected Dictionary<TKey,TValue> BaseDictionary
{
   get { return _Dictionary_; }
}

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

/// <exception cref="HReadonlyObjectAccessException" />
protected void DenyReadonlyAccess()
{
   if ( IsStrictReadonly ) throw new HReadonlyObjectAccessException();
}

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

protected void Access(Action callback)
{
   Access( false, callback );
}
protected R Access<R>(Func<R> callback)
{
   return Access( false, callback );
}

protected void Access(bool denyReadonlyAccess,Action callback)
{
   if ( denyReadonlyAccess ) DenyReadonlyAccess();
   HConditionalLock.LockIf( IsSynchronized, SyncRoot, callback );
}
protected R Access<R>(bool denyReadonlyAccess,Func<R> callback)
{
   if ( denyReadonlyAccess ) DenyReadonlyAccess();
   return HConditionalLock.LockIf( IsSynchronized, SyncRoot, callback );
}

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

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

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

IEnumerator IEnumerable.GetEnumerator()
{
   return GetEnumerator();
}

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

readonly object
   _SyncRoot_ = new object();
readonly DictionaryWrapper<TKey,TValue>
   _Dictionary_;
readonly bool
   _CanBeMadeStrictReadonly_;
volatile bool
   _IsStrictReadonly_, _IsSynchronized_;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HSimpleDictionary<TKey,TValue>
//**************************************************************************************************

} // CommonHelpers (.WASM)
