/// <summary>
 /// Gets the hashes information from database.
 /// </summary>
 /// <returns></returns>
 private async Task <HashesInfo> GetHashesInfoFromDB()
 {
     if (_hashesInfoStatic == null)
     {
         if (_hi == null)                   //local value is empty, fill it from DB once
         {
             _hi = null;                    //await CalculateHashesInfo(null, null, null, null);
         }
         if (_hi == null || _hi.IsCalculating)
         {
             return(_hi);                                //still calculating, return just this local value
         }
         else
         {
             _hashesInfoStatic = _hi;                    //calculation ended, save to global static value
         }
     }
     return(await Task.FromResult(_hashesInfoStatic));
 }
        internal static Moq.Mock <IHashesRepository> MockHashesRepository()
        {
            var    mock = new Moq.Mock <IHashesRepository>();
            string ilfad = "ilfad", alphabet = "abcdefghijklmopqrstuvwxyz";
            var    hashes = new List <ThinHashes>(3)
            {
                new ThinHashes
                {
                    Key        = ilfad,
                    HashMD5    = MD5(ilfad),
                    HashSHA256 = Sha256(ilfad)
                }
            };
            HashesInfo hi = new HashesInfo
            {
                ID            = 0,
                IsCalculating = false
            };

            mock.Setup(r => r.SetReadOnly(Moq.It.IsAny <bool>()));

            mock.Setup(r => r.CalculateHashesInfo(Moq.It.IsAny <ILogger>(), Moq.It.IsAny <DbContextOptions <BloggingContext> >(), default))
            .Returns(() =>
            {
                return(Task.FromResult(hi));
            })
            .Callback(() =>
            {
                hi.ID            = 0;
                hi.Alphabet      = alphabet;
                hi.Count         = (int)Math.Pow(alphabet.Length, ilfad.Length);
                hi.IsCalculating = false;
                hi.KeyLength     = ilfad.Length;
            });

            mock.SetupGet(r => r.CurrentHashesInfo).Returns(() =>
            {
                return(Task.FromResult(hi));
            });

            mock.Setup(r => r.FindByAsync(Moq.It.IsAny <Expression <Func <ThinHashes, bool> > >())).Returns <Expression <Func <ThinHashes, bool> > >((s) =>
            {
                var expr  = s.Compile();
                var found = hashes.Where(h => expr.Invoke(h)).ToList();
                return(Task.FromResult(found));
            });

            mock.Setup(r => r.AutoComplete(Moq.It.IsAny <string>())).Returns <string>((s) =>
            {
                var found = hashes.Where(h =>
                                         h.HashMD5.ToLowerInvariant().StartsWith(s) || h.HashSHA256.ToLowerInvariant().StartsWith(s) || h.Key.ToLowerInvariant().StartsWith(s))
                            .DefaultIfEmpty(new ThinHashes {
                    Key = "nothing found"
                });

                return(Task.FromResult(found));
            });

            mock.Setup(r => r.AddRangeAsync(Moq.It.IsAny <IEnumerable <ThinHashes> >())).Returns <IEnumerable <ThinHashes> >((s) =>
            {
                hashes.AddRange(s);

                return(Task.FromResult(0));
            });

            mock.Setup(r => r.PagedSearchAsync(Moq.It.IsAny <string>(), Moq.It.IsAny <string>(), Moq.It.IsAny <string>(),
                                               Moq.It.IsAny <int>(), Moq.It.IsAny <int>(), Moq.It.IsAny <CancellationToken>()))
            .Returns((string sort, string order, string search, int offset, int limit, CancellationToken token) =>
            {
                token.ThrowIfCancellationRequested();

                var column_names = WebControllers.BaseController <ThinHashes> .AllColumnNames;

                IEnumerable <ThinHashes> items = WebControllers.BaseController <ThinHashes> .SearchItems(hashes.AsQueryable(), search, column_names);

                (IEnumerable <ThinHashes> Itemz, int Count)orgtuple =
                    WebControllers.BaseController <ThinHashes> .ItemsToJson(items, sort, order, limit, offset);
                (IEnumerable <string[]> Itemz, int Count)tuple =
                    (orgtuple.Itemz.Select(tab => new string[] { tab.Key, tab.HashMD5, tab.HashSHA256 }), orgtuple.Count);

                return(Task.FromResult(tuple));
            });

            mock.Setup(r => r.SearchAsync(Moq.It.IsAny <HashInput>())).Returns((HashInput inp) =>
            {
                ThinHashes th;
                if (inp.Kind == KindEnum.MD5)
                {
                    th = hashes.FirstOrDefault(x => x.HashMD5 == inp.Search);
                }
                else
                {
                    th = hashes.FirstOrDefault(x => x.HashSHA256 == inp.Search);
                }

                return(Task.FromResult(th ?? new ThinHashes {
                    Key = "nothing found"
                }));
            });

            mock.Setup(r => r.GetAll()).Returns(() =>
            {
                var querable = hashes.AsQueryable();
                return(querable);
            });

            return(mock);
        }
        public async Task <HashesInfo> CalculateHashesInfo(ILogger logger, Microsoft.EntityFrameworkCore.DbContextOptions <BloggingContext> dbContextOptions,
                                                           CancellationToken token = default)
        {
            using (var client = new DocumentClient(new Uri(_endpoint), _key))
            {
                HashesInfo hi = null;
                try
                {
                    if (GetHashesInfoFromDB().Result != null)
                    {
                        if (logger != null)
                        {
                            logger.LogInformation(0, $"###Leaving calculation of initial Hash parameters; already present");
                        }
                        return(GetHashesInfoFromDB().Result);
                    }
                    if (logger != null)
                    {
                        logger.LogInformation(0, $"###Starting calculation of initial Hash parameters");
                    }

                    hi = new HashesInfo {
                        ID = 0, IsCalculating = true
                    };

                    _hashesInfoStatic = hi;                    //temporary save to static to indicate calculation and block new calcultion threads


                    var collection_link = UriFactory.CreateDocumentCollectionUri(_databaseId, _collectionId);
                    //var alphabet = client.CreateDocumentQuery<DocumentDBHash>(collection_link)
                    //	.Select(f => f.Key.First())
                    //	.Distinct()
                    //	.OrderBy(o => o);
                    int.TryParse(client.CreateDocumentQuery <DocumentDBHash>(collection_link)
                                 .OrderByDescending(x => x.Key).Take(1).ToArray().FirstOrDefault().Id, out int count);
                    var key_length = client.CreateDocumentQuery <int>(collection_link,
                                                                      "SELECT TOP 1 VALUE LENGTH(c.Key) FROM c").ToAsyncEnumerable().First();

                    hi.Count         = count;
                    hi.KeyLength     = await key_length;
                    hi.Alphabet      = "fakefakefake";               //string.Concat(alphabet);
                    hi.IsCalculating = false;

                    if (logger != null)
                    {
                        logger.LogInformation(0, $"###Calculation of initial Hash parameters ended");
                    }
                }
                catch (Exception ex)
                {
                    if (logger != null)
                    {
                        logger.LogError(ex, nameof(CalculateHashesInfo));
                    }
                    hi = null;
                }
                finally
                {
                    _hashesInfoStatic = hi;
                }
                return(hi);
            }
        }