using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Windows.Forms; using CarManagerV3.Classes; using CarManagerV3.Manager; namespace CarManagerV3 { /// /// Handles safe reading and writing of car data to files. /// internal class SafeManager { /// /// The path of the txt file that contains recently opened file paths. /// private static string recentPathsFile = Properties.Settings.Default.DataLocation + "\\recent_paths.txt"; /// /// Initializes a file at a specified path if it does not already exist. /// /// The path of the file. public static void InitializeFile(string path) { try { if (!File.Exists(@path)) { using (StreamWriter writer = new StreamWriter(@path)) { // Create the file, empty //writer.WriteLine(); writer.Close(); } } } catch (Exception ex) { Console.Error.WriteLine($"Error initializing file: {ex.Message}"); } } /// /// Initializes a file and its parent folders at a specified path if they do not already exist. /// /// The path of the file. public static void initializeFileAndFolders(string path, bool folderOnly = false) { try { string directory = Path.GetDirectoryName(path); Console.WriteLine($"Initializing file and folders for path: {path}"); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } if (!folderOnly) InitializeFile(path); } catch (Exception ex) { Console.Error.WriteLine($"Error initializing file and folders: {ex.Message}"); } } /// /// Ensures the directory exists. /// /// The path. public static void EnsureDirectoryExists(string path) { try { string directory = Path.GetDirectoryName(path); if (directory != null && !Directory.Exists(directory)) { Directory.CreateDirectory(directory); } } catch (Exception ex) { Console.Error.WriteLine($"Error ensuring directory exists: {ex.Message}"); } } /// /// Reads cars from a specified file path. /// /// The path. /// /// A containing the cars read from the file. /// public static List ReadCars(string path) { List cars = new List(); List failedLines = new List(); FileMeta meta = null; bool isLegacy = false; try { using (StreamReader reader = new StreamReader(@path)) { string line; while ((line = reader.ReadLine()) != null) { if (FileMeta.IsFileMeta(line)) { meta = FileMeta.FromCSV(line); if (meta != null) { if (FileMeta.NeedsUpdate(meta)) { if (!StateManager.askForMigration(meta)) { MessageBox.Show($"The file you are trying to open is from an older version that is no longer supported. Please select a different file.\nRunning:{Updater.GetCurrentVersion()}, File:{meta.Version}", "Unsupported Version", MessageBoxButtons.OK, MessageBoxIcon.Error); throw new LegacyException(); //Environment.Exit(0); } else { isLegacy = true; } } } continue; } // Process the line if (line == "") continue; if (Car.isLegacyCsvString(line)) { if (!StateManager.askForMigration()) { MessageBox.Show("The file you are trying to open is in an old format that is no longer supported. Please select a different file.", "Unsupported Format", MessageBoxButtons.OK, MessageBoxIcon.Error); throw new LegacyException(); //Environment.Exit(0); } else { isLegacy = true; line = FileUpdate.PerformOldLegacyUpdate(line); } } if (isLegacy && meta != null) line = FileUpdate.ApplyUpdates(line, meta.Version); Car tmp = Car.FromCsvString(line); if (tmp == null) { failedLines.Add(line); continue; } cars.Add(tmp); } reader.Close(); } } catch (LegacyException ex) { throw ex; } catch (Exception ex) { Console.Error.WriteLine($"Error reading cars from file: {ex.Message}"); } if (failedLines.Count > 0) { Console.Error.WriteLine($"Warning: {failedLines.Count} lines could not be parsed and were skipped."); foreach (string failedLine in failedLines) { Console.Error.WriteLine($"Failed line: {failedLine}"); } MessageBox.Show($"Warning: {failedLines.Count} lines in the file could not be parsed and were skipped. Check the console for details.", "Parsing Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); } cars = StateManager.normalizeOrders(cars); cars = cars.OrderBy(c => c.Order).ToList(); if (isLegacy) { SafeManager.SaveCars(path, cars); } return cars; } /// /// Saves the cars to a specified file path. /// /// The path. /// A containing all cars to save. public static void SaveCars(string path, List cars) { try { using (StreamWriter writer = new StreamWriter(@path)) { FileMeta meta = FileMeta.Generate(); writer.WriteLine(meta.ToCSV()); foreach (Car car in cars) { writer.WriteLine(car.ToCsvString()); } writer.Close(); } } catch (Exception ex) { Console.Error.WriteLine($"Error saving cars to file: {ex.Message}"); MessageBox.Show($"Error saving cars to file: {ex.Message}", "Save Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } /// /// Adds a file path to the recent paths list. /// If a path is already in the list, it is moved to the top. /// Otherwise, it is added to the top. /// Keeps only the 5 most recent paths. /// /// The path. public static void AddRecentPath(string path) { List paths = new List(); try { paths = GetRecentPaths(); paths.Remove(path); paths.Insert(0, path); if (paths.Count > 5) { paths = paths.Take(5).ToList(); } using (StreamWriter writer = new StreamWriter(recentPathsFile)) { foreach (string p in paths) { writer.WriteLine(p); } writer.Close(); } } catch (Exception ex) { Console.Error.WriteLine($"Error managing recent paths: {ex.Message}"); } } /// /// Gets the recently opened file paths. /// /// /// A containing the recent file paths. /// public static List GetRecentPaths() { List paths = new List(); try { recentPathsFile = Properties.Settings.Default.DataLocation + "\\recent_paths.txt"; initializeFileAndFolders(recentPathsFile); if (File.Exists(recentPathsFile)) //TODO: Remove { using (StreamReader reader = new StreamReader(recentPathsFile)) { string line; while ((line = reader.ReadLine()) != null) { paths.Add(line); } reader.Close(); } } } catch (Exception ex) { Console.Error.WriteLine($"Error reading recent paths: {ex.Message}"); } return paths; } /// /// Gets the folder of the most recently opened file. /// /// /// The folder path of the most recently opened file, or the users documents folder if no recent files. /// public static string getRecentFolder() { List recentPaths = GetRecentPaths(); if (recentPaths.Count > 0) { string recentFile = recentPaths[0]; if (File.Exists(recentFile)) { return Path.GetDirectoryName(recentFile); } } return Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); } /// /// Clears the recently opened file paths list by deleting the recent paths file. /// public static void ClearRecentPaths() { try { if (File.Exists(recentPathsFile)) { File.Delete(recentPathsFile); } } catch (Exception ex) { Console.Error.WriteLine($"Error clearing recent paths: {ex.Message}"); } } public static FileMeta GetFileMeta(string path) { try { using (StreamReader reader = new StreamReader(@path)) { string line; while ((line = reader.ReadLine()) != null) { if (FileMeta.IsFileMeta(line)) { reader.Close(); return FileMeta.FromCSV(line); } } reader.Close(); } } catch (Exception ex) { Console.Error.WriteLine($"Error getting file meta: {ex.Message}"); } return null; } } }