using System;

namespace Wayne.Lib.AsyncManager
{
    /// <summary>
    /// Async operation that contains a delegate that should be called upon completion. 
    /// When the operation is completed, the Complete() method should be called, which results in that the result delegate
    /// will be invoked, and the operation will be removed from the Async Manager cache. Cancel can also be called, to remove
    /// the operation from the outstanding operation list without calling the delegate.
    /// </summary>
    /// <typeparam name="TOperationId">Type of the OperationId </typeparam>
    /// <typeparam name="TResultEventArgs"></typeparam>
    public class AsyncOperation<TOperationId, TResultEventArgs> : AsyncOperation<TOperationId> where TResultEventArgs : EventArgs
    {
        #region Fields

        private EventHandler<TResultEventArgs> resultDelegate;
        private Type resultEventArgsType;

        #endregion

        #region Construction

        /// <summary>
        /// Internal constructor.
        /// </summary>
        /// <param name="owner"></param>
        /// <param name="id"></param>
        /// <param name="userToken"></param>
        /// <param name="data"></param>
        /// <param name="resultDelegate"></param>
        /// <param name="abandonedTime"></param>
        internal AsyncOperation(object owner, TOperationId id, object userToken, object data, EventHandler<TResultEventArgs> resultDelegate, TimeSpan abandonedTime)
            : base(owner, id, userToken, data, abandonedTime)
        {
            this.resultDelegate = resultDelegate;
            resultEventArgsType = typeof(TResultEventArgs);
        }

        #endregion

        #region Properties

        internal override Type ResultEventArgsType
        {
            get { return resultEventArgsType; }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Completes the operation, calls the result delegate with the specified event args.
        /// </summary>
        /// <param name="resultEventArgs"></param>
        public void Complete(TResultEventArgs resultEventArgs)
        {
            Complete();

            if (resultDelegate != null)
                resultDelegate(Owner, resultEventArgs);
        }

        #endregion

        #region Debug methods

        /// <summary>
        /// Presents the class as a string.
        /// </summary>
        /// <returns></returns>
        public virtual string ToString(string format, IFormatProvider provider)
        {
            string ownerName;
            IIdentifiableEntity identifiableOwner = Owner as IIdentifiableEntity;
            if (identifiableOwner != null)
                ownerName = IdentifiableEntity.ToString(identifiableOwner);
            else
                ownerName = this.Owner.ToString();

            return string.Format(System.Globalization.CultureInfo.InvariantCulture, "AsyncOperation<TOperatorId={0},TResultEventArgs={1}> Owner={2},Id={3},",
                                 typeof(TOperationId).FullName, typeof(TResultEventArgs).FullName, ownerName, Id);
        }

        /// <summary>
        /// Presents the class as a string using the specified culture-specific format information.
        /// </summary>
        /// <returns></returns>
        public virtual string ToString(IFormatProvider provider)
        {
            return ToString("", provider);
        }

        /// <summary>
        /// Presents the class as a string using a format string.
        /// </summary>
        /// <returns></returns>
        public virtual string ToString(string format)
        {
            return ToString(format, System.Globalization.CultureInfo.InvariantCulture);
        }

        /// <summary>
        /// Presents the class as a string using a format string and the specified culture-specific format information.
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return ToString("", System.Globalization.CultureInfo.InvariantCulture);
        }

        #endregion
    }
}