using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Reflection; using Artemis.Core.Modules; using Humanizer; namespace Artemis.Core.DataModelExpansions { /// /// Represents a data model that contains information on a game/application etc. /// public abstract class DataModel { private readonly Dictionary _dynamicDataModels = new Dictionary(); /// /// Creates a new instance of the class /// protected DataModel() { // These are both set right after construction to keep the constructor of inherited classes clean Feature = null!; DataModelDescription = null!; } /// /// Gets the plugin feature this data model belongs to /// [DataModelIgnore] public DataModelPluginFeature Feature { get; internal set; } /// /// Gets the describing this data model /// [DataModelIgnore] public DataModelPropertyAttribute DataModelDescription { get; internal set; } /// /// Gets the is expansion status indicating whether this data model expands the main data model /// [DataModelIgnore] public bool IsExpansion { get; internal set; } /// /// Gets an read-only dictionary of all dynamic data models /// [DataModelIgnore] public ReadOnlyDictionary DynamicDataModels => new ReadOnlyDictionary(_dynamicDataModels); /// /// Returns a read-only collection of all properties in this datamodel that are to be ignored /// /// public ReadOnlyCollection GetHiddenProperties() { if (Feature is ProfileModule profileModule) return profileModule.HiddenProperties; if (Feature is BaseDataModelExpansion dataModelExpansion) return dataModelExpansion.HiddenProperties; return new List().AsReadOnly(); } /// /// Adds a dynamic data model to this data model /// /// The dynamic data model to add /// The key of the child, must be unique to this data model /// An optional name, if not provided the key will be used in a humanized form /// An optional description public T AddDynamicChild(T dynamicDataModel, string key, string? name = null, string? description = null) where T : DataModel { if (dynamicDataModel == null) throw new ArgumentNullException(nameof(dynamicDataModel)); if (key == null) throw new ArgumentNullException(nameof(key)); if (key.Contains('.')) throw new ArtemisCoreException("The provided key contains an illegal character (.)"); if (_dynamicDataModels.ContainsKey(key)) throw new ArtemisCoreException($"Cannot add a dynamic data model with key '{key}' " + "because the key is already in use on by another dynamic property this data model."); if (_dynamicDataModels.ContainsValue(dynamicDataModel)) { string existingKey = _dynamicDataModels.First(kvp => kvp.Value == dynamicDataModel).Key; throw new ArtemisCoreException($"Cannot add a dynamic data model with key '{key}' " + $"because the dynamic data model is already added with key '{existingKey}."); } if (GetType().GetProperty(key) != null) throw new ArtemisCoreException($"Cannot add a dynamic data model with key '{key}' " + "because the key is already in use by a static property on this data model."); dynamicDataModel.Feature = Feature; dynamicDataModel.DataModelDescription = new DataModelPropertyAttribute { Name = string.IsNullOrWhiteSpace(name) ? key.Humanize() : name, Description = description }; _dynamicDataModels.Add(key, dynamicDataModel); OnDynamicDataModelAdded(new DynamicDataModelEventArgs(dynamicDataModel, key)); return dynamicDataModel; } /// /// Removes a dynamic data model from the data model by its key /// /// The key of the dynamic data model to remove public void RemoveDynamicChildByKey(string key) { _dynamicDataModels.TryGetValue(key, out DataModel? childDataModel); if (childDataModel == null) return; _dynamicDataModels.Remove(key); OnDynamicDataModelRemoved(new DynamicDataModelEventArgs(childDataModel, key)); } /// /// Removes a dynamic data model from this data model /// /// The dynamic data model to remove public void RemoveDynamicChild(DataModel dynamicDataModel) { List keys = _dynamicDataModels.Where(kvp => kvp.Value == dynamicDataModel).Select(kvp => kvp.Key).ToList(); foreach (string key in keys) { _dynamicDataModels.Remove(key); OnDynamicDataModelRemoved(new DynamicDataModelEventArgs(dynamicDataModel, key)); } } /// /// Removes all dynamic data models from this data model /// public void ClearDynamicChildren() { while (_dynamicDataModels.Any()) RemoveDynamicChildByKey(_dynamicDataModels.First().Key); } /// /// Gets a dynamic data model of type by its key /// /// The type of data model you expect /// The unique key of the dynamic data model /// If found, the dynamic data model otherwise null public T? DynamicChild(string key) where T : DataModel { _dynamicDataModels.TryGetValue(key, out DataModel? value); return value as T; } #region Events /// /// Occurs when a dynamic data model has been added to this data model /// public event EventHandler? DynamicDataModelAdded; /// /// Occurs when a dynamic data model has been removed from this data model /// public event EventHandler? DynamicDataModelRemoved; /// /// Invokes the event /// protected virtual void OnDynamicDataModelAdded(DynamicDataModelEventArgs e) { DynamicDataModelAdded?.Invoke(this, e); } /// /// Invokes the event /// protected virtual void OnDynamicDataModelRemoved(DynamicDataModelEventArgs e) { DynamicDataModelRemoved?.Invoke(this, e); } #endregion } }