204 lines
9.2 KiB
C#
204 lines
9.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using Newtonsoft.Json;
|
|
|
|
namespace EveOPreview.Configuration.Implementation {
|
|
class ConfigurationStorage : IConfigurationStorage {
|
|
private const string CONFIGURATION_FILE_NAME = "EVE-O-Preview.json";
|
|
private const string PROFILES_DIRECTORY = "Profiles";
|
|
private const string MASTER_CONFIG_FILE = "master.json";
|
|
|
|
private readonly IAppConfig _appConfig;
|
|
private readonly IThumbnailConfiguration _thumbnailConfiguration;
|
|
|
|
public ConfigurationStorage(IAppConfig appConfig, IThumbnailConfiguration thumbnailConfiguration) {
|
|
this._appConfig = appConfig;
|
|
this._thumbnailConfiguration = thumbnailConfiguration;
|
|
}
|
|
|
|
public void Load() {
|
|
string masterConfigPath = this.GetMasterConfigPath();
|
|
|
|
// First, load the master configuration which contains ProfileReadOnly and CurrentProfile
|
|
string currentProfile = "Default";
|
|
bool profileReadOnly = false;
|
|
|
|
if (File.Exists(masterConfigPath)) {
|
|
string masterRawData = File.ReadAllText(masterConfigPath);
|
|
var masterConfig = JsonConvert.DeserializeObject<dynamic>(masterRawData);
|
|
if (masterConfig.CurrentProfile != null) {
|
|
currentProfile = masterConfig.CurrentProfile.ToString();
|
|
}
|
|
if (masterConfig.ProfileReadOnly != null) {
|
|
profileReadOnly = (bool)masterConfig.ProfileReadOnly;
|
|
}
|
|
}
|
|
|
|
this._thumbnailConfiguration.CurrentProfile = currentProfile;
|
|
this._thumbnailConfiguration.ProfileReadOnly = profileReadOnly;
|
|
|
|
// Scan the profiles directory for available profiles AFTER loading master config
|
|
List<string> scannedProfiles = this.ScanAvailableProfiles();
|
|
|
|
// Replace AvailableProfiles with scanned profiles (they are the source of truth)
|
|
this._thumbnailConfiguration.AvailableProfiles.Clear();
|
|
foreach (string profile in scannedProfiles) {
|
|
this._thumbnailConfiguration.AvailableProfiles.Add(profile);
|
|
}
|
|
|
|
// Ensure CurrentProfile is in the list
|
|
if (!string.IsNullOrEmpty(this._thumbnailConfiguration.CurrentProfile) &&
|
|
!this._thumbnailConfiguration.AvailableProfiles.Contains(this._thumbnailConfiguration.CurrentProfile)) {
|
|
this._thumbnailConfiguration.AvailableProfiles.Add(this._thumbnailConfiguration.CurrentProfile);
|
|
}
|
|
|
|
// Then, load the profile-specific configuration
|
|
// IMPORTANT: Reset the configuration to clean state before loading
|
|
// to avoid merging with existing default values
|
|
string profileConfigPath = this.GetProfileConfigPath(currentProfile);
|
|
|
|
if (File.Exists(profileConfigPath)) {
|
|
string profileRawData = File.ReadAllText(profileConfigPath);
|
|
JsonSerializerSettings jsonSerializerSettings =
|
|
new JsonSerializerSettings() { ObjectCreationHandling = ObjectCreationHandling.Replace };
|
|
JsonConvert.PopulateObject(profileRawData, this._thumbnailConfiguration, jsonSerializerSettings);
|
|
} else {
|
|
// Try to load from legacy config file for backwards compatibility
|
|
string legacyConfigPath = this.GetConfigFileName();
|
|
if (File.Exists(legacyConfigPath)) {
|
|
string legacyRawData = File.ReadAllText(legacyConfigPath);
|
|
JsonSerializerSettings jsonSerializerSettings =
|
|
new JsonSerializerSettings() { ObjectCreationHandling = ObjectCreationHandling.Replace };
|
|
JsonConvert.PopulateObject(legacyRawData, this._thumbnailConfiguration, jsonSerializerSettings);
|
|
}
|
|
}
|
|
|
|
// Restore the values we just set (they might have been overwritten by profile load)
|
|
this._thumbnailConfiguration.CurrentProfile = currentProfile;
|
|
this._thumbnailConfiguration.ProfileReadOnly = profileReadOnly;
|
|
// Re-scan profiles after loading in case the profile overwrote AvailableProfiles
|
|
this._thumbnailConfiguration.AvailableProfiles.Clear();
|
|
foreach (string profile in scannedProfiles) {
|
|
this._thumbnailConfiguration.AvailableProfiles.Add(profile);
|
|
}
|
|
|
|
// Validate data after loading it
|
|
this._thumbnailConfiguration.ApplyRestrictions();
|
|
}
|
|
|
|
public void Save() {
|
|
// Save master configuration (contains ProfileReadOnly and CurrentProfile)
|
|
this.SaveMasterConfig();
|
|
|
|
// If profile is read-only, don't save to the profile file
|
|
if (!this._thumbnailConfiguration.ProfileReadOnly) {
|
|
this.SaveProfileConfig();
|
|
}
|
|
}
|
|
|
|
private void SaveMasterConfig() {
|
|
string masterConfigPath = this.GetMasterConfigPath();
|
|
string directory = Path.GetDirectoryName(masterConfigPath);
|
|
|
|
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) {
|
|
Directory.CreateDirectory(directory);
|
|
}
|
|
|
|
// Create a minimal master config with only ProfileReadOnly and CurrentProfile
|
|
// AvailableProfiles is determined by scanning the folder, not saved here
|
|
var masterConfig = new {
|
|
CurrentProfile = this._thumbnailConfiguration.CurrentProfile ?? "Default",
|
|
ProfileReadOnly = this._thumbnailConfiguration.ProfileReadOnly
|
|
};
|
|
|
|
string rawData = JsonConvert.SerializeObject(masterConfig, Formatting.Indented);
|
|
|
|
try {
|
|
File.WriteAllText(masterConfigPath, rawData);
|
|
} catch (IOException) {
|
|
// Ignore error if for some reason the updated config cannot be written down
|
|
}
|
|
}
|
|
|
|
private void SaveProfileConfig() {
|
|
string profileConfigPath = this.GetProfileConfigPath();
|
|
string directory = Path.GetDirectoryName(profileConfigPath);
|
|
|
|
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) {
|
|
Directory.CreateDirectory(directory);
|
|
}
|
|
|
|
// Serialize the full configuration to the profile file
|
|
string rawData = JsonConvert.SerializeObject(this._thumbnailConfiguration, Formatting.Indented);
|
|
|
|
try {
|
|
File.WriteAllText(profileConfigPath, rawData);
|
|
} catch (IOException) {
|
|
// Ignore error if for some reason the updated config cannot be written down
|
|
}
|
|
}
|
|
|
|
private string GetMasterConfigPath() {
|
|
return Path.Combine(PROFILES_DIRECTORY, MASTER_CONFIG_FILE);
|
|
}
|
|
|
|
private string GetProfileConfigPath() {
|
|
return this.GetProfileConfigPath(this._thumbnailConfiguration.CurrentProfile ?? "Default");
|
|
}
|
|
|
|
private string GetProfileConfigPath(string profileName) {
|
|
string sanitizedProfileName = this.SanitizeFileName(profileName);
|
|
return Path.Combine(PROFILES_DIRECTORY, $"{sanitizedProfileName}.json");
|
|
}
|
|
|
|
private string GetConfigFileName() {
|
|
return string.IsNullOrEmpty(this._appConfig.ConfigFileName) ? ConfigurationStorage.CONFIGURATION_FILE_NAME
|
|
: this._appConfig.ConfigFileName;
|
|
}
|
|
|
|
private string SanitizeFileName(string fileName) {
|
|
string invalidChars = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
|
|
foreach (char c in invalidChars) {
|
|
fileName = fileName.Replace(c, '_');
|
|
}
|
|
return fileName;
|
|
}
|
|
|
|
private List<string> ScanAvailableProfiles() {
|
|
List<string> profiles = new List<string>();
|
|
|
|
if (!Directory.Exists(PROFILES_DIRECTORY)) {
|
|
profiles.Add("Default");
|
|
return profiles;
|
|
}
|
|
|
|
try {
|
|
foreach (string filePath in Directory.GetFiles(PROFILES_DIRECTORY, "*.json")) {
|
|
string fileName = Path.GetFileNameWithoutExtension(filePath);
|
|
|
|
// Skip the master config file
|
|
if (fileName.Equals(MASTER_CONFIG_FILE.Replace(".json", ""), StringComparison.OrdinalIgnoreCase)) {
|
|
continue;
|
|
}
|
|
|
|
// Add the profile name
|
|
if (!string.IsNullOrEmpty(fileName) && !profiles.Contains(fileName)) {
|
|
profiles.Add(fileName);
|
|
}
|
|
}
|
|
} catch (IOException) {
|
|
// If there's an error scanning the directory, just return what we have
|
|
}
|
|
|
|
// Ensure Default is always in the list
|
|
if (!profiles.Contains("Default")) {
|
|
profiles.Add("Default");
|
|
}
|
|
|
|
return profiles;
|
|
}
|
|
}
|
|
}
|