using System; using System.Diagnostics; using System.IO; using System.Reflection; using System.Collections.Generic; namespace DaireApplication.DataBase { public static class DataPathManager { private static readonly string AppName = "DaireApplication"; private static string _dataDirectory; // Expected CSV headers for each file private static readonly string UsersCsvHeader = "ID,UserName,Password,CanEdit,IsAdmin,IsActive"; private static readonly string RecipeCsvHeader = "ID,Name,TankTemp,FountainTemp,Mixer,Fountain,MoldHeater,Vibration,VibHeater,Pedal,PedalOnTime,PedalOffTime,HeatingGoal,CoolingGoal,PouringGoal"; private static readonly string MachineCsvHeader = "ID,TankMaxHeat,PumbMaxHeat,PumbDelay,MixerDelay,HeatingDelay,CoolingDelay,PouringDelay,PumbMinHeat,AbsMaxTemp,AbsMinTemp,PreHeatingTemp,SetTemp1,SetTemp2,SetTemp3,SetTemp4"; private static readonly string MappingCsvHeader = "Id,Name,Address,IsRead,BitNumbers"; private static readonly string ConfigrationCsvHeader = "Id,Max,Min,H_out,FC_out,SC_out,kp,ki,kd,kl,Name,I_Nuet,I_Mot1,I_Mot2,FC_Threshold,HeatConRange"; private static readonly string ErrorSettingsCsvHeader = "Id,gridFreq,phaseNumber,extPower,phaseVoltage"; private static readonly string ScreenCsvHeader = "Id,Brightness,DimSec,OffSec,Port,BoundRate,Parity,StopBits,SendingTime,WarningLimit,ErrorLimit"; static DataPathManager() { try { // Determine the data directory based on the OS if (OperatingSystem.IsWindows()) { // Windows: Use LocalApplicationData string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); _dataDirectory = Path.Combine(appDataPath, AppName); } else { // Linux/macOS: Use ~/.local/share/DaireApplication string home = Environment.GetEnvironmentVariable("HOME") ?? "/tmp"; _dataDirectory = Path.Combine(home, ".local", "share", AppName); } // Ensure the directory exists Directory.CreateDirectory(_dataDirectory); } catch (Exception ex) { Console.WriteLine($"Failed to CreateDirectory: {ex.Message}"); Console.WriteLine($"_dataDirectory: {_dataDirectory}"); } } /// /// Returns the full path for a data file, ensuring the directory exists. /// public static string GetDataFilePath(string fileName) { try { // Ensure the directory exists before returning the file path Directory.CreateDirectory(_dataDirectory); return Path.Combine(_dataDirectory, fileName); } catch (Exception ex) { Console.WriteLine($"Failed to GetDataFilePath: {ex.Message}"); return string.Empty; } } /// /// Migrates legacy data files from the application's base directory to the new data directory. /// public static void MigrateLegacyData() { try { string[] csvFiles = { "Users.csv", "Recipe.csv", "Machine.csv", "Mapping.csv", "Configration.csv", "ErrorSettings.csv", "Screen.csv" }; foreach (string file in csvFiles) { string legacyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file); string newPath = GetDataFilePath(file); // If the file exists in the old location but not in the new location, move it if (File.Exists(legacyPath) && !File.Exists(newPath)) { // Ensure the target directory exists Directory.CreateDirectory(Path.GetDirectoryName(newPath) ?? _dataDirectory); File.Move(legacyPath, newPath); } } } catch (Exception ex) { Console.WriteLine($"Failed to MigrateLegacyData: {ex.Message}"); } } /// /// Migrates CSV files by adding missing columns with default values instead of deleting them. /// public static void MigrateCsvFiles() { MigrateCsvFile("Users.csv", UsersCsvHeader, GetUsersDefaultValues); MigrateCsvFile("Recipe.csv", RecipeCsvHeader, GetRecipeDefaultValues); MigrateCsvFile("Machine.csv", MachineCsvHeader, GetMachineDefaultValues); MigrateCsvFile("Mapping.csv", MappingCsvHeader, GetMappingDefaultValues); MigrateCsvFile("Configration.csv", ConfigrationCsvHeader, GetConfigrationDefaultValues); MigrateCsvFile("ErrorSettings.csv", ErrorSettingsCsvHeader, GetErrorSettingsDefaultValues); MigrateCsvFile("Screen.csv", ScreenCsvHeader, GetScreenDefaultValues); } /// /// Migrates a CSV file by adding missing columns with default values. /// private static void MigrateCsvFile(string fileName, string expectedHeader, Func getDefaultValue) { try { string filePath = GetDataFilePath(fileName); if (!File.Exists(filePath)) return; string[] lines = File.ReadAllLines(filePath); if (lines.Length == 0) return; string actualHeader = lines[0]; if (string.Equals(actualHeader.Trim(), expectedHeader.Trim(), StringComparison.OrdinalIgnoreCase)) return; // No migration needed string[] expectedColumns = expectedHeader.Split(','); string[] actualColumns = actualHeader.Split(','); // Find missing columns var missingColumns = new List<(int index, string columnName)>(); for (int i = 0; i < expectedColumns.Length; i++) { if (i >= actualColumns.Length || !string.Equals(actualColumns[i].Trim(), expectedColumns[i].Trim(), StringComparison.OrdinalIgnoreCase)) { missingColumns.Add((i, expectedColumns[i])); } } if (missingColumns.Count == 0) return; // Migrate the file var migratedLines = new List(); // Add new header migratedLines.Add(expectedHeader); // Migrate data rows for (int i = 1; i < lines.Length; i++) { string[] dataColumns = lines[i].Split(','); var newDataColumns = new List(dataColumns); // Add missing columns with default values foreach (var missing in missingColumns) { if (missing.index >= newDataColumns.Count) { newDataColumns.Add(getDefaultValue(missing.columnName)); } else { newDataColumns.Insert(missing.index, getDefaultValue(missing.columnName)); } } migratedLines.Add(string.Join(",", newDataColumns)); } // Write the migrated file File.WriteAllLines(filePath, migratedLines); Console.WriteLine($"Migrated {fileName} - added {missingColumns.Count} missing columns"); } catch (Exception ex) { Console.WriteLine($"Failed to migrate {fileName}: {ex.Message}"); } } // Default value providers for each file type private static string GetUsersDefaultValues(string columnName) { return columnName switch { "IsActive" => "0", _ => "" }; } private static string GetRecipeDefaultValues(string columnName) { return columnName switch { "TankTemp" => "0", "FountainTemp" => "0", "Mixer" => "0", "Fountain" => "0", "MoldHeater" => "0", "Vibration" => "0", "VibHeater" => "0", "Pedal" => "0", "PedalOnTime" => "0", "PedalOffTime" => "0", "HeatingGoal" => "46", "CoolingGoal" => "27", "PouringGoal" => "30", _ => "" }; } private static string GetMachineDefaultValues(string columnName) { return columnName switch { "TankMaxHeat" => "50", "PumbMaxHeat" => "50", "PumbDelay" => "60", "MixerDelay" => "60", "HeatingDelay" => "60", "CoolingDelay" => "60", "PouringDelay" => "60", "PumbMinHeat" => "-10", "AbsMaxTemp" => "65", "AbsMinTemp" => "-14", "PreHeatingTemp" => "5", "SetTemp1" => "0", "SetTemp2" => "-10", "SetTemp3" => "5", "SetTemp4" => "0", _ => "" }; } private static string GetMappingDefaultValues(string columnName) { return columnName switch { "BitNumbers" => "", _ => "" }; } private static string GetConfigrationDefaultValues(string columnName) { return columnName switch { "Max" => "0", "Min" => "0", "H_out" => "", "FC_out" => "", "SC_out" => "", "kp" => "0", "ki" => "0", "kd" => "0", "kl" => "0", "Name" => "", "I_Nuet" => "0", "I_Mot1" => "0", "I_Mot2" => "0", "FC_Threshold" => "3", "HeatConRange" => "50", _ => "" }; } private static string GetErrorSettingsDefaultValues(string columnName) { return columnName switch { "gridFreq" => "50", "phaseNumber" => "3", "extPower" => "1", "phaseVoltage" => "220", _ => "" }; } private static string GetScreenDefaultValues(string columnName) { return columnName switch { "Brightness" => "100", "DimSec" => "3300", "OffSec" => "3600", "Port" => "", "BoundRate" => "19200", "Parity" => "1", "StopBits" => "0", "SendingTime" => "50", "WarningLimit" => "0.5", "ErrorLimit" => "2", _ => "" }; } // Legacy delete methods (kept for backward compatibility but now call migration) public static void DeleteUsersCsv() => MigrateCsvFile("Users.csv", UsersCsvHeader, GetUsersDefaultValues); public static void DeleteRecipeCsv() => MigrateCsvFile("Recipe.csv", RecipeCsvHeader, GetRecipeDefaultValues); public static void DeleteMachineCsv() => MigrateCsvFile("Machine.csv", MachineCsvHeader, GetMachineDefaultValues); public static void DeleteMappingCsv() => MigrateCsvFile("Mapping.csv", MappingCsvHeader, GetMappingDefaultValues); public static void DeleteConfigrationCsv() => MigrateCsvFile("Configration.csv", ConfigrationCsvHeader, GetConfigrationDefaultValues); public static void DeleteErrorSettingsCsv() => MigrateCsvFile("ErrorSettings.csv", ErrorSettingsCsvHeader, GetErrorSettingsDefaultValues); public static void DeleteScreenCsv() => MigrateCsvFile("Screen.csv", ScreenCsvHeader, GetScreenDefaultValues); } }