﻿namespace Dike.Core.Domain.UnitOfWork
{
    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;

    /// <summary>
    /// This interface is used to work with active unit of work. This interface can not be injected. Use <see cref="IUnitOfWorkManager"/> instead.
    /// </summary>
    public interface IActiveUnitOfWork
    {
        #region Events

        /// <summary>
        /// Occurs when the unit of work is successfully completed.
        /// </summary>
        event EventHandler Completed;

        /// <summary>
        /// Occurs when the unit of work is disposed.
        /// </summary>
        event EventHandler Disposed;

        /// <summary>
        /// Occurs when the unit of work fails.
        /// </summary>
        event EventHandler<UnitOfWorkFailedEventArgs> Failed;

        #endregion Events

        #region Properties

        /// <summary>
        /// Gets the data configuration filters.
        /// </summary>
        /// <value>A read-only list with the data filter configurations.</value>
        IReadOnlyList<DataFilterConfiguration> Filters
        {
            get;
        }

        /// <summary>
        /// Gets a value indicating whether this instance is disposed.
        /// </summary>
        /// <value><c>true</c> if this instance is disposed; otherwise, <c>false</c>.</value>
        bool IsDisposed
        {
            get;
        }

        /// <summary>
        /// Gets the unit of work options.
        /// </summary>
        /// <value>The unit of work options.</value>
        UnitOfWorkOptions Options
        {
            get;
        }

        /// <summary>
        /// Gets the tenant identifier.
        /// </summary>
        /// <returns>The tenant identifier.</returns>
        int? TenantId
        {
            get;
        }

        #endregion Properties

        #region Methods

        /// <summary>
        /// Disables one ore more filter.
        /// </summary>
        /// <param name="filterNames">One or more filter names. <see cref="DataFilters"/> for standard filters.</param>
        /// <returns>A <see cref="IDisposable"/> handle to re-enable all concerned filters.</returns>
        IDisposable DisableFilter(params string[] filterNames);

        /// <summary>
        /// Enables one ore more filter.
        /// </summary>
        /// <param name="filterNames">One or more filter names. <see cref="DataFilters"/> for standard filters.</param>
        /// <returns>A <see cref="IDisposable"/> handle to re-disable all concerned filters.</returns>
        IDisposable EnableFilter(params string[] filterNames);

        /// <summary>
        /// Determines whether a given filter is enabled or not.
        /// </summary>
        /// <param name="filterName">Name of the filter.</param>
        /// <returns><c>true</c> if the filter is enabled; otherwise, <c>false</c>.</returns>
        bool IsFilterEnabled(string filterName);

        /// <summary>
        /// Saves all changes until now. This method may be called to apply changes whenever needed.
        /// </summary>
        /// <remarks>Note that if this unit of work is transactional, saved changes are also rolled back if transaction is rolled back.
        /// No explicit call is needed to SaveChanges generally, since all changes saved at end of a unit of work automatically.</remarks>
        void SaveChanges();

        /// <summary>
        /// Asynchronously saves all changes until now. This method may be called to apply changes whenever needed.
        /// </summary>
        /// <remarks>Note that if this unit of work is transactional, saved changes are also rolled back if transaction is rolled back.
        /// No explicit call is needed to SaveChanges generally, since all changes saved at end of a unit of work automatically.</remarks>
        /// <returns>A task that represents the asynchronous operation.</returns>
        Task SaveChangesAsync();

        /// <summary>
        /// Sets or overrides a value of a filter parameter.
        /// </summary>
        /// <param name="filterName">Name of the filter.</param>
        /// <param name="parameterName">Name of the parameter.</param>
        /// <param name="value">The parameter value.</param>
        /// <returns>A <see cref="IDisposable"/> handle to restore the old value of the filter parameter.</returns>
        IDisposable SetFilterParameter(string filterName, string parameterName, object value);

        /// <summary>
        /// Sets the tenant identifier.
        /// </summary>
        /// <param name="tenantId">The new tenant identifier.</param>
        /// <returns>A <see cref="IDisposable"/> handle to restore the old tenant identifier.</returns>
        IDisposable SetTenantId(int? tenantId);

        /// <summary>
        /// Sets the tenant identifier.
        /// </summary>
        /// <param name="tenantId">The new tenant identifier.</param>
        /// <param name="switchMustHaveTenantEnableDisable"><c>true</c> to enable/disable <see cref=" Entities.IMustHaveTenant"/> based on given tenant identifier.
        /// Enables <see cref="Entities.IMustHaveTenant"/> filter if tenant identifier not <c>null</c>. Disables <see cref="Entities.IMustHaveTenant"/> filter if tenant identifier is <c>null</c>.
        /// This value is <c>true</c> for the <see cref="SetTenantId(int?)"/> method.</param>
        /// <returns>A <see cref="IDisposable"/> handle to restore the old tenant identifier.</returns>
        IDisposable SetTenantId(int? tenantId, bool switchMustHaveTenantEnableDisable);

        #endregion Methods
    }
}