/// <summary>
        /// Downloads the provided manifest entry.
        /// This function resumes incomplete files, verifies downloaded files and
        /// downloads missing files.
        /// </summary>
        /// <param name="Entry">The entry to download.</param>
        /// <param name="Module">The module to download the file for. Determines download location.</param>
        private void DownloadEntry(ManifestEntry Entry, EModule Module)
        {
            ModuleDownloadProgressArgs.Module = Module;

            string baseRemotePath;
            string baseLocalPath;

            if (Module == EModule.Game)
            {
                baseRemotePath = Config.GetGameURL();
                baseLocalPath  = Config.GetGamePath();
            }
            else
            {
                baseRemotePath = Config.GetLauncherBinariesURL();
                baseLocalPath  = ConfigHandler.GetTempLauncherDownloadPath();
            }

            string RemotePath = String.Format("{0}{1}",
                                              baseRemotePath,
                                              Entry.RelativePath);

            string LocalPath = String.Format("{0}{1}{2}",
                                             baseLocalPath,
                                             Path.DirectorySeparatorChar,
                                             Entry.RelativePath);

            // Make sure we have a directory to put the file in
            Directory.CreateDirectory(Path.GetDirectoryName(LocalPath));

            // Reset the cookie
            File.WriteAllText(ConfigHandler.GetInstallCookiePath(), String.Empty);

            // Write the current file progress to the install cookie
            using (TextWriter textWriterProgress = new StreamWriter(ConfigHandler.GetInstallCookiePath()))
            {
                textWriterProgress.WriteLine(Entry);
                textWriterProgress.Flush();
            }

            if (File.Exists(LocalPath))
            {
                FileInfo fileInfo = new FileInfo(LocalPath);
                if (fileInfo.Length != Entry.Size)
                {
                    // If the file is partial, resume the download.
                    if (fileInfo.Length < Entry.Size)
                    {
                        DownloadRemoteFile(RemotePath, LocalPath, fileInfo.Length);
                    }
                    else
                    {
                        // If it's larger than expected, toss it in the bin and try again.
                        File.Delete(LocalPath);
                        DownloadRemoteFile(RemotePath, LocalPath);
                    }
                }
                else
                {
                    string LocalHash;
                    using (FileStream fs = File.OpenRead(LocalPath))
                    {
                        LocalHash = MD5Handler.GetStreamHash(fs);
                    }

                    if (LocalHash != Entry.Hash)
                    {
                        File.Delete(LocalPath);
                        DownloadRemoteFile(RemotePath, LocalPath);
                    }
                }
            }
            else
            {
                //no file, download it
                DownloadRemoteFile(RemotePath, LocalPath);
            }

            if (ChecksHandler.IsRunningOnUnix())
            {
                //if we're dealing with a file that should be executable,
                string gameName = Config.GetGameName();
                bool   bFileIsGameExecutable = (Path.GetFileName(LocalPath).EndsWith(".exe")) || (Path.GetFileName(LocalPath) == gameName);
                if (bFileIsGameExecutable)
                {
                    //set the execute bits
                    UnixHandler.MakeExecutable(LocalPath);
                }
            }

            // We've finished the download, so empty the cookie
            File.WriteAllText(ConfigHandler.GetInstallCookiePath(), String.Empty);
        }
        protected virtual void DownloadManifestEntry(ManifestEntry Entry, EModule Module)
        {
            ModuleDownloadProgressArgs.Module = Module;

            string baseRemoteURL;
            string baseLocalPath;

            switch (Module)
            {
            case EModule.Launcher:
            {
                baseRemoteURL = Config.GetLauncherBinariesURL();
                baseLocalPath = ConfigHandler.GetTempLauncherDownloadPath();
                break;
            }

            case EModule.Game:
            {
                baseRemoteURL = Config.GetGameURL();
                baseLocalPath = Config.GetGamePath();
                break;
            }

            default:
            {
                throw new ArgumentOutOfRangeException(nameof(Module), Module, "The module passed to DownloadManifestEntry was invalid.");
            }
            }

            // Build the access strings
            string remoteURL = $"{baseRemoteURL}{Entry.RelativePath}";
            string localPath = $"{baseLocalPath}{Path.DirectorySeparatorChar}{Entry.RelativePath}";

            // Make sure we have a directory to put the file in
            if (Path.GetDirectoryName(localPath) != null)
            {
                Directory.CreateDirectory(Path.GetDirectoryName(localPath));
            }
            else
            {
                throw new ArgumentNullException(nameof(localPath), "The local path was null.");
            }

            // Reset the cookie
            File.WriteAllText(ConfigHandler.GetInstallCookiePath(), string.Empty);

            // Write the current file progress to the install cookie
            using (TextWriter textWriterProgress = new StreamWriter(ConfigHandler.GetInstallCookiePath()))
            {
                textWriterProgress.WriteLine(Entry);
                textWriterProgress.Flush();
            }

            if (File.Exists(localPath))
            {
                FileInfo fileInfo = new FileInfo(localPath);
                if (fileInfo.Length != Entry.Size)
                {
                    // If the file is partial, resume the download.
                    if (fileInfo.Length < Entry.Size)
                    {
                        Log.Info($"Resuming interrupted file \"{Path.GetFileNameWithoutExtension(Entry.RelativePath)}\" at byte {fileInfo.Length}.");
                        DownloadRemoteFile(remoteURL, localPath, Entry.Size, fileInfo.Length);
                    }
                    else
                    {
                        // If it's larger than expected, toss it in the bin and try again.
                        Log.Info($"Restarting interrupted file \"{Path.GetFileNameWithoutExtension(Entry.RelativePath)}\": File bigger than expected.");

                        File.Delete(localPath);
                        DownloadRemoteFile(remoteURL, localPath, Entry.Size);
                    }
                }
                else
                {
                    string localHash;
                    using (FileStream fs = File.OpenRead(localPath))
                    {
                        localHash = MD5Handler.GetStreamHash(fs);
                    }

                    if (localHash != Entry.Hash)
                    {
                        // If the hash doesn't match, toss it in the bin and try again.
                        Log.Info($"Redownloading file \"{Path.GetFileNameWithoutExtension(Entry.RelativePath)}\": " +
                                 $"Hash sum mismatch. Local: {localHash}, Expected: {Entry.Hash}");

                        File.Delete(localPath);
                        DownloadRemoteFile(remoteURL, localPath, Entry.Size);
                    }
                }
            }
            else
            {
                // No file, download it
                DownloadRemoteFile(remoteURL, localPath, Entry.Size);
            }

            if (ChecksHandler.IsRunningOnUnix())
            {
                // If we're dealing with a file that should be executable,
                string gameName = Config.GetGameName();
                bool   bFileIsGameExecutable = (Path.GetFileName(localPath).EndsWith(".exe")) || (Path.GetFileName(localPath) == gameName);
                if (bFileIsGameExecutable)
                {
                    // Set the execute bits
                    UnixHandler.MakeExecutable(localPath);
                }
            }

            // We've finished the download, so empty the cookie
            File.WriteAllText(ConfigHandler.GetInstallCookiePath(), string.Empty);
        }