using System;
using JD.Kernel.Classes;
using JD.Kernel.StaticHelpers;
namespace JD.PropertyService
{
///
/// Properties that cache changes made to them until they are bulk written to
/// the property object which is being cached.
///
public class TransactionalProperties : Properties, IDisposable
{
#region Variables
private readonly Scope m_isSyncing = new Scope();
private IProperties m_internalProperties;
private bool m_isDirty;
#endregion
#region Constructor
///
/// Constructor
///
public TransactionalProperties()
: this(new Properties())
{}
///
/// Constructor
///
///
public TransactionalProperties(IProperties cachedProperties)
{
Throw.IfNull(cachedProperties, "cachedProperties");
InternalProperties = cachedProperties;
}
#endregion
#region Properties
///
/// Dirty flag
///
public bool IsDirty
{
get { return m_isDirty; }
}
public override bool IsReadOnly
{
get
{
return m_internalProperties.IsReadOnly;
}
}
///
/// Access to the cached properties
///
public IProperties InternalProperties
{
get
{
return m_internalProperties;
}
set
{
if (m_internalProperties != null)
{
m_internalProperties.PropertyChanged -= InternalPropertiesPropertyChanged;
}
m_internalProperties = value;
if (m_internalProperties != null)
{
m_internalProperties.PropertyChanged += InternalPropertiesPropertyChanged;
Revert();
}
}
}
private bool Syncing
{
get { return m_isSyncing.InScope; }
}
#endregion
#region Public Methods
///
/// Write dirty cache entries to cached properties, then reload the cache.
///
public void Commit()
{
if (!Syncing)
{
using (m_isSyncing.Begin())
{
if (m_isDirty && OnPropertyChanging())
{
using (m_internalProperties.BeginScopedUpdate())
{
m_internalProperties.Clear();
CopyTo(m_internalProperties);
}
m_isDirty = false;
OnCommit();
}
}
}
}
///
/// Load the cache from the properties being cached, discarding any previous cache content.
///
public void Revert()
{
if (!Syncing)
{
using (m_isSyncing.Begin())
{
Clear();
m_internalProperties.CopyTo(this);
m_isDirty = false;
OnReverted();
}
}
}
#endregion
#region Events
private void OnCommit()
{
Commited?.Invoke(this, EventArgs.Empty);
}
private void OnReverted()
{
Reverted?.Invoke(this, EventArgs.Empty);
}
///
/// Raised when the cache has been reloaded from the cached item.
///
public event EventHandler Reverted;
///
/// Raised when a dirty cache was written.
///
public event EventHandler Commited;
#endregion
#region Event Handlers
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
m_isDirty = true;
base.OnPropertyChanged(e);
}
private void InternalPropertiesPropertyChanged(object sender, PropertyChangedEventArgs e)
{
Revert();
}
#endregion
#region IDisposable Members
///
/// Interface implementation
///
public void Dispose()
{
// unbind event handlers
InternalProperties = null;
}
#endregion
}
}