// TODO: adapter à Silverlight (utiliser System.Threading.Timer ?) et à WinRT
#if !SILVERLIGHT && !NETFX_CORE
using System;
using System.Text;
using System.Timers;
using Developpez.Dotnet.Properties;
namespace Developpez.Dotnet
{
    /// 
    /// Représente une chaîne de caractères à durée de vie limitée.
    /// Lorsque la durée de vie expire, la chaîne de caractères est vidée.
    /// La durée de vie est réinitialisée à chaque ajout de caractère.
    /// 
    public class TemporaryString
    {
#region Fields
        /// 
        /// Durée de vie par défaut.
        /// 
        private static readonly double _DEFAULTLIFETIME = 1000;
        /// 
        /// Instance du Timer.
        /// 
        private readonly Timer _timer;
        /// 
        /// Chaîne de caractères.
        /// 
        private readonly StringBuilder _value;
        /// 
        /// Evènement levé lorsque la durée de vie a expiré.
        /// 
        /// La chaîne de caractère est vidée.
        public event EventHandler Reset;
        /// 
        /// Evènement levé lorsqu'un caractère a été ajouté à l'instance.
        /// 
        /// La durée de vie est réinitialisée.
        public event EventHandler CharAdded;
        #endregion
#region Constructors
        /// 
        /// Intialise une nouvelle instance de la classe  avec la durée de vie par défaut.
        /// 
        public TemporaryString()
            : this(_DEFAULTLIFETIME, string.Empty)
        { }
        /// 
        /// Intialise une nouvelle instance de la classe  avec la durée de vie donnée.
        /// 
        /// Durée de vie (en millisecondes).
        public TemporaryString(double lifeTime)
            : this(lifeTime, string.Empty)
        { }
        /// 
        /// Intialise une nouvelle instance de la classe  avec la valeur initiale donnée.
        /// 
        /// Valeur initiale.
        public TemporaryString(string value)
            : this(_DEFAULTLIFETIME, value)
        { }
        /// 
        /// Intialise une nouvelle instance de la classe  
        /// avec la durée de vie et la valeur initiale données.
        /// 
        /// Durée de vie.
        /// Valeur initiale.
        public TemporaryString(double lifeTime, string value)
        {
            if (lifeTime <= 0)
                throw new ArgumentOutOfRangeException("lifeTime", ExceptionMessages.NegativeLifeTime);
            if (value == null)
                throw new ArgumentNullException("value");
            this._timer = new Timer(lifeTime);
            this._value = new StringBuilder(value);
            this._timer.Elapsed += this._Timer_Elapsed;
            this._timer.Enabled = true;
            this._timer.AutoReset = false;
        }
        #endregion
        /// 
        /// Elapsed timer event.
        /// 
        /// Source object.
        /// Elapsed event arguments.
        private void _Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            this._value.Length = 0;
            // Stop the timer :
            this._timer.Stop();
            EventHandler handler = Reset;
            // NOTE : Make a temporary copy of the event to avoid possibility of a race condition 
            // if the last subscriber unsubscribes immediately after the null check and before the event is raised.
            if (handler != null)
                handler(this, new EventArgs());
        }
#region Public methods
        /// 
        /// Ajoute un caractère à la fin de la chaîne.
        /// 
        /// Le caractère Unicode à ajouter.
        public void Append(char value)
        {
            this._value.Append(value);
            // Reset the timer :
            this._timer.Stop();
            this._timer.Start();
            EventHandler handler = CharAdded;
            // NOTE : Make a temporary copy of the event to avoid possibility of a race condition 
            // if the last subscriber unsubscribes immediately after the null check and before the event is raised.
            if (handler != null)
                handler(this, new EventArgs());
        }
        /// 
        /// Ajoute un tableau de caractères à la fin de cette instance.
        /// 
        /// Le tableau de caractères Unicode à ajouter.
        public void Append(char[] value)
        {
            foreach (var c in value)
                this.Append(c);
        }
        /// 
        /// Ajoute une chaîne de caractères à la chaîne courante.
        /// 
        /// Chaîne de caractères à ajouter à la chaîne courante.
        public void Append(string value)
        {
            foreach (char c in value)
                this.Append(c);
        }
        /// 
        /// Retourne une chaîne de caractères représentant l'instance courante.
        /// 
        /// Une chaîne de caractères représentant l'instance courante.
        public override string ToString()
        {
            return this._value.ToString();
        }
        #endregion
    }
}
#endif