using System; using System.Collections.Generic; using System.Linq; using Artemis.Core.Exceptions; using Artemis.Core.Models.Surface; using Artemis.Core.Plugins.Models; using Artemis.Storage.Entities.Profile; using SkiaSharp; namespace Artemis.Core.Models.Profile { public sealed class Profile : ProfileElement { internal Profile(PluginInfo pluginInfo, string name) { ProfileEntity = new ProfileEntity(); EntityId = Guid.NewGuid(); PluginInfo = pluginInfo; Name = name; UndoStack = new Stack(); RedoStack = new Stack(); AddChild(new Folder(this, null, "Root folder")); ApplyToEntity(); } internal Profile(PluginInfo pluginInfo, ProfileEntity profileEntity) { ProfileEntity = profileEntity; EntityId = profileEntity.Id; PluginInfo = pluginInfo; UndoStack = new Stack(); RedoStack = new Stack(); ApplyToProfile(); } public PluginInfo PluginInfo { get; } public bool IsActivated { get; private set; } internal ProfileEntity ProfileEntity { get; set; } internal Stack UndoStack { get; set; } internal Stack RedoStack { get; set; } public override void Update(double deltaTime) { lock (this) { if (!IsActivated) throw new ArtemisCoreException($"Cannot update inactive profile: {this}"); foreach (var profileElement in Children) profileElement.Update(deltaTime); } } public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint) { lock (this) { if (!IsActivated) throw new ArtemisCoreException($"Cannot render inactive profile: {this}"); foreach (var profileElement in Children) profileElement.Render(deltaTime, canvas, canvasInfo, paint); } } public Folder GetRootFolder() { return (Folder) Children.Single(); } public void ApplyToProfile() { Name = ProfileEntity.Name; lock (_children) { _children.Clear(); // Populate the profile starting at the root, the rest is populated recursively var rootFolder = ProfileEntity.Folders.FirstOrDefault(f => f.ParentId == new Guid()); if (rootFolder == null) AddChild(new Folder(this, null, "Root folder")); else AddChild(new Folder(this, null, rootFolder)); } } public override string ToString() { return $"[Profile] {nameof(Name)}: {Name}, {nameof(IsActivated)}: {IsActivated}, {nameof(PluginInfo)}: {PluginInfo}"; } internal override void ApplyToEntity() { ProfileEntity.Id = EntityId; ProfileEntity.PluginGuid = PluginInfo.Guid; ProfileEntity.Name = Name; ProfileEntity.IsActive = IsActivated; foreach (var profileElement in Children) profileElement.ApplyToEntity(); ProfileEntity.Folders.Clear(); ProfileEntity.Folders.AddRange(GetAllFolders().Select(f => f.FolderEntity)); ProfileEntity.Layers.Clear(); ProfileEntity.Layers.AddRange(GetAllLayers().Select(f => f.LayerEntity)); } internal void Activate(ArtemisSurface surface) { lock (this) { if (IsActivated) return; PopulateLeds(surface); OnActivated(); IsActivated = true; } } internal void Deactivate() { lock (this) { if (!IsActivated) return; foreach (var layer in GetAllLayers()) layer.Deactivate(); IsActivated = false; OnDeactivated(); } } internal void PopulateLeds(ArtemisSurface surface) { foreach (var layer in GetAllLayers()) layer.PopulateLeds(surface); } #region Events /// /// Occurs when the profile is being activated. /// public event EventHandler Activated; /// /// Occurs when the profile is being deactivated. /// public event EventHandler Deactivated; private void OnActivated() { Activated?.Invoke(this, EventArgs.Empty); } private void OnDeactivated() { Deactivated?.Invoke(this, EventArgs.Empty); } #endregion } }