using System; using System.Collections.Generic; using System.Linq; using System.Text; using log4net; using Quadarax.Foundation.Common.Object; using StructureMap; namespace Quadarax.Foundation.Infrastructure.Layers { public abstract class Layer : DisposableObject { private IContainer _container; private IList _childLayers = new List(); private Layer _parentLayer; protected ILog Log { get; } public string Name { get; } public int ChildLayersCount => _childLayers.Count; public LayerClassificationEnum LayerType { get; protected set; } protected Layer(string name, Layer parentLayer) { if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name), "Infrastucture layer must have a name."); _parentLayer = parentLayer; Log = LogManager.GetLogger(GetType()); Name = name; InitializeInternal(); Log.Info($"Layer '{Name}' fully created."); } private void InitializeInternal() { // _container = _parentLayer == null ? new Container() : _parentLayer._container.CreateChildContainer(); _container = _parentLayer == null ? new Container() : _parentLayer._container; OnModuleRegistry(_container); OnLayerRegistry(); Log.Info($"Layer '{Name}' initialization done"); } protected void AddChildLayer(Layer layer) { if (layer==null) throw new ArgumentNullException(nameof(layer)); _childLayers.Add(layer); Log.Info($"Layer 'Name' append child layer '{layer.Name}'. Current child count on layer '{Name}' is {ChildLayersCount} childs."); } protected abstract void OnLayerRegistry(); protected abstract void OnModuleRegistry(IContainer container); protected override void OnDisposing() { _parentLayer = null; if (_childLayers != null) { foreach (var layer in _childLayers) { layer.Dispose(); } } Log.Info($"Layer '{Name}' disposed."); } public TModule Get() where TModule : IModule { Log.Debug($"Try to find module '{typeof(TModule)}' in layer '{Name}'..."); var result = _container.TryGetInstance(); if (result != null) return result; Log.Debug($"Cannot find module '{typeof(TModule)}' in layer '{Name}'. Trying to find in child layers."); foreach (var child in _childLayers) { result = child.Get(); if (result != null) return result; } return default(TModule); } public IEnumerable FindChildLayer(bool recursive = true) where TLayer : Layer { var result = new List(); if (recursive) { foreach (var child in _childLayers) { result.AddRange(child.FindChildLayer(recursive)); } } result.AddRange(_childLayers.Where(x => x.GetType() == typeof(TLayer)).Select(x=> (TLayer)x)); return result.ToArray(); } public IEnumerable FindChildLayer(string layerName, bool recursive = true) { var result = new List(); if (recursive) { foreach (var child in _childLayers) { result.AddRange(child.FindChildLayer(layerName, recursive)); } } result.AddRange(_childLayers.Where(x => x.Name == layerName)); return result.ToArray(); } public IEnumerable GetChildLayerNames(bool recursive = true) { var result = new List(); if (recursive) { foreach (var child in _childLayers) { result.AddRange(child.GetChildLayerNames(recursive)); } } result.AddRange(_childLayers.Select(x => x.Name)); return result.ToArray(); } public string Dump() { return DumpInternal(0); } private string DumpInternal(int level) { var sb = new StringBuilder(); sb.Append(new string(' ', level * 3)).Append("*** Layer [").Append(level).Append("]: ").Append(Name).Append(" [").Append(LayerType).Append("] * BEGIN ***").AppendLine(); sb.Append(new string(' ', level * 3)).Append("Parent:").AppendLine(); sb.Append(_parentLayer == null ? "none" : _parentLayer.Name); sb.AppendLine(); sb.Append(new string(' ', level * 3)).Append("Childs:").AppendLine(); if (_childLayers.Count > 0) foreach (var child in _childLayers) sb.Append(child.DumpInternal(level + 1)).AppendLine(); else sb.Append(new string(' ', level * 3)).Append("no childs").AppendLine(); sb.Append(new string(' ', level * 3)).Append("*** Layer [").Append(level).Append("]: ").Append(LayerType).Append("] * END ***").AppendLine(); return sb.ToString(); } public string DumpContainer(bool recursive = false) { var sb = new StringBuilder(); sb.Append("LAYER: ").Append(Name).AppendLine(); sb.AppendLine(_container.WhatDoIHave()); if (recursive) { sb.Append("LAYER: ").Append(Name).Append(" childs").AppendLine(); foreach (var layer in _childLayers) { sb.AppendLine(layer.DumpContainer(recursive)); } } return sb.ToString(); } public override string ToString() { return $"Layer={Name};Type={LayerType};ChildCount={ChildLayersCount}"; } } }