context: //------------------------------------------------------------------------------------------------- 
  // <copyright file="MetaPopulation.cs" company="Allors bvba">
  // Copyright 2002-2017 Allors bvba.
  // 
  // Dual Licensed under
  //   a) the Lesser General Public Licence v3 (LGPL)
  //   b) the Allors License
  // 
  // The LGPL License is included in the file lgpl.txt.
  // The Allors License is an addendum to your contract.
  // 
  // Allors Platform is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  // GNU General Public License for more details.
  // 
  // For more information visit http://www.allors.com/legal
  // </copyright>
  // <summary>Defines the Domain type.</summary>
  //-------------------------------------------------------------------------------------------------
  
  using Allors.Meta;
  
  namespace Allors.Meta
  {
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Reflection;
      using System.Runtime.CompilerServices;
  
      public sealed partial class MetaPopulation : IMetaPopulation
      {
          private const string NamespaceName = "Allors.Domain";
  
          private readonly Dictionary<Guid, MetaObjectBase> metaObjectById;
  
          private Dictionary<string, Class> derivedClassByLowercaseName;
          private Composite[] derivedComposites;
  
          private bool isBound;
  
          private bool isStale;
          private bool isDeriving;
  
          private IList<Domain> domains;
          private IList<Unit> units;
          private IList<Interface> interfaces;
          private IList<Class> classes;
          private IList<Inheritance> inheritances;
          private IList<RelationType> relationTypes;
          private IList<AssociationType> associationTypes;
          private IList<RoleType> roleTypes;
          private IList<MethodType> methodTypes;
  
          public static readonly MetaPopulation Instance;
  
          static MetaPopulation()
          {
              Instance = new MetaPopulation();
              var metaBuilder = new MetaBuilder(Instance);
              metaBuilder.BuildDomains();
              metaBuilder.BuildObjectTypes();
              metaBuilder.BuildOperandTypes();
          }
  
          private MetaPopulation()
          {
              this.isStale = true;
              this.isDeriving = false;
  
              this.domains = new List<Domain>();
              this.units = new List<Unit>();
              this.interfaces = new List<Interface>();
              this.classes = new List<Class>();
              this.inheritances = new List<Inheritance>();
              this.relationTypes = new List<RelationType>();
              this.associationTypes = new List<AssociationType>();
              this.roleTypes = new List<RoleType>();
              this.methodTypes = new List<MethodType>();
  
              this.metaObjectById = new Dictionary<Guid, MetaObjectBase>();
          }
  
          public bool IsBound => this.isBound;
  
          public IEnumerable<Domain> Domains => this.domains;
  
          public IEnumerable<Domain> SortedDomains
          {
              get
              {
                  var sortedDomains = new List<Domain>(this.domains);
                  sortedDomains.Sort((x, y) => x.Superdomains.Contains(y) ? -1 : 1);
                  return sortedDomains.ToArray();
              }
          }
  
          IEnumerable<IUnit> IMetaPopulation.Units => this.Units;
  
          public IEnumerable<Unit> Units => this.units;
  
          IEnumerable<IInterface> IMetaPopulation.Interfaces => this.Interfaces;
  
          public IEnumerable<Interface> Interfaces => this.interfaces;
  
          IEnumerable<IClass> IMetaPopulation.Classes => this.Classes;
  
          public IEnumerable<Class> Classes => this.classes;
  
          public IEnumerable<Inheritance> Inheritances => this.inheritances;
  
          IEnumerable<IRelationType> IMetaPopulation.RelationTypes => this.RelationTypes;
  
          public IEnumerable<RelationType> RelationTypes => this.relationTypes;
  
          public IEnumerable<AssociationType> AssociationTypes => this.associationTypes;
  
          public IEnumerable<RoleType> RoleTypes => this.roleTypes;
  
          public IEnumerable<MethodType> MethodTypes => this.methodTypes;
  
          IEnumerable<IComposite> IMetaPopulation.Composites => this.Composites;
  
          public IEnumerable<Composite> Composites
          {
              get
              {
                  this.Derive();
                  return this.derivedComposites;
              }
          }
          
          public IEnumerable<Composite> SortedComposites => this.Composites.OrderBy(v => v.Name);
  
          /// <summary>
          /// Gets a value indicating whether this instance is valid.
          /// </summary>
          /// <value><c>true</c> if this instance is valid; otherwise, <c>false</c>.</value>
          public bool IsValid
          {
              get
              {
                  var validation = this.Validate();
                  if (validation.ContainsErrors)
                  {
                      return false;
                  }
  
                  return true;
              }
          }
  
          IMetaObject IMetaPopulation.Find(Guid id)
          {
              return this.Find(id);
          }
  
          /// <summary>
          /// Find a meta object by meta object id.
          /// </summary>
          /// <param name="id">
          /// The meta object id.
          /// </param>
          /// <returns>
          /// The <see cref="IMetaObject"/>.
          /// </returns>
          public MetaObjectBase Find(Guid id)
          {
              MetaObjectBase metaObject;
              this.metaObjectById.TryGetValue(id, out metaObject);
  
              return metaObject;
          }
          
          IClass IMetaPopulation.FindClassByName(string name)
          {
              return this.FindByName(name);
          }
  
          /// <summary>
          /// Find a meta object by name.
          /// </summary>
          /// <param name="name">
          /// The meta object id.
          /// </param>
          /// <returns>
          /// The <see cref="IMetaObject"/>.
          /// </returns>
          public Class FindByName(string name)
          {
              this.Derive();
  
              Class cls;
              this.derivedClassByLowercaseName.TryGetValue(name.ToLowerInvariant(), out cls);
  
              return cls;
          }
  
          IValidationLog IMetaPopulation.Validate()
          {
              return this.Validate();
          }
  
          /// <summary>
          /// Validates this instance.
          /// </summary>
          /// <returns>The Validate.</returns>
          public ValidationLog Validate()
          {
              var log = new ValidationLog();
  
              foreach (var domain in this.Domains)
              {
                  domain.Validate(log);
              }
  
              foreach (var unitType in this.Units)
              {
                  unitType.Validate(log);
              }
  
              foreach (var @interface in this.Interfaces)
              {
                  @interface.Validate(log);
              }
  
              foreach (var @class in this.Classes)
              {
                  @class.Validate(log);
              }
  
              foreach (var inheritance in this.Inheritances)
              {
                  inheritance.Validate(log);
              }
  
              foreach (var relationType in this.RelationTypes)
              {
                  relationType.Validate(log);
              }
  
              foreach (var methodType in this.MethodTypes)
              {
                  methodType.Validate(log);
              }
  
  
              var inheritancesBySubtype = new Dictionary<Composite, List<Inheritance>>();
              foreach (var inheritance in this.Inheritances)
              {
                  var subtype = inheritance.Subtype;
                  if (subtype != null)
                  {
                      List<Inheritance> inheritanceList;
                      if (!inheritancesBySubtype.TryGetValue(subtype, out inheritanceList))
                      {
                          inheritanceList = new List<Inheritance>();
                          inheritancesBySubtype[subtype] = inheritanceList;
                      }
  
                      inheritanceList.Add(inheritance);
                  }
              }
  
              var supertypes = new HashSet<Interface>();
              foreach (var subtype in inheritancesBySubtype.Keys)
              {
                  supertypes.Clear();
                  if (this.HasCycle(subtype, supertypes, inheritancesBySubtype))
                  {
                      var message = subtype.ValidationName + " has a cycle in its inheritance hierarchy";
                      log.AddError(message, subtype, ValidationKind.Cyclic, "IComposite.Supertypes");
                  }
              }
  
  
              return log;
          }
  
          public void Bind(Type[] types, MethodInfo[] methods)
          {
              if (!this.IsBound)
              {
                  this.Derive();
  
                  this.isBound = true;
  
  
gt:                 this.domains = this.domains.ToArray();