// --------------------------------------------------------------------------------------------------------------------
//
// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
//
//
// The User Setting Service
//
// --------------------------------------------------------------------------------------------------------------------
namespace HandBrakeWPF.Services
{
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml.Serialization;
using HandBrake.Interop.Model;
using HandBrake.Interop.Utilities;
using HandBrakeWPF.Collections;
using HandBrakeWPF.Extensions;
using HandBrakeWPF.Properties;
using HandBrakeWPF.Services.Interfaces;
using HandBrakeWPF.Utilities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using GeneralApplicationException = Exceptions.GeneralApplicationException;
using SettingChangedEventArgs = EventArgs.SettingChangedEventArgs;
///
/// The User Setting Service
///
public class UserSettingService : IUserSettingService
{
private readonly string settingsFile = Path.Combine(DirectoryUtilities.GetUserStoragePath(VersionHelper.IsNightly()), "settings.json");
private readonly string releaseSettingsFile = Path.Combine(DirectoryUtilities.GetUserStoragePath(false), "settings.json");
private readonly string nightlySettingsFile = Path.Combine(DirectoryUtilities.GetUserStoragePath(true), "settings.json");
private readonly JsonSerializerSettings settings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
private Dictionary userSettings;
///
/// Initializes a new instance of the class.
///
public UserSettingService()
{
this.Load();
}
///
/// The setting changed.
///
public event SettingEventHandler SettingChanged;
///
/// Set the specified user setting.
///
///
/// Name of the property
///
///
/// The value to store.
///
public void SetUserSetting(string name, object value)
{
this.userSettings[name] = value;
this.Save();
this.OnSettingChanged(new SettingChangedEventArgs { Key = name, Value = value });
}
///
/// Get user setting for a given key.
///
///
/// The name.
///
///
/// The conversion Type.
///
///
/// The Type of the setting
///
///
/// The user setting
///
public T GetUserSetting(string name, Type conversionType = null)
{
if (this.userSettings.ContainsKey(name))
{
if (conversionType != null && typeof(int) == conversionType)
{
object storedValue = this.userSettings[name];
object converted = storedValue?.ToString().ToInt();
return (T)converted;
}
// Treat String Arrays as StringCollections. TODO refactor upstream code to more traditional string arrays.
object settingValue = this.userSettings[name];
if (settingValue != null && settingValue.GetType() == typeof(JArray))
{
string[] stringArr = ((JArray)settingValue).ToObject();
StringCollection stringCollection = new StringCollection();
foreach (var item in stringArr)
{
stringCollection.Add(item);
}
settingValue = stringCollection;
}
return (T)settingValue;
}
return default(T);
}
///
/// The on setting changed.
///
///
/// The e.
///
protected virtual void OnSettingChanged(SettingChangedEventArgs e)
{
SettingEventHandler handler = this.SettingChanged;
if (handler != null)
{
handler(this, e);
}
}
///
/// Save the User Settings
///
private void Save()
{
try
{
string directory = Path.GetDirectoryName(this.settingsFile);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
using (StreamWriter file = new StreamWriter(new FileStream(this.settingsFile, FileMode.Create, FileAccess.Write)))
{
string appSettings = JsonConvert.SerializeObject(this.userSettings, Formatting.Indented, this.settings);
file.Write(appSettings);
}
}
catch (Exception exc)
{
throw new GeneralApplicationException(
Resources.UserSettings_AnErrorOccured,
Resources.SettingService_SaveErrorReset,
exc);
}
}
///
/// Load the User Settings
///
private void Load()
{
try
{
// Load up the users current settings file.
if (File.Exists(this.settingsFile))
{
using (StreamReader reader = new StreamReader(this.settingsFile))
{
string appSettings = reader.ReadToEnd();
Dictionary deserialisedSettings = JsonConvert.DeserializeObject< Dictionary>(appSettings);
this.userSettings = deserialisedSettings;
}
}
else if (VersionHelper.IsNightly() && File.Exists(this.releaseSettingsFile))
{
// Port the release versions config to the nightly.
if (!Directory.Exists(DirectoryUtilities.GetUserStoragePath(true)))
{
Directory.CreateDirectory(DirectoryUtilities.GetUserStoragePath(true));
}
File.Copy(this.releaseSettingsFile, this.nightlySettingsFile);
using (StreamReader reader = new StreamReader(this.settingsFile))
{
string appSettings = reader.ReadToEnd();
Dictionary deserialisedSettings = JsonConvert.DeserializeObject>(appSettings);
this.userSettings = deserialisedSettings;
}
}
else
{
this.userSettings = new Dictionary();
}
// Add any missing / new settings
SerializableDictionary defaults = this.GetDefaults();
foreach (var item in defaults.Where(item => !this.userSettings.Keys.Contains(item.Key)))
{
this.userSettings.Add(item.Key, item.Value);
this.Save();
}
// Legacy Settings forced Reset.
this.userSettings[UserSettingConstants.ScalingMode] = VideoScaler.Lanczos;
}
catch (Exception exc)
{
try
{
this.userSettings = this.GetDefaults();
if (File.Exists(this.settingsFile))
{
File.Delete(this.settingsFile);
}
this.Save();
throw new GeneralApplicationException(Resources.UserSettings_YourSettingsHaveBeenReset, Resources.UserSettings_YourSettingsAreCorrupt, exc);
}
catch (Exception)
{
throw new GeneralApplicationException(string.Format(Resources.UserSettings_UnableToLoad, this.settingsFile), Resources.UserSettings_UnableToLoadSolution, exc);
}
}
}
///
/// Load Default Settings
///
///
/// The get defaults.
///
private SerializableDictionary GetDefaults()
{
// TODO Convert this to JSON.
try
{
Assembly assembly = Assembly.GetEntryAssembly();
Stream stream = assembly.GetManifestResourceStream("HandBrakeWPF.defaultsettings.xml");
if (stream != null)
{
XmlSerializer serializer = new XmlSerializer(typeof(Collections.SerializableDictionary));
return (SerializableDictionary)serializer.Deserialize(stream);
}
}
catch (Exception)
{
return new SerializableDictionary();
}
return new SerializableDictionary();
}
}
}