/* * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using SafeExamBrowser.Contracts.Logging; namespace SafeExamBrowser.ResetUtility.Procedure { internal abstract class ProcedureStep { private CancellationTokenSource progressAnimationToken; private Task progressAnimation; protected ProcedureContext Context { get; } protected ILogger Logger => Context.Logger; protected ConsoleColor BackgroundColor => ConsoleColor.White; protected ConsoleColor ForegroundColor => ConsoleColor.Black; internal ProcedureStep(ProcedureContext context) { Context = context; } internal abstract ProcedureStepResult Execute(); internal abstract ProcedureStep GetNextStep(); protected void InitializeConsole() { var title = "SEB Reset Utility"; var height = Console.LargestWindowHeight > 40 ? 40 : Console.LargestWindowHeight; var width = Console.LargestWindowWidth > 160 ? 160 : Console.LargestWindowWidth; Console.SetBufferSize(width, height); Console.SetWindowSize(width, height); Console.BackgroundColor = BackgroundColor; Console.ForegroundColor = ForegroundColor; Console.Clear(); Console.BackgroundColor = ConsoleColor.Gray; Console.ForegroundColor = ConsoleColor.Black; Console.Write(new String(' ', Console.BufferWidth)); Console.Write(new String(' ', (int) Math.Floor((Console.BufferWidth - title.Length) / 2.0))); Console.Write(title); Console.Write(new String(' ', (int) Math.Ceiling((Console.BufferWidth - title.Length) / 2.0))); Console.Write(new String(' ', Console.BufferWidth)); Console.BackgroundColor = BackgroundColor; Console.ForegroundColor = ForegroundColor; Console.SetCursorPosition(0, 4); Console.CursorVisible = false; } protected void ClearLine(int top) { Console.SetCursorPosition(0, top); Console.WriteLine(new String(' ', Console.BufferWidth)); Console.SetCursorPosition(0, top); } protected string ReadLine() { Console.Write("> "); Console.CursorVisible = true; var input = Console.ReadLine(); Console.CursorVisible = false; return input; } protected void ShowError(string message) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(message); Console.ForegroundColor = ForegroundColor; Console.ReadKey(); } protected void ShowMenu(IList options, bool showInstructions = false) { var left = Console.CursorLeft; var top = Console.CursorTop; PrintMenu(options, left, top, showInstructions); for (var key = Console.ReadKey(true).Key; key != ConsoleKey.Enter; key = Console.ReadKey(true).Key) { if (key == ConsoleKey.UpArrow || key == ConsoleKey.DownArrow) { SelectNextOption(key, options); PrintMenu(options, left, top, showInstructions); } } } protected void ShowProgress(int current, int total) { var scale = Console.BufferWidth - 8.0; var progress = Math.Floor(current * scale / total); var remaining = Math.Ceiling((total - current) * scale / total); Console.SetCursorPosition(0, Console.CursorTop); Console.Write($"[{new String('■', (int) progress)}{new String('─', (int) remaining)}] {current * 100 / total}%"); } protected void StartProgressAnimation() { progressAnimationToken = new CancellationTokenSource(); progressAnimation = Task.Run(new Action(ProgressAnimation)); } protected void StopProgressAnimation() { progressAnimationToken?.Cancel(); progressAnimation?.Wait(); } private void PrintMenu(IList options, int left, int top, bool showInstructions) { Console.SetCursorPosition(left, top); if (showInstructions) { Console.WriteLine("Please choose one of the following options:"); Console.WriteLine(); } foreach (var option in options) { Console.WriteLine(option.ToString()); } if (showInstructions) { Console.WriteLine(); Console.WriteLine("Use the up/down arrow keys and enter to navigate the menu."); } } private void ProgressAnimation() { var length = 12; var max = Console.BufferWidth - 8; var min = 1; var left = 1; var operand = 1; Console.Write($"[{new String('■', length)}{new String('─', max - length)}]"); while (!progressAnimationToken.IsCancellationRequested) { Console.SetCursorPosition(left, Console.CursorTop); Console.Write(new String('─', length)); if (left + length > max) { operand = -1; } else if (left <= min) { operand = 1; } left += operand; Console.SetCursorPosition(left, Console.CursorTop); Console.Write(new String('■', length)); Thread.Sleep(20); } Console.SetCursorPosition(0, Console.CursorTop); Console.WriteLine(new String(' ', Console.BufferWidth)); Console.SetCursorPosition(0, Console.CursorTop - 2); } private void SelectNextOption(ConsoleKey key, IList options) { var current = options.First(o => o.IsSelected); var currentIndex = options.IndexOf(current); var nextIndex = default(int); if (key == ConsoleKey.UpArrow) { nextIndex = --currentIndex < 0 ? options.Count - 1 : currentIndex; } if (key == ConsoleKey.DownArrow) { nextIndex = ++currentIndex == options.Count ? 0 : currentIndex; } var next = options.ElementAt(nextIndex); current.IsSelected = false; next.IsSelected = true; } } }