context: // <copyright file="Load.cs" company="Allors bvba">
  // Copyright (c) Allors bvba. All rights reserved.
  // Licensed under the LGPL license. See LICENSE file in the project root for full license information.
  // </copyright>
  
  namespace Allors.Database.Adapters.Memory
  {
      using System;
      using System.Collections.Generic;
      using System.Xml;
  
      using Adapters;
  
      using Allors.Meta;
  
      public class Load
      {
          private static readonly byte[] emptyByteArray = new byte[0];
  
          private readonly Session session;
          private readonly XmlReader reader;
  
          public Load(Session session, XmlReader reader)
          {
              this.session = session;
              this.reader = reader;
          }
  
          public void Execute()
          {
              while (this.reader.Read())
              {
                  // only process elements, ignore others
                  if (this.reader.NodeType.Equals(XmlNodeType.Element))
                  {
                      if (this.reader.Name.Equals(Serialization.Population))
                      {
                          var version = this.reader.GetAttribute(Serialization.Version);
                          if (string.IsNullOrEmpty(version))
                          {
                              throw new ArgumentException("Save population has no version.");
                          }
  
                          Serialization.CheckVersion(int.Parse(version));
  
                          if (!this.reader.IsEmptyElement)
                          {
                              this.LoadPopulation();
                          }
  
                          break;
                      }
                  }
              }
          }
  
          private void LoadPopulation()
          {
              while (this.reader.Read())
              {
                  switch (this.reader.NodeType)
                  {
                      // eat everything but elements
                      case XmlNodeType.Element:
                          if (this.reader.Name.Equals(Serialization.Objects))
                          {
                              if (!this.reader.IsEmptyElement)
                              {
                                  this.LoadObjects();
                              }
                          }
                          else if (this.reader.Name.Equals(Serialization.Relations))
                          {
                              if (!this.reader.IsEmptyElement)
                              {
                                  this.LoadRelations();
                              }
                          }
                          else
                          {
                              throw new Exception("Unknown child element <" + this.reader.Name + "> in parent element <" + Serialization.Population + ">");
                          }
  
                          break;
  
                      case XmlNodeType.EndElement:
                          if (!this.reader.Name.Equals(Serialization.Population))
                          {
                              throw new Exception("Expected closing element </" + Serialization.Population + ">");
                          }
  
                          return;
                  }
              }
          }
  
          private void LoadObjects()
          {
              while (this.reader.Read())
              {
                  switch (this.reader.NodeType)
                  {
                      case XmlNodeType.Element:
                          if (this.reader.Name.Equals(Serialization.Database))
                          {
                              if (!this.reader.IsEmptyElement)
                              {
                                  this.LoadObjectTypes();
                              }
                          }
                          else if (this.reader.Name.Equals(Serialization.Workspace))
                          {
                              throw new Exception("Can not load workspace objects in a database.");
                          }
                          else
                          {
                              throw new Exception("Unknown child element <" + this.reader.Name + "> in parent element <" + Serialization.Objects + ">");
                          }
  
                          break;
  
                      case XmlNodeType.EndElement:
                          if (!this.reader.Name.Equals(Serialization.Objects))
                          {
                              throw new Exception("Expected closing element </" + Serialization.Objects + ">");
                          }
  
                          return;
                  }
              }
          }
  
          private void LoadObjectTypes()
          {
              var skip = false;
              while (skip || this.reader.Read())
              {
                  skip = false;
  
                  switch (this.reader.NodeType)
                  {
                      // eat everything but elements
                      case XmlNodeType.Element:
                          if (this.reader.Name.Equals(Serialization.ObjectType))
                          {
                              if (!this.reader.IsEmptyElement)
                              {
                                  var objectTypeIdString = this.reader.GetAttribute(Serialization.Id);
                                  if (string.IsNullOrEmpty(objectTypeIdString))
                                  {
                                      throw new Exception("object type has no id");
                                  }
  
                                  var objectTypeId = new Guid(objectTypeIdString);
                                  var objectType = this.session.Database.ObjectFactory.GetObjectTypeForType(objectTypeId);
  
                                  var objectIdsString = this.reader.ReadElementContentAsString();
                                  var objectIdStringArray = objectIdsString.Split(Serialization.ObjectsSplitterCharArray);
  
                                  foreach (var objectIdString in objectIdStringArray)
                                  {
                                      var objectArray = objectIdString.Split(Serialization.ObjectSplitterCharArray);
  
                                      var objectId = long.Parse(objectArray[0]);
                                      var objectVersion = objectArray.Length > 1
                                          ? long.Parse(objectArray[1])
                                          : Database.IntialVersion;
  
                                      if (objectType is IClass)
                                      {
                                          this.session.InsertStrategy((IClass)objectType, objectId, objectVersion);
                                      }
                                      else
                                      {
                                          this.session.MemoryDatabase.OnObjectNotLoaded(objectTypeId, objectId);
                                      }
                                  }
  
                                  skip = this.reader.IsStartElement() ||
                                         (this.reader.NodeType == XmlNodeType.EndElement && this.reader.Name.Equals(Serialization.Database));
                              }
                          }
                          else
                          {
                              throw new Exception("Unknown child element <" + this.reader.Name + "> in parent element <" +
                                                  Serialization.Database + ">");
                          }
  
                          break;
  
                      case XmlNodeType.EndElement:
                          if (!this.reader.Name.Equals(Serialization.Database))
                          {
                              throw new Exception("Expected closing element </" + Serialization.Database + ">");
                          }
  
                          return;
                  }
              }
          }
  
          private void LoadRelations()
          {
              while (this.reader.Read())
              {
                  switch (this.reader.NodeType)
                  {
                      case XmlNodeType.Element:
                          if (this.reader.Name.Equals(Serialization.Database))
                          {
                              if (!this.reader.IsEmptyElement)
                              {
                                  this.LoadDatabaseRelationTypes();
                              }
                          }
                          else if (this.reader.Name.Equals(Serialization.Workspace))
                          {
                              throw new Exception("Can not load workspace relations in a database.");
                          }
                          else
                          {
                              throw new Exception("Unknown child element <" + this.reader.Name + "> in parent element <" + Serialization.Relations + ">");
                          }
  
                          break;
  
                      case XmlNodeType.EndElement:
                          if (!this.reader.Name.Equals(Serialization.Relations))
                          {
                              throw new Exception("Expected closing element </" + Serialization.Relations + ">");
                          }
  
                          return;
                  }
              }
          }
  
          private void LoadDatabaseRelationTypes()
          {
              while (this.reader.Read())
              {
                  switch (this.reader.NodeType)
                  {
                      // eat everything but elements
                      case XmlNodeType.Element:
                          if (!this.reader.IsEmptyElement)
                          {
                              if (this.reader.Name.Equals(Serialization.RelationTypeUnit)
                                  || this.reader.Name.Equals(Serialization.RelationTypeComposite))
                              {
                                  var relationTypeIdString = this.reader.GetAttribute(Serialization.Id);
                                  if (string.IsNullOrEmpty(relationTypeIdString))
                                  {
                                      throw new Exception("Relation type has no id");
                                  }
  
  
gt:                                 var relationTypeId = new Guid(relationTypeIdString);