context: // --------------------------------------------------------------------------------------------------------------------
  // <copyright file="Strategy.cs" company="Allors bvba">
  //   Copyright 2002-2013 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>
  // --------------------------------------------------------------------------------------------------------------------
  
  namespace Allors.Adapters.Relation.SQLite
  {
      using System;
      using System.Collections;
      using System.Collections.Generic;
  
      using Allors.Meta;
      using Adapters;
  
      public class Strategy : IStrategy
      {
          private readonly Session session;
          private readonly ObjectId objectId;
          private IObject domainObject;
         
          internal Strategy(Session session, ObjectId objectId)
          {
              this.session = session;
              this.objectId = objectId;
          }
  
          ISession IStrategy.Session 
          {
              get
              {
                  return this.session;
              }
          }
          
          public ObjectId ObjectId
          {
              get
              {
                  return this.objectId;
              }
          }
  
          public ObjectVersion ObjectVersion
          {
              get
              {
                  this.AssertNotDeleted();
                  var cacheId = this.session.GetCacheId(objectId);
                  return new ObjectVersionLong(cacheId);
              }
          }
  
          public bool IsDeleted 
          {
              get
              {
                  return this.session.IsDeleted(this.objectId);
              }
          }
  
          public bool IsNewInSession 
          {
              get
              {
                  return this.session.IsNew(this.ObjectId);
              }
          }
  
          public IClass Class
          {
              get
              {
                  this.AssertNotDeleted();
                  return this.session.GetObjectType(this.ObjectId);
              }
          }
  
          internal IClass UncheckedObjectType
          {
              get
              {
                  return this.session.GetObjectType(this.ObjectId);
              }
          }
  
          public IObject GetObject()
          {
              this.AssertNotDeleted();
              return this.domainObject ?? (this.domainObject = this.session.Database.ObjectFactory.Create(this));
          }
  
          public void Delete()
          {
              this.AssertNotDeleted();
  
              foreach (var roleType in this.UncheckedObjectType.RoleTypes)
              {
                  if (roleType.ObjectType is IUnit)
                  {
                      this.session.RemoveUnitRole(this.objectId, roleType);
                  }
                  else
                  {
                      if (roleType.IsMany)
                      {
                          switch (roleType.RelationType.Multiplicity)
                          {
                              case Multiplicity.OneToMany:
                                  this.session.RemoveCompositeRolesOneToMany(this.objectId, roleType);
                                  break;
                              case Multiplicity.ManyToMany:
                                  this.session.RemoveCompositeRolesManyToMany(this.objectId, roleType);
                                  break;
                          }
                      }
                      else
                      {
                          switch (roleType.RelationType.Multiplicity)
                          {
                              case Multiplicity.OneToOne:
                                  this.session.RemoveCompositeRoleOneToOne(this.objectId, roleType);
                                  break;
                              case Multiplicity.ManyToOne:
                                  this.session.RemoveCompositeRoleManyToOne(this.objectId, roleType);
                                  break;
                          }
                      }
                  }
              }
  
              foreach (var associationType in this.UncheckedObjectType.AssociationTypes)
              {
                  var roleType = associationType.RoleType;
  
                  if (associationType.IsMany)
                  {
                      switch (associationType.RelationType.Multiplicity)
                      {
                          case Multiplicity.ManyToOne:
                              foreach (var association in this.session.GetCompositeAssociationsManyToOne(this.objectId, associationType))
                              {
                                  this.session.RemoveCompositeRoleManyToOne(association, roleType);
                              }
  
                              break;
                          case Multiplicity.ManyToMany:
                              foreach (var association in this.session.GetCompositeAssociationsManyToMany(this.objectId, associationType))
                              {
                                  this.session.RemoveCompositeRoleManyToMany(association, roleType, this.objectId);
                              }
  
                              break;
                      }
                  }
                  else
                  {
                      ObjectId association;
                      switch (associationType.RelationType.Multiplicity)
                      {
                          case Multiplicity.OneToOne:
                              association = this.session.GetCompositeAssociationOneToOne(this.objectId, associationType);
                              if (association != null)
                              {
                                  this.session.RemoveCompositeRoleOneToOne(association, roleType);
                              }
  
                              break;
                          case Multiplicity.OneToMany:
                              association = this.session.GetCompositeAssociationOneToMany(this.objectId, associationType);
                              if (association != null)
                              {
                                  this.session.RemoveCompositeRoleOneToMany(association, roleType, this.objectId);
                              }
  
                              break;
                      }
                  }
              }
  
              this.session.Delete(this.objectId);
          }
  
          public virtual bool ExistRole(IRoleType roleType)
          {
              if (roleType.ObjectType is IUnit)
              {
                  return this.ExistUnitRole(roleType);
              }
  
              if (roleType.IsMany)
              {
                  return this.ExistCompositeRoles(roleType);
              }
  
              return this.ExistCompositeRole(roleType);
          }
  
          public virtual object GetRole(IRoleType roleType)
          {
              if (roleType.ObjectType is IUnit)
              {
                  return this.GetUnitRole(roleType);
              }
  
              if (roleType.IsMany)
              {
                  return this.GetCompositeRoles(roleType);
              }
  
              return this.GetCompositeRole(roleType);
          }
  
          public virtual void SetRole(IRoleType roleType, object value)
          {
              if (roleType.ObjectType is IUnit)
              {
                  this.SetUnitRole(roleType, value);
              }
              else
              {
                  if (roleType.IsMany)
                  {
                      var roleExtent = value as Extent;
                      if (roleExtent == null)
                      {
                          // TODO: Use Linq
                          var roleList = new ArrayList((ICollection)value);
                          roleExtent = (IObject[])roleList.ToArray(typeof(IObject));
                      }
  
                      this.SetCompositeRoles(roleType, roleExtent);
                  }
                  else
                  {
                      this.SetCompositeRole(roleType, (IObject)value);
                  }
              }
          }
  
          public virtual void RemoveRole(IRoleType roleType)
          {
              if (roleType.ObjectType is IUnit)
              {
                  this.RemoveUnitRole(roleType);
              }
              else
              {
                  if (roleType.IsMany)
                  {
                      this.RemoveCompositeRoles(roleType);
                  }
                  else
                  {
                      this.RemoveCompositeRole(roleType);
                  }
              }
          }
          
          public bool ExistUnitRole(IRoleType roleType)
          {
              this.AssertNotDeleted();
  
              return this.session.ExistUnitRole(this.objectId, roleType);
          }
  
          public object GetUnitRole(IRoleType roleType)
          {
              this.AssertNotDeleted();
  
              return this.session.GetUnitRole(this.ObjectId, roleType);
          }
  
          public void SetUnitRole(IRoleType roleType, object unit)
          {
              if (unit == null)
              {
                  this.RemoveUnitRole(roleType);
                  return;
              }
  
              this.AssertNotDeleted();
  
              RoleAssertions.UnitRoleChecks(this, roleType);
  
gt:             unit = roleType.Normalize(unit);