public async Task InitializeInterface()
        {
            // Delete registry key left-over
            var startWithWindows = GetRegistryKeyValue(Constants.RunRegistryKey, Constants.AppName);

            if (startWithWindows != null && !WtmSettings.StartWithWindows)
            {
                DeleteRegistryKeyValue(Constants.RunRegistryKey, Constants.AppName);
            }

            ApplyServerSettingsCommand(null); // Start server if app's role is 'Server'

            NetHelper.Port        = WtmSettings.TcpPort;
            AccessPoinServiceHost = new ServiceHost(typeof(Service));
            AccessPoinServiceHost.Open();

            string failedToDecrypt = "The encryption is based on machine configuration. "
                                     + "If you have copied settings to a different machine, logged on as a different user or changed your Windows password you need to re-enter ";

            ScanLanCancelSource = new System.Threading.CancellationTokenSource();
            var token = ScanLanCancelSource.Token;

            Func <Task> taskLoadWtmCoins = (async() =>
            {
                //Load Whattomine available coins
                if (WtmSettings.ProxyPasswordEncrypted != null && WtmSettings.ProxyPasswordEncrypted != string.Empty)
                {
                    try
                    {
                        BypassUndo(() => WtmSettings.ProxyPassword = WtmSettings.ProxyPasswordEncrypted.DecryptSecure());
                    }
                    catch (Exception)
                    {
                        WtmSettings.ProxyPasswordEncrypted = null;
                        string msg = "Failed to decrypt WhatToMine proxy password. " + failedToDecrypt + "the proxy password.";
                        var t = Task.Run(() => MessageBox.Show(msg, "Error", MessageBoxButton.OK, MessageBoxImage.Error));
                    }
                }
                await LoadWtmCoins(token);

                // Update coins statuses
                if (WtmCoins != null)
                {
                    UpdateCoinStatus();
                }
                IsInitializingWtm = false;
            });

            Func <Task> taskLoadYahooCurrencies = (async() =>
            {
                //Load Yahoo currencies
                SaveUndoIsEnabled = false;
                await WtmSettings.GetYahooRates();
                SaveUndoIsEnabled = true;
            });

            var tasks = new List <Task>()
            {
                taskLoadWtmCoins()
            };

            if (WtmSettings.UseYahooRates)
            {
                tasks.Add(taskLoadYahooCurrencies());
            }
            try
            {
                await Task.WhenAll(tasks).WithCancellation(token);
            }
            catch (Exception ex)
            {
                Task <MessageBoxResult> t = null;
                if (ex.Message != "The operation was canceled.")
                {
                    t = Task.Run(() => MessageBox.Show("Error while waiting for taskLoadWtmCoins or taskLoadYahooCurrencies.\n" + ex.Message, "", MessageBoxButton.OK, MessageBoxImage.Error));
                }
            }
            finally
            {
                IsInitializingWtm = false;
            }

            // Update callback
            using (RegistryKey key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(Constants.BaseRegistryKey, true))
            {
                if (key != null)
                {
                    var callerHostName = key.GetValue("CallerHostName") as string;
                    if (callerHostName != null && callerHostName != string.Empty)
                    {
                        var address = BuildServerAddress(callerHostName, Constants.AccessPoint);
                        var channel = Service.NewChannel(address, TimeSpan.FromSeconds(60));
                        try
                        {
                            await channel.UpdateApplicationCallback(Environment.MachineName, Helpers.ApplicationVersion());
                        }
                        catch { }
                        finally
                        {
                            NetHelper.CloseChannel(channel);
                        }
                        key.DeleteValue("CallerHostName");
                    }
                }
            }

            bool workersExist  = File.Exists(Constants.WorkersFile);
            bool settingsExist = File.Exists(Constants.WtmSettingsFile);

            if (!workersExist && !settingsExist)
            {
                var t = Task.Run(() =>
                                 MessageBox.Show($"If you're running a fresh copy of {Constants.AppName} please define your workers inside 'Workers' tab and click 'Save' icon.", "Default configuration used", MessageBoxButton.OK, MessageBoxImage.Information));
            }

            else
            {
                if (DefaultWorkers)
                {
                    var t = Task.Run(() =>
                                     MessageBox.Show($"{Constants.WorkersFile} is missing or corrupt.", "", MessageBoxButton.OK, MessageBoxImage.Warning));
                }
                if (DefaultWtmSettings)
                {
                    var t = Task.Run(() =>
                                     MessageBox.Show($"{Constants.WtmSettingsFile} is missing or corrupt. Default settings are used.", "", MessageBoxButton.OK, MessageBoxImage.Warning));
                }
            }

            // Check if there are any pending jobs in registry
            bool   switchJobIsInProgress      = false;
            bool   updatePriceJobIsInProgress = false;
            string switchTime            = string.Empty;
            string switchLastTime        = string.Empty;
            string updatePriceTime       = string.Empty;
            string updatePriceLastUpdate = string.Empty;

            using (RegistryKey switchKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(Constants.SwitchRegistryKey, true))
                using (RegistryKey updatePriceKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(Constants.UpdatePriceHistoryRegistryKey, true))
                {
                    if ((string)switchKey.GetValue("IsInProgress") == "True")
                    {
                        switchJobIsInProgress = true;
                    }
                    switchTime = (string)switchKey.GetValue("Schedule");
                    if (switchTime != null && switchTime != string.Empty)
                    {
                        SwitchSchedule = Convert.ToDateTime(switchTime, DateTimeFormatInfo.InvariantInfo).ToLocalTime();
                    }
                    switchLastTime = (string)switchKey.GetValue("LastUpdate");
                    if (switchLastTime != null && switchLastTime != string.Empty)
                    {
                        SwitchLastTime = Convert.ToDateTime(switchLastTime, DateTimeFormatInfo.InvariantInfo).ToLocalTime();
                    }

                    if ((string)updatePriceKey.GetValue("IsInProgress") == "True")
                    {
                        updatePriceJobIsInProgress = true;
                    }
                    updatePriceTime = (string)updatePriceKey.GetValue("Schedule");
                    if (updatePriceTime != null && updatePriceTime != string.Empty)
                    {
                        HistoricalPricesSchedule = Convert.ToDateTime(updatePriceTime, DateTimeFormatInfo.InvariantInfo).ToLocalTime();
                    }
                    updatePriceLastUpdate = (string)updatePriceKey.GetValue("LastUpdate");
                    if (updatePriceLastUpdate != null && updatePriceLastUpdate != string.Empty)
                    {
                        HistoricalPricesLastTime = Convert.ToDateTime(updatePriceLastUpdate, DateTimeFormatInfo.InvariantInfo).ToLocalTime();
                    }
                }

            // Start job if one is still pending after system restart
            if (switchJobIsInProgress && workersExist)
            {
                await SwitchTaskWrapper();

                switchTime = string.Empty;
            }
            if (updatePriceJobIsInProgress && workersExist)
            {
                await UpdatePriceHistoryTaskWrapper();

                updatePriceTime = string.Empty;
            }

            // Delete Mass Update left-overs if they exist
            Helpers.DeleteUpdateLeftOvers();

            // Check if Switch job has been missed today/this hour
            if (WtmSettings.AutoSwitch)
            {
                if (switchTime != string.Empty)
                {
                    DateTime schedule   = Convert.ToDateTime(switchTime, DateTimeFormatInfo.InvariantInfo);
                    DateTime now        = DateTime.Now;
                    DateTime expiryTime = GetSwitchExpiry(schedule);
                    if (schedule < now && now < expiryTime)
                    {
                        await SwitchTaskWrapper();

                        switchTime = string.Empty;
                    }
                }
            }

            // Check if UpdateHistoricalPrices job has been missed today
            DateTime updatePriceLastUpdateTime;

            if (WtmSettings.BackupHistoricalPrices)
            {
                if (updatePriceLastUpdate != string.Empty)
                {
                    updatePriceLastUpdateTime = Convert.ToDateTime(updatePriceLastUpdate, DateTimeFormatInfo.InvariantInfo);
                    DateTime now = DateTime.Now;
                    DateTime historyBackupTime = new DateTime(now.Year, now.Month, now.Day, WtmSettings.HistoryTimeTo.Hour, WtmSettings.HistoryTimeTo.Minute, 0, DateTimeKind.Local);
                    if (now > historyBackupTime && updatePriceLastUpdateTime.Day < now.Day) // Now is past daily schedule and last update had been done before today
                    {
                        await UpdatePriceHistoryTaskWrapper();

                        updatePriceTime = string.Empty;
                    }
                }
            }

            // Schedule jobs
            JobManager.UseUtcTime();
            if (WtmSettings.AutoSwitch == true && workersExist)
            {
                Debug.WriteLine(DateTime.Now + " Scheduling a Switch task at startup.");
                if (switchTime != string.Empty)
                {
                    ResetScheduledJob(JobType.Switch, switchTime);
                }
                else
                {
                    ResetScheduledJob(JobType.Switch);
                }
            }
            if (WtmSettings.BackupHistoricalPrices == true && workersExist)
            {
                if (updatePriceTime != string.Empty)
                {
                    ResetScheduledJob(JobType.UpdatePriceHistory, updatePriceTime);
                }
                else
                {
                    ResetScheduledJob(JobType.UpdatePriceHistory);
                }
            }
            UpdateNextJobStatus();
        }
        private async void StartCommand(object obj)
        {
            SwitchIsInProgress = true;

            ManualSwitchCancelSource = new CancellationTokenSource();
            var          token      = ManualSwitchCancelSource.Token;
            var          taskList   = new List <Task>();
            var          jobCount   = ProfitTables.Sum(x => x.Computers.Count);
            var          failList   = new List <ProfitTable>();
            FlowDocument report     = new FlowDocument();
            int          errorCount = 0;

            await Task.Run(() =>
            {
                ReportTitle = $"Progress: 0 of {jobCount}.";
                int i       = 1;

                foreach (var table in ProfitTables)
                {
                    var currentCoinRow = table.ProfitList[0];

                    foreach (var pc in table.Computers)
                    {
                        pc.RestartStatus = pc.Restart ? Computer.OperationStatus.OperationInProgress : Computer.OperationStatus.Indeterminate;
                        pc.SwitchStatus  = pc.Switch ? Computer.OperationStatus.OperationInProgress : Computer.OperationStatus.Indeterminate;

                        Func <Task> function = (async() =>
                        {
                            var serverAddress = "net.tcp://" + pc.Name + ":" + NetHelper.Port + Constants.AccessPoint;
                            var channel = Service.NewChannel(serverAddress, TimeSpan.FromSeconds(10));

                            try
                            {
                                try
                                {
                                    if (pc.Switch)
                                    {
                                        bool switchResult = await channel.SetCurrentCoinAsync(
                                            currentCoinRow.Name,
                                            currentCoinRow.Symbol,
                                            currentCoinRow.Algorithm,
                                            currentCoinRow.Path,
                                            currentCoinRow.Arguments).WithCancellation(token);
                                        if (switchResult)
                                        {
                                            pc.SwitchStatus = Computer.OperationStatus.Success;
                                        }
                                        else
                                        {
                                            pc.SwitchStatus = Computer.OperationStatus.Failure;
                                        }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    errorCount++;
                                    pc.SwitchStatus = Computer.OperationStatus.Failure;
                                    Application.Current.Dispatcher.Invoke(() =>
                                    {
                                        var p = new Paragraph();
                                        p.Inlines.Add(new Run($"{table.Name}:").FontWeight(FontWeights.Bold).Color(Colors.Salmon));
                                        p.Inlines.Add(new Run($"{pc.Name} Failed to switch to {currentCoinRow.NameAndSymbol}.\r\n"));
                                        p.Inlines.Add(new Run(ex.Message + "\r\n"));
                                        NewParagraph = p;
                                    });
                                    if (pc.Restart)
                                    {
                                        pc.RestartStatus = Computer.OperationStatus.Failure;
                                    }
                                    else
                                    {
                                        pc.RestartStatus = Computer.OperationStatus.NotPossible;
                                    }
                                    return;
                                }
                                try
                                {
                                    if (pc.Restart)
                                    {
                                        // Schedule delayed restart if pc is localhost
                                        if (string.Equals(pc.Name, Environment.MachineName, StringComparison.CurrentCultureIgnoreCase))
                                        {
                                            RestartPending = true;
                                            pc.RestartStatus = Computer.OperationStatus.Pending;
                                        }
                                        else
                                        {
                                            bool restartResult = await channel.RestartComputerAsync(5).WithCancellation(token);
                                            if (restartResult)
                                            {
                                                pc.RestartStatus = Computer.OperationStatus.Success;
                                            }
                                            else
                                            {
                                                pc.RestartStatus = Computer.OperationStatus.Failure;
                                            }
                                        }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    errorCount++;
                                    pc.RestartStatus = Computer.OperationStatus.Failure;
                                    Application.Current.Dispatcher.Invoke(() =>
                                    {
                                        var p = new Paragraph();
                                        p.Inlines.Add(new Run($"{table.Name}:").FontWeight(FontWeights.Bold).Color(Colors.Salmon));
                                        p.Inlines.Add(new Run($"{pc.Name} Failed to restart.\r\n"));
                                        p.Inlines.Add(new Run(ex.Message + "\r\n"));
                                        NewParagraph = p;
                                    });
                                }
                            }
                            finally
                            {
                                NetHelper.CloseChannel(channel);
                                ReportTitle = $"Progress: {i} of {jobCount}.";
                                i++;
                            }
                        });
                        // This line blocks UI upon DNS lookup of a non-existing or disconnected machine.
                        // That is why the entire block is wrapped into Task.Run().
                        Task task = function();
                        taskList.Add(task);
                    }
                }
            });

            await Task.WhenAll(taskList);

            if (errorCount == 0)
            {
                ReportTitle  = "Report:";
                NewParagraph = new Paragraph(new Run("Operation has finished successfully."));
            }
            else
            {
                ReportTitle = "Error report:";
            }

            SwitchIsInProgress = false;
            SwitchIsFinished   = true;
        }