using CareFusion.Lib.StorageSystem.Helpers.Enums;
using CareFusion.Lib.StorageSystem.Stock;
using System;

namespace CareFusion.Lib.StorageSystem.Input
{
    /// <summary>
    /// Interface which defines the methods and properties of an infeed input request.
    /// </summary>
    public interface IInfeedInputRequest
    {
        #region Properties

        /// <summary>
        /// Gets the unique identifier number which is used to identify an infeed input process.
        /// </summary>
        string Id { get; }

        /// <summary>
        /// Gets the destination identifier of the storage system that should start the input process.
        /// </summary>
        int Destination { get; }

        /// <summary>
        /// Gets the current state of the infeed input process.
        /// </summary>
        InfeedInputRequestState State { get; }

        /// <summary>
        /// The reason for the rejection of an infeed input.
        /// This property is set after the input process finished.
        /// </summary>
        InfeedInputRejectReason RejectionReason { get; }

        /// <summary>
        /// Optional additional description for the rejection of an infeed input.
        /// This property is set after the input process finished.
        /// </summary>
        string RejectionDescription { get;  }

        /// <summary>
        /// If the infeed pack input is part of a new stock delivery, this property
        /// specifies the delivery number which will be used during pack input.
        /// If this property is null, this pack input is NOT part of a new delivery.
        /// </summary>
        string DeliveryNumber { get; }

        /// <summary>
        /// Flag whether the storage system will set a so-called picking 
        /// indicator during the infeed input to enforce a redefinition 
        /// of the requested pack articles as storage system capable articles.
        /// This flag is usually used when the new storage system 
        /// gets filled for the very first time to realize a kind
        /// of first-time synchronization between the IT system and 
        /// the storage system according to which articles are "storage
        /// system articles".
        /// </summary>
        bool PickingIndicator { get; }

        /// <summary>
        /// Gets the number which defines the infeed source that should be used 
        /// to transfer the pack into the storage system. 
        /// </summary>
        int InfeedNumber { get; }

        /// <summary>
        /// Gets the list of packs that are ready to be input.
        /// </summary>
        IPack[] InputPacks { get; }

        /// <summary>
        /// Gets the information of the articles and the packs that are processed during
        /// the input. This property is set after the input process finished.
        /// </summary>
        IArticle[] InputArticles { get; }

        #endregion

        #region Events

        /// <summary>
        /// Event which is raised when the infeed input process requested the placement of the packs to input.
        /// </summary>
        /// <param name="sender">The infeed input process instance which raised the event.</param>
        /// <param name="e">Not used.</param>
        event EventHandler PlacePacks;

        /// <summary>
        /// Event which is raised when the infeed input process finished execution.
        /// </summary>
        /// <param name="sender">The infeed input process instance which raised the event.</param>
        /// <param name="e">Not used.</param>
        event EventHandler Finished;

        #endregion

        #region Methods

        /// <summary>
        /// Adds a new pack that is ready for input.
        /// </summary>
        /// <param name="scanCode">Raw scan code of the pack.</param>
        /// <param name="batchNumber">Optional batch number of the pack.</param>
        /// <param name="externalId">Optional external identifier of the pack.</param>
        /// <param name="expiryDate">Optional expiry date of the pack.</param>
        /// <param name="expiryDateSource">Optional source for the pack's expiry date.</param>
        /// <param name="subItemQuantity">Optional number of elements (e.g. pills or ampoules) which are currently in this pack.</param>
        /// <param name="depth">Optional depth of the pack in mm.</param>
        /// <param name="width">Optional width of the pack in mm.</param>
        /// <param name="height">Optional height of the pack in mm.</param>
        /// <param name="shape">Optional shape of the pack.</param>
        /// <param name="stockLocationId">Optional stock location to use for the pack.</param>
        /// <param name="machineLocation">Optional machine location to use for the pack.</param>
        /// <param name="serialNumber">Optional serial number of the pack.</param>
        void AddInputPack(string scanCode,
            string batchNumber = null,
            string externalId = null,
            Nullable<DateTime> expiryDate = null,
            ExpiryDateSource expiryDateSource = ExpiryDateSource.AutoCalculated,
            int subItemQuantity = 0,
            int depth = 0,
            int width = 0,
            int height = 0,
            PackShape shape = PackShape.Cuboid,
            string stockLocationId = null,
            string machineLocation = null,
            string serialNumber = null);

        /// <summary>
        /// Initiates the input process by sending the according request to the storage system.
        /// </summary>
        void Start();

        /// <summary>
        /// Notifies the storage system that the input packs have been placed.
        /// </summary>
        void PacksPlaced();

        /// <summary>
        /// Notifies the storage system that the infeed input has to be aborted.
        /// </summary>
        void Abort();

        #endregion
    }
}
