public TorrentUpdater(string versionString, List<MetaAddon> addOns, bool fullSystemCheck, TorrentLauncher downloader,
			DayZUpdater updater, bool errorMsgsOnly)
        {
            addOnTorrents = new List<AddOnTorrent>();
            this.versionString = versionString;
            this.fullSystemCheck = fullSystemCheck;
            this.downloader = downloader;
            this.updater = updater;
            this.errorMsgsOnly = errorMsgsOnly;

            string torrentsDir = null;
            try
            {
                torrentsDir = Path.Combine(UserSettings.ContentMetaPath, versionString);
                {
                    var dirInfo = new DirectoryInfo(torrentsDir);
                    if (!dirInfo.Exists)
                        dirInfo = Directory.CreateDirectory(torrentsDir);
                }
            }
            catch (Exception ex)
            {
                updater.Status = "Error creating torrents directory";
                downloader.Status = ex.Message;
                downloader.IsRunning = false;

                return;
            }

            foreach (MetaAddon addOn in addOns)
            {
                var newAddOn = new AddOnTorrent();
                newAddOn.Meta = addOn;
                newAddOn.torrentFileName = Path.Combine(torrentsDir,
                    newAddOn.Meta.Description + "-" + newAddOn.Meta.Version + ".torrent");
                newAddOn.torrentSavePath = null; //will be filled in if successfull download
                addOnTorrents.Add(newAddOn);
            }

            //delete .torrent files that do not match the ones we want
            string[] allTorrents = Directory.GetFiles(torrentsDir, "*.torrent", SearchOption.TopDirectoryOnly);
            foreach (string torrentPath in allTorrents)
            {
                if (
                    addOnTorrents.Count(
                        naot => { return naot.torrentFileName.Equals(torrentPath, StringComparison.InvariantCultureIgnoreCase); }) < 1)
                {
                    //this is an unwanted torrent file
                    try
                    {
                        var fileInfo = new FileInfo(torrentPath);
                        if (fileInfo.IsReadOnly)
                        {
                            fileInfo.IsReadOnly = false;
                            fileInfo.Refresh();
                        }
                        fileInfo.Delete();
                    }
                    catch (Exception)
                    {
                    }
                }
            }

            for (int i = 0; i < addOnTorrents.Count; i++)
            {
                int idxCopy = i;
                AddOnTorrent newAddOn = addOnTorrents[i];
                try
                {
                    var wc = new HashWebClient();
                    wc.DownloadFileCompleted += (sender, args) => { TorrentDownloadComplete(sender, args, idxCopy); };
                    wc.BeginDownload(newAddOn.Meta.Torrent, newAddOn.torrentFileName);
                }
                catch (Exception ex)
                {
                    updater.Status = "Error starting torrent file download";
                    downloader.Status = ex.Message;
                    downloader.IsRunning = false;
                    return;
                }
            }
        }
		public static void DownloadWithStatusDots(RemoteFileInfo fileInfo, string destPath, string initialStatus,
			StatusChangeString statusCb, StatusDownloadComplete finishCb)
		{
			using (var downloadingEvt = new ManualResetEvent(false))
			{
				string updateInfoString = initialStatus.Replace("...", String.Empty);
				statusCb(updateInfoString);

				var wc = new HashWebClient();
				wc.DownloadFileCompleted += (source, evt) =>
				{
					if (evt.Cancelled)
						statusCb("Async operation cancelled");
					else if (evt.Error != null)
						statusCb(evt.Error.Message);
					else
					{
						try
						{
							if (finishCb != null)
								finishCb(wc, fileInfo, destPath);
						}
						catch (Exception ex)
						{
							statusCb(ex.Message);
						}
					}
					downloadingEvt.Set();
				};
				wc.BeginDownload(fileInfo, destPath);

				int numDots = 0;
				uint loops = 0;
				while (downloadingEvt.WaitOne(10) == false)
				{
					if (loops >= 10)
					{
						numDots = (numDots + 1)%3;
						statusCb(updateInfoString + new String('.', numDots));
						loops = 0;
					}

					loops++;
				}
				if (wc != null)
				{
					wc.Dispose();
					wc = null;
				}
			}
		}
        private void StartInstallerDownload(int arrIdx)
        {
            InstallersMeta.InstallerInfo inst = installers.ElementAt(arrIdx);

            LowerProgressText = "Downloading " + inst.Archive.Url;
            LowerProgressValue = 0;
            LowerProgressLimit = 100;

            var wc = new HashWebClient();
            wc.DownloadProgressChanged += (sender, args) => { LowerProgressValue = args.ProgressPercentage; };
            wc.DownloadFileCompleted += (sender, args) =>
            {
                if (HandlePossibleError("Error " + UpperProgressText, args))
                    return;

                LowerProgressLimit = 100;
                LowerProgressValue = 100;

                UpperProgressValue = UpperProgressValue + 1;
                if (UpperProgressValue == UpperProgressLimit) //downloaded all installers
                    VerifyAndInstallPackages();
                else
                    StartInstallerDownload(arrIdx + 1);
            };
            wc.BeginDownload(inst.Archive, inst.GetArchiveFileName());
        }
        protected void GetInstallersMeta()
        {
            Closeable = false;
            UpperProgressValue = 0;
            UpperProgressLimit = 1;

            LocatorInfo locator = CalculatedGameSettings.Current.Locator;
            if (locator == null)
            {
                UpperProgressText = "Please check for updates first.";
                UpperProgressLimit = 0;
                Closeable = true;
                return;
            }

            UpperProgressText = "Getting installer info...";
            string installersFileName = InstallersMeta.GetFileName();
            var wc = new HashWebClient();
            wc.DownloadProgressChanged += (sender, args) =>
            {
                UpperProgressLimit = 100;
                UpperProgressValue = args.ProgressPercentage;
            };
            wc.DownloadFileCompleted += (sender, args) =>
            {
                if (HandlePossibleError("Installer index download failed", args))
                    return;

                UpperProgressLimit = 100;
                UpperProgressValue = 100;

                UpperProgressText = "Parsing installer info...";
                InstallersMeta newInsts = null;
                try
                {
                    newInsts = InstallersMeta.LoadFromFile(installersFileName);
                }
                catch (Exception ex)
                {
                    HandleException("Error parsing installer info", ex);
                    return;
                }

                var wntInsts = new List<InstallersMeta.InstallerInfo>();
                try
                {
                    foreach (MetaAddon addon in addOns)
                    {
                        InstallersMeta.InstallerInfo instMatch =
                            wntInsts.FirstOrDefault(x => { return String.Equals(x.Version, addon.InstallerName); });
                        if (instMatch == null)
                            instMatch = newInsts.Installers.FirstOrDefault(x => { return String.Equals(x.Version, addon.InstallerName); });

                        if (instMatch == null)
                            throw new InstallerNotFound(addon.InstallerName);
                        wntInsts.Add(instMatch);
                    }
                }
                catch (Exception ex)
                {
                    HandleException("Error matching installers", ex);
                    return;
                }

                installers = wntInsts;
                DownloadInstallerPackages();
            };
            wc.BeginDownload(locator.Installers, installersFileName);
        }
        public void DownloadAndInstall(int revision, HashWebClient.RemoteFileInfo archiveInfo)
        {
            IsRunning = true;
            Status = "Getting file info...";

            string extractedFolderLocation = Path.Combine(UserSettings.PatchesPath, revision.ToString());
            string zipFileLocation = extractedFolderLocation + ".zip";

            var wc = new HashWebClient();
            wc.DownloadProgressChanged +=
                (sender, args) => { Status = string.Format("Downloading... {0}%", args.ProgressPercentage); };
            wc.DownloadFileCompleted += (sender, args) =>
            {
                if (args.Error != null)
                {
                    Status = "Error: " + args.Error.Message;
                    IsRunning = false;
                    return;
                }
                ExtractFile(zipFileLocation, extractedFolderLocation);
            };
            wc.BeginDownload(archiveInfo, zipFileLocation);
        }
        public void StartFromNetContent(string versionString, bool forceFullSystemsCheck,
			HashWebClient.RemoteFileInfo jsonIndex, DayZUpdater updater, bool errorMsgsOnly = false)
        {
            if (jsonIndex == null)
            {
                MessageBox.Show("No version index specified, please Check first.", "Error initiating torrent download",
                    MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

            if (string.IsNullOrWhiteSpace(versionString))
            {
                MessageBox.Show("Invalid version specified for download", "Error initiating torrent download", MessageBoxButton.OK,
                    MessageBoxImage.Error);
                return;
            }

            if (IsRunning)
            {
                if (_updatingVersion.Equals(versionString, StringComparison.OrdinalIgnoreCase))
                    return; //already running for this same version
            }

            _updatingVersion = versionString;
            if (!errorMsgsOnly)
                updater.Status = DayZeroLauncherUpdater.STATUS_DOWNLOADING;

            Status = "Initiating Download...";

            string metaJsonFilename = MetaModDetails.GetFileName(versionString);
            var wc = new HashWebClient();
            wc.DownloadFileCompleted += (sender, args) =>
            {
                if (args.Cancelled)
                {
                    Status = updater.Status = "Async operation cancelled";
                    IsRunning = false;
                    _gameLauncher.SetModDetails(null, true, null);
                }
                else if (args.Error != null)
                {
                    updater.Status = "Error downloading content index file";
                    Status = args.Error.Message;
                    IsRunning = false;
                    _gameLauncher.SetModDetails(null, false, args.Error);
                }
                else
                    ContinueFromContentFile(versionString, metaJsonFilename, forceFullSystemsCheck, updater, errorMsgsOnly);
            };
            wc.BeginDownload(jsonIndex, metaJsonFilename);
        }