public async Task <IEnumerable <Tuple <Identifier, Version, string> > > DoFetch(Identifier id, VersionRange range, LogHandler logCallback, ProgressHandler progressCallback)
        {
            // TODO: Throw exception on circular reference

            var resolveQueue       = new Queue <Tuple <Identifier, VersionRange, string> >();
            var revInstallSequence = new List <Tuple <Identifier, Version, string> >();

            resolveQueue.Enqueue(new Tuple <Identifier, VersionRange, string>(id, range, ""));
            while (resolveQueue.Count > 0)
            {
                var elem = resolveQueue.Dequeue();
                RemotePackageInfo remotePack = null;
                if (!elem.Item1.HasGuid || !elem.Item1.HasName)
                {
                    // Get the full identifier first, so that installed package can be queried better
                    logCallback(LogLevel.Info, Translation.Translate("bpmcore_context_downloadmetadata", elem.Item1));
                    remotePack = await CachedQueryRemotePackage(elem.Item1);

                    if (remotePack == null)
                    {
                        if (string.IsNullOrEmpty(elem.Item3))
                        {
                            throw new PackageNotFoundException(this, elem.Item1);
                        }
                        else
                        {
                            throw new DependencyException(this, elem.Item1.ToString(), elem.Item3, new PackageNotFoundException(this, elem.Item1));
                        }
                    }
                    else
                    {
                        var newIdentifier = elem.Item1;
                        if (!newIdentifier.HasGuid && remotePack.ID.HasGuid)
                        {
                            newIdentifier.Guid    = remotePack.ID.Guid;
                            newIdentifier.HasGuid = true;
                        }
                        if (!newIdentifier.HasName && remotePack.ID.HasName)
                        {
                            newIdentifier.Name    = remotePack.ID.Name;
                            newIdentifier.HasName = true;
                        }
                        elem = new Tuple <Identifier, VersionRange, string>(newIdentifier, elem.Item2, elem.Item3);
                    }
                }
                var installedPackInfo = LocalRegistry.QueryInstalledPackage(this, elem.Item1);

                // Skip if the dependency is already installed and the version satisfies the requirement
                if (installedPackInfo != null && elem.Item2.ContainsVersion(installedPackInfo.Version))
                {
                    logCallback(LogLevel.Debug, Translation.Translate("bpmcore_context_alreadyinstalled", elem.Item1.ToString(), installedPackInfo.Version));
                    continue;
                }

                // Get the remote metadata
                if (remotePack == null)
                {
                    logCallback(LogLevel.Info, Translation.Translate("bpmcore_context_downloadmetadata", elem.Item1));
                    remotePack = await CachedQueryRemotePackage(elem.Item1);

                    if (remotePack == null)
                    {
                        if (string.IsNullOrEmpty(elem.Item3))
                        {
                            throw new PackageNotFoundException(this, elem.Item1);
                        }
                        else
                        {
                            throw new DependencyException(this, elem.Item1.ToString(), elem.Item3, new PackageNotFoundException(this, elem.Item1));
                        }
                    }
                }
                // Check other dependncies for a highest suitable version
                var installable = DependencyHelper.GetSuitableVersion(this, remotePack, elem.Item3, elem.Item2);
                logCallback(LogLevel.Info, Translation.Translate("bpmcore_context_willinstall", elem.Item1, installable.Item1));
                if (installable.Item1 < remotePack.AvailableVersions.Keys.Last())
                {
                    logCallback(LogLevel.Warning, Translation.Translate("bpmcore_context_cannotlatest",
                                                                        remotePack.AvailableVersions.Keys.Last(), remotePack.ID));
                }

                // Download the file from internet
                logCallback(LogLevel.Info, Translation.Translate("bpmcore_context_downloading", installable.Item2));
                var tempFile = await DownloadManager.AcquirePackage(this, elem.Item1, installable.Item1, installable.Item2, progressCallback);

                // Push further dependencies into the queue
                var packInfo = LocalRegistry.QueryExternalPackage(this, tempFile);
                logCallback(LogLevel.Debug, Translation.Translate("bpmcore_context_requires", packInfo.ID, string.Join(",", packInfo.Dependencies.Select(t => t.Key.ToString() + t.Value))));
                foreach (var dependency in packInfo.Dependencies)
                {
                    resolveQueue.Enqueue(new Tuple <Identifier, VersionRange, string>(dependency.Key, dependency.Value, packInfo.PlainName));
                }

                if (revInstallSequence.Any(t => t.Item3 == tempFile))
                {
                    revInstallSequence.Remove(revInstallSequence.Single(t => t.Item3 == tempFile));
                }
                revInstallSequence.Add(new Tuple <Identifier, Version, string>(remotePack.ID, installable.Item1, tempFile));
            }
            revInstallSequence.Reverse();
            return(revInstallSequence);
        }