/// <summary>
        /// Creates the specified catalog entry.
        /// </summary>
        /// <param name="stream">The stream of <see cref="CatalogEntryStream" /> type to create the entry from.</param>
        /// <returns>The newly created instance of <see cref="CatalogEntry" /> type.</returns>
        public async Task <CatalogEntry> CreateCatalogEntry(CatalogEntryStream stream)
        {
            CatalogEntry entry = stream.Entry;

            FileContract fileContract = await this.mapper.MapNewAsync <CatalogEntry, FileContract>(entry);

            CatalogContract catalogContract = null;

            using (IDbContextScope scope = this.dataContextScopeFactory.CreateDbContextScope(this.connectionStrings.DataStorageDB, true))
            {
                IFileRepository fileRepository = scope.GetRepository <IFileRepository>();
                fileContract = await fileRepository.SaveAsync(fileContract);

                ICatalogRepository catalogRepository = scope.GetRepository <ICatalogRepository>();
                catalogContract = await catalogRepository.GetAsync(fileContract.DirectoryID);

                scope.Commit();
            }

            entry = await this.mapper.MapAsync(fileContract, entry);

            entry.Catalog = await this.mapper.MapAsync(catalogContract, entry.Catalog);

            return(entry);
        }
        /// <summary>
        /// Updates the specified catalog.
        /// </summary>
        /// <param name="catalog">The instance of <see cref="Catalog" /> type to update.</param>
        /// <returns>The updated instance of <see cref="Catalog"/> type.</returns>
        public async Task <Catalog> UpdateCatalog(Catalog catalog)
        {
            CatalogContract catalogContract       = null;
            CatalogContract parentCatalogContract = null;

            using (IDbContextScope scope = this.dataContextScopeFactory.CreateDbContextScope(this.connectionStrings.DataStorageDB, true))
            {
                ICatalogRepository catalogRepository = scope.GetRepository <ICatalogRepository>();

                catalogContract = await catalogRepository.GetAsync(catalog.ID);

                catalogContract = await this.mapper.MapAsync(catalog, catalogContract);

                if (catalogContract.IsChanged)
                {
                    catalogContract = await catalogRepository.SaveAsync(catalogContract);
                }

                if ((catalogContract?.ParentID).HasValue)
                {
                    parentCatalogContract = await catalogRepository.GetAsync(catalogContract.ParentID.Value);
                }

                scope.Commit();
            }

            catalog = await this.mapper.MapAsync(catalogContract, catalog);

            catalog.Parent = await this.mapper.MapAsync(parentCatalogContract, catalog.Parent);

            return(catalog);
        }
        /// <summary>
        /// Updates the specified storage.
        /// </summary>
        /// <param name="storage">The instance of <see cref="Storage" /> type to update.</param>
        /// <returns>The updated instance of <see cref="Storage"/> type.</returns>
        public async Task <Storage> UpdateStorage(Storage storage)
        {
            StorageContract storageContract = null;
            CatalogContract catalogContract = null;

            using (IDbContextScope scope = this.dataContextScopeFactory.CreateDbContextScope(this.connectionStrings.DataStorageDB, true))
            {
                IStorageRepository storageRepository = scope.GetRepository <IStorageRepository>();

                storageContract = await storageRepository.GetAsync(storage.ID);

                storageContract = await this.mapper.MapAsync(storage, storageContract);

                if (storageContract.IsChanged)
                {
                    storageContract = await storageRepository.SaveAsync(storageContract);
                }

                ICatalogRepository catalogRepository = scope.GetRepository <ICatalogRepository>();
                catalogContract = await catalogRepository.GetAsync(storage.ID);

                scope.Commit();
            }

            storage = await this.mapper.MapAsync(storageContract, storage);

            storage = await this.mapper.MapAsync(catalogContract, storage);

            return(storage);
        }
        /// <summary>
        /// Creates the specified storage.
        /// </summary>
        /// <param name="storage">The instance of <see cref="Storage" /> type to create.</param>
        /// <returns>The newly created instance of <see cref="Storage" /> type.</returns>
        public async Task <Storage> CreateStorage(Storage storage)
        {
            StorageContract storageContract = await this.mapper.MapNewAsync <Storage, StorageContract>(storage);

            CatalogContract catalogContract = await this.mapper.MapNewAsync <Storage, CatalogContract>(storage);

            using (IDbContextScope scope = this.dataContextScopeFactory.CreateDbContextScope(this.connectionStrings.DataStorageDB, true))
            {
                ICatalogRepository catalogRepository = scope.GetRepository <ICatalogRepository>();
                catalogContract = await catalogRepository.SaveAsync(catalogContract);

                storageContract.ID = catalogContract.ID;

                IStorageRepository storageRepository = scope.GetRepository <IStorageRepository>();
                storageContract = await storageRepository.SaveAsync(storageContract);

                scope.Commit();
            }

            storage = await this.mapper.MapAsync(storageContract, storage);

            storage = await this.mapper.MapAsync(catalogContract, storage);

            return(storage);
        }
        /// <summary>
        /// Gets the catalog entry by the initial instance set.
        /// </summary>
        /// <param name="entry">The initial catalog entry set.</param>
        /// <returns>The instance of <see cref="CatalogEntry"/> type.</returns>
        public async Task <CatalogEntry> GetCatalogEntry(CatalogEntry entry)
        {
            FileContract    fileContract    = null;
            CatalogContract catalogContract = null;

            using (IDbContextScope scope = this.dataContextScopeFactory.CreateDbContextScope(this.connectionStrings.DataStorageDB, false))
            {
                IFileRepository fileRepository = scope.GetRepository <IFileRepository>();
                fileContract = await fileRepository.GetAsync(entry.ID);

                ICatalogRepository catalogRepository = scope.GetRepository <ICatalogRepository>();
                catalogContract = await catalogRepository.GetAsync(fileContract.DirectoryID);
            }

            entry = await this.mapper.MapAsync(fileContract, entry);

            entry.Catalog = await this.mapper.MapAsync(catalogContract, entry.Catalog);

            return(entry);
        }
        /// <summary>
        /// Gets storage by initial instance set.
        /// </summary>
        /// <param name="storage">The initial storage set.</param>
        /// <returns>The instance of <see cref="Storage"/> type.</returns>
        public async Task <Storage> GetStorage(Storage storage)
        {
            StorageContract storageContract = null;
            CatalogContract catalogContract = null;

            using (IDbContextScope scope = this.dataContextScopeFactory.CreateDbContextScope(this.connectionStrings.DataStorageDB, false))
            {
                IStorageRepository storageRepository = scope.GetRepository <IStorageRepository>();
                storageContract = await storageRepository.GetAsync(storage.ID);

                ICatalogRepository catalogRepository = scope.GetRepository <ICatalogRepository>();
                catalogContract = await catalogRepository.GetAsync(storage.ID);
            }

            storage = await this.mapper.MapNewAsync <StorageContract, Storage>(storageContract);

            storage = await this.mapper.MapAsync(catalogContract, storage);

            return(storage);
        }
        /// <summary>
        /// Gets the list of catalogs located in specified parent catalog.
        /// </summary>
        /// <param name="parent">The parent catalog of <see cref="CatalogRoot"/> type.</param>
        /// <param name="offset">The offset index.</param>
        /// <param name="limit">The number of records to return.</param>
        /// <returns>
        /// The list of instances of <see cref="Catalog" /> type.
        /// </returns>
        public async Task <IPaginable <Catalog> > GetCatalogs(CatalogRoot parent, int offset = 0, int limit = 20)
        {
            if (limit == 0)
            {
                return(await Task.FromResult(new PagedList <Catalog>()
                {
                    Offset = offset,
                    Limit = limit
                }));
            }

            IEnumerable <CatalogContract> data = null;
            int count = 0;

            CatalogContract contract = new CatalogContract()
            {
                ParentID = parent?.ID
            };

            using (IDbContextScope scope = this.dataContextScopeFactory.CreateDbContextScope(this.connectionStrings.DataStorageDB, false))
            {
                ICatalogRepository catalogRepository = scope.GetRepository <ICatalogRepository>();

                await Task.WhenAll(
                    Task.Run(async() => data  = await catalogRepository.FindAsync(contract, offset, limit)),
                    Task.Run(async() => count = await catalogRepository.GetCountAsync(contract)));
            }

            IPaginable <Catalog> result = (await this.mapper.MapNewAsync <CatalogContract, Catalog>(data)).Select(catalog =>
            {
                catalog.Parent = (Catalog)parent;

                return(catalog);
            }).AsPaginable();

            result.Offset     = offset;
            result.Limit      = limit;
            result.TotalCount = count;

            return(result);
        }
        /// <summary>
        /// Gets the list of storages.
        /// </summary>
        /// <param name="offset">The offset index.</param>
        /// <param name="limit">The number of records to return.</param>
        /// <returns>The list of instances of <see cref="Storage"/> type.</returns>
        public async Task <IPaginable <Storage> > GetStorages(int offset = 0, int limit = 20)
        {
            if (limit == 0)
            {
                return(await Task.FromResult(new PagedList <Storage>()
                {
                    Offset = offset,
                    Limit = limit
                }));
            }

            IEnumerable <Storage> storages = null;
            int count = 0;

            using (IDbContextScope scope = this.dataContextScopeFactory.CreateDbContextScope(this.connectionStrings.DataStorageDB, false))
            {
                IStorageRepository storageRepository = scope.GetRepository <IStorageRepository>();
                ICatalogRepository catalogRepository = scope.GetRepository <ICatalogRepository>();

                count = await storageRepository.GetCountAsync();

                IEnumerable <StorageContract> data = await storageRepository.FindAsync(offset, limit);

                storages = await this.mapper.MapNewAsync <StorageContract, Storage>(data);

                storages = await Task.WhenAll(storages.Select(async storage =>
                {
                    CatalogContract catalogContract = await catalogRepository.GetAsync(storage.ID);

                    return(await this.mapper.MapAsync(catalogContract, storage));
                }));
            }

            IPaginable <Storage> result = storages.AsPaginable();

            result.Offset     = offset;
            result.Limit      = limit;
            result.TotalCount = count;

            return(result);
        }
        /// <summary>
        /// Gets a value indicating whether the specified catalog already exists.
        /// </summary>
        /// <param name="catalog">The catalog.</param>
        /// <returns><c>true</c> if the catalog exists. Otherwise <c>false.</c></returns>
        public async Task <bool> CatalogExists(Catalog catalog)
        {
            CatalogContract contract = await this.mapper.MapNewAsync <Catalog, CatalogContract>(catalog);

            if (string.IsNullOrWhiteSpace(contract.Name) && contract.ID == Guid.Empty)
            {
                return(false);
            }

            using (IDbContextScope scope = this.dataContextScopeFactory.CreateDbContextScope(this.connectionStrings.DataStorageDB, false))
            {
                ICatalogRepository catalogRepository = scope.GetRepository <ICatalogRepository>();

                if (!string.IsNullOrWhiteSpace(contract.Name))
                {
                    CatalogContract catalogResult = (await catalogRepository.FindAsync(contract, 0, 1)).FirstOrDefault();

                    return(!(catalogResult is null || (contract.ID != Guid.Empty && contract.ID == catalogResult.ID)));
                }

                return((await catalogRepository.GetAsync(contract.ID)) != null);
            }
        }