public QueryResult QueryWithTimeSequenceInformation(IModelService modelService, IEnumerable<HashedFingerprint> hashedFingerprints, QueryConfiguration queryConfiguration)
        {
            var allCandidates = GetAllCandidates(modelService, hashedFingerprints, queryConfiguration);
            if (!allCandidates.Any())
            {
                return NoResult;
            }

            var entries = this.GetCandidatesSortedByLCS(allCandidates);

            var resultEntries = entries
                   .Take(queryConfiguration.MaximumNumberOfTracksToReturnAsResult)
                   .Select(datas => new ResultEntry
                    {
                        Track = modelService.ReadTrackByReference(datas.First().TrackReference),
                        Similarity = datas.Count(),
                        SequenceStart = datas.First().SequenceAt,
                        SequenceLength = datas.Last().SequenceAt - datas.First().SequenceAt + 1.48d // TODO 1.48 because of default fingerprint config. For other configurations there is going to be equal to Overlap * ImageLength / SampleRate 
                    })
                    .ToList();

            var returnresult = new QueryResult
                {
                    IsSuccessful = true,
                    ResultEntries = resultEntries,
                    AnalyzedCandidatesCount = allCandidates.Count
                };

            return returnresult;
        }
        private ConcurrentDictionary<IModelReference, ResultEntryAccumulator> GetSimilaritiesUsingNonBatchedStrategy(IEnumerable<HashedFingerprint> queryFingerprints, QueryConfiguration configuration, IModelService modelService)
        {
            var hammingSimilarities = new ConcurrentDictionary<IModelReference, ResultEntryAccumulator>();
            foreach (var queryFingerprint in queryFingerprints)
            {
                var subFingerprints = modelService.ReadSubFingerprints(queryFingerprint.HashBins, configuration);
                similarityUtility.AccumulateHammingSimilarity(subFingerprints, queryFingerprint, hammingSimilarities);
            }

            return hammingSimilarities;
        }
        private ConcurrentDictionary<IModelReference, ResultEntryAccumulator> GetSimilaritiesUsingBatchedStrategy(IEnumerable<HashedFingerprint> queryFingerprints, QueryConfiguration configuration, IModelService modelService)
        {
            var hashedFingerprints = queryFingerprints as List<HashedFingerprint> ?? queryFingerprints.ToList();
            var allCandidates = modelService.ReadSubFingerprints(hashedFingerprints.Select(querySubfingerprint => querySubfingerprint.HashBins), configuration);
            var hammingSimilarities = new ConcurrentDictionary<IModelReference, ResultEntryAccumulator>();
            foreach (var hashedFingerprint in hashedFingerprints)
            {
                HashedFingerprint queryFingerprint = hashedFingerprint;
                var subFingerprints = allCandidates.Where(candidate => queryMath.IsCandidatePassingThresholdVotes(queryFingerprint, candidate, configuration.ThresholdVotes));
                similarityUtility.AccumulateHammingSimilarity(subFingerprints, queryFingerprint, hammingSimilarities);
            }

            return hammingSimilarities;
        }
        public QueryResult Query(List<HashedFingerprint> queryFingerprints, QueryConfiguration configuration, IModelService modelService)
        {
            ConcurrentDictionary<IModelReference, ResultEntryAccumulator> hammingSimilarities;
            if (modelService.SupportsBatchedSubFingerprintQuery)
            {
                hammingSimilarities = GetSimilaritiesUsingBatchedStrategy(queryFingerprints, configuration, modelService);
            }
            else
            {
                hammingSimilarities = GetSimilaritiesUsingNonBatchedStrategy(queryFingerprints, configuration, modelService);
            }

            if (!hammingSimilarities.Any())
            {
                return QueryResult.EmptyResult();
            }

            var resultEntries = queryMath.GetBestCandidates(queryFingerprints, hammingSimilarities, configuration.MaxTracksToReturn, modelService, configuration.FingerprintConfiguration);
            return QueryResult.NonEmptyResult(resultEntries);
        }
        public QueryResult Query(IModelService modelService, IEnumerable<HashedFingerprint> hashedFingerprints, QueryConfiguration queryConfiguration)
        {
            var hammingSimilarities = new Dictionary<IModelReference, int>();
            foreach (var hashedFingerprint in hashedFingerprints)
            {
                var subFingerprints = GetSubFingerprints(modelService, hashedFingerprint, queryConfiguration);
                foreach (var subFingerprint in subFingerprints)
                {
                    int hammingSimilarity = similarityCalculationUtility.CalculateHammingSimilarity(hashedFingerprint.SubFingerprint, subFingerprint.Signature);
                    if (!hammingSimilarities.ContainsKey(subFingerprint.TrackReference))
                    {
                        hammingSimilarities.Add(subFingerprint.TrackReference, 0);
                    }

                    hammingSimilarities[subFingerprint.TrackReference] += hammingSimilarity;
                }
            }

            if (!hammingSimilarities.Any())
            {
                return NoResult;
            }

            var resultEntries = hammingSimilarities.OrderByDescending(e => e.Value)
                               .Take(queryConfiguration.MaximumNumberOfTracksToReturnAsResult)
                               .Select(e => new ResultEntry
                                   {
                                       Track = modelService.ReadTrackByReference(e.Key),
                                       Similarity = e.Value
                                   })
                                .ToList();

            return new QueryResult
                {
                    ResultEntries = resultEntries,
                    IsSuccessful = true,
                    AnalyzedCandidatesCount = hammingSimilarities.Count
                };
        }
 public virtual ISet<SubFingerprintData> ReadSubFingerprints(IEnumerable<long[]> hashes, QueryConfiguration config)
 {
     return subFingerprintDao.ReadSubFingerprints(hashes, config.ThresholdVotes, config.Clusters);
 }
 public virtual IList<SubFingerprintData> ReadSubFingerprints(long[] hashBins, QueryConfiguration config)
 {
     return subFingerprintDao.ReadSubFingerprints(hashBins, config.ThresholdVotes, config.Clusters).ToList();
 }
 public IUsingQueryServices WithConfigs(FingerprintConfiguration fingerprintConfiguration, QueryConfiguration configuration)
 {
     QueryConfiguration = configuration;
     FingerprintConfiguration = fingerprintConfiguration;
     return this;
 }
 public IUsingQueryServices WithQueryConfig(QueryConfiguration queryConfiguration)
 {
     QueryConfiguration = queryConfiguration;
     return this;
 }
        private IEnumerable<SubFingerprintData> GetSubFingerprints(IModelService modelService, HashedFingerprint hash, QueryConfiguration queryConfiguration)
        {
            if (!string.IsNullOrEmpty(queryConfiguration.TrackGroupId))
            {
                return modelService.ReadSubFingerprintDataByHashBucketsThresholdWithGroupId(hash.HashBins, queryConfiguration.ThresholdVotes, queryConfiguration.TrackGroupId);
            }

            return modelService.ReadSubFingerprintDataByHashBucketsWithThreshold(hash.HashBins, queryConfiguration.ThresholdVotes);
        }
        private Dictionary<IModelReference, ISet<SubFingerprintData>> GetAllCandidates(IModelService modelService, IEnumerable<HashedFingerprint> hashedFingerprints, QueryConfiguration queryConfiguration)
        {
            var allCandidates = new Dictionary<IModelReference, ISet<SubFingerprintData>>();
            foreach (var hashedFingerprint in hashedFingerprints)
            {
                var subFingerprints = GetSubFingerprints(modelService, hashedFingerprint, queryConfiguration); // TODO No need to extract full subfingerprint from the DB. We use only TrackReference and Sequence # to build the result
                foreach (var subFingerprint in subFingerprints)
                {
                    if (!allCandidates.ContainsKey(subFingerprint.TrackReference))
                    {
                        allCandidates.Add(
                            subFingerprint.TrackReference,
                            new SortedSet<SubFingerprintData>(new SubFingerprintSequenceComparer()));
                    }

                    allCandidates[subFingerprint.TrackReference].Add(subFingerprint);
                }
            }

            return allCandidates;
        }