context: using System;
  using System.Collections.Generic;
  using System.Collections.ObjectModel;
  using System.Linq;
  
  using ACE.Database.Models.Shard;
  using ACE.Entity.Enum;
  using ACE.Entity.Enum.Properties;
  using ACE.Entity.Models;
  
  namespace ACE.Database.Adapter
  {
      public static class BiotaConverter
      {
          public static ACE.Entity.Models.Biota ConvertToEntityBiota(ACE.Database.Models.Shard.Biota biota, bool instantiateEmptyCollections = false)
          {
              var result = new ACE.Entity.Models.Biota();
  
              result.Id = biota.Id;
              result.WeenieClassId = biota.WeenieClassId;
              result.WeenieType = (WeenieType)biota.WeenieType;
  
              if (biota.BiotaPropertiesBool != null && (instantiateEmptyCollections || biota.BiotaPropertiesBool.Count > 0))
              {
                  result.PropertiesBool = new Dictionary<PropertyBool, bool>(biota.BiotaPropertiesBool.Count);
                  foreach (var value in biota.BiotaPropertiesBool)
                      result.PropertiesBool[(PropertyBool)value.Type] = value.Value;
              }
              if (biota.BiotaPropertiesDID != null && (instantiateEmptyCollections || biota.BiotaPropertiesDID.Count > 0))
              {
                  result.PropertiesDID = new Dictionary<PropertyDataId, uint>(biota.BiotaPropertiesDID.Count);
                  foreach (var value in biota.BiotaPropertiesDID)
                      result.PropertiesDID[(PropertyDataId)value.Type] = value.Value;
              }
              if (biota.BiotaPropertiesFloat != null && (instantiateEmptyCollections || biota.BiotaPropertiesFloat.Count > 0))
              {
                  result.PropertiesFloat = new Dictionary<PropertyFloat, double>(biota.BiotaPropertiesFloat.Count);
                  foreach (var value in biota.BiotaPropertiesFloat)
                      result.PropertiesFloat[(PropertyFloat)value.Type] = value.Value;
              }
              if (biota.BiotaPropertiesIID != null && (instantiateEmptyCollections || biota.BiotaPropertiesIID.Count > 0))
              {
                  result.PropertiesIID = new Dictionary<PropertyInstanceId, uint>(biota.BiotaPropertiesIID.Count);
                  foreach (var value in biota.BiotaPropertiesIID)
                      result.PropertiesIID[(PropertyInstanceId)value.Type] = value.Value;
              }
              if (biota.BiotaPropertiesInt != null && (instantiateEmptyCollections || biota.BiotaPropertiesInt.Count > 0))
              {
                  result.PropertiesInt = new Dictionary<PropertyInt, int>(biota.BiotaPropertiesInt.Count);
                  foreach (var value in biota.BiotaPropertiesInt)
                      result.PropertiesInt[(PropertyInt)value.Type] = value.Value;
              }
              if (biota.BiotaPropertiesInt64 != null && (instantiateEmptyCollections || biota.BiotaPropertiesInt64.Count > 0))
              {
                  result.PropertiesInt64 = new Dictionary<PropertyInt64, long>(biota.BiotaPropertiesInt64.Count);
                  foreach (var value in biota.BiotaPropertiesInt64)
                      result.PropertiesInt64[(PropertyInt64)value.Type] = value.Value;
              }
              if (biota.BiotaPropertiesString != null && (instantiateEmptyCollections || biota.BiotaPropertiesString.Count > 0))
              {
                  result.PropertiesString = new Dictionary<PropertyString, string>(biota.BiotaPropertiesString.Count);
                  foreach (var value in biota.BiotaPropertiesString)
                      result.PropertiesString[(PropertyString)value.Type] = value.Value;
              }
  
  
              if (biota.BiotaPropertiesPosition != null && (instantiateEmptyCollections || biota.BiotaPropertiesPosition.Count > 0))
              {
                  result.PropertiesPosition = new Dictionary<PositionType, PropertiesPosition>(biota.BiotaPropertiesPosition.Count);
  
                  foreach (var record in biota.BiotaPropertiesPosition)
                  {
                      var newEntity = new PropertiesPosition
                      {
                          ObjCellId = record.ObjCellId,
                          PositionX = record.OriginX,
                          PositionY = record.OriginY,
                          PositionZ = record.OriginZ,
                          RotationW = record.AnglesW,
                          RotationX = record.AnglesX,
                          RotationY = record.AnglesY,
                          RotationZ = record.AnglesZ,
  
                      };
  
                      result.PropertiesPosition[(PositionType)record.PositionType] = newEntity;
                  }
              }
  
  
              if (biota.BiotaPropertiesSpellBook != null && (instantiateEmptyCollections || biota.BiotaPropertiesSpellBook.Count > 0))
              {
                  result.PropertiesSpellBook = new Dictionary<int, float>(biota.BiotaPropertiesSpellBook.Count);
                  foreach (var value in biota.BiotaPropertiesSpellBook)
                      result.PropertiesSpellBook[value.Spell] = value.Probability;
              }
  
  
              if (biota.BiotaPropertiesAnimPart != null && (instantiateEmptyCollections || biota.BiotaPropertiesAnimPart.Count > 0))
              {
                  result.PropertiesAnimPart = new List<PropertiesAnimPart>(biota.BiotaPropertiesAnimPart.Count);
  
                  foreach (var record in biota.BiotaPropertiesAnimPart.OrderBy(r => r.Order))
                  {
                      var newEntity = new PropertiesAnimPart
                      {
                          Index = record.Index,
                          AnimationId = record.AnimationId,
                      };
  
                      result.PropertiesAnimPart.Add(newEntity);
                  }
              }
  
              if (biota.BiotaPropertiesPalette != null && (instantiateEmptyCollections || biota.BiotaPropertiesPalette.Count > 0))
              {
                  result.PropertiesPalette = new Collection<PropertiesPalette>();
  
                  foreach (var record in biota.BiotaPropertiesPalette.OrderBy(r => r.Order))
                  {
                      var newEntity = new PropertiesPalette
                      {
                          SubPaletteId = record.SubPaletteId,
                          Offset = record.Offset,
                          Length = record.Length,
                      };
  
                      result.PropertiesPalette.Add(newEntity);
                  }
              }
  
              if (biota.BiotaPropertiesTextureMap != null && (instantiateEmptyCollections || biota.BiotaPropertiesTextureMap.Count > 0))
              {
                  result.PropertiesTextureMap = new List<PropertiesTextureMap>(biota.BiotaPropertiesTextureMap.Count);
  
                  foreach (var record in biota.BiotaPropertiesTextureMap.OrderBy(r => r.Order))
                  {
                      var newEntity = new PropertiesTextureMap
                      {
                          PartIndex = record.Index,
                          OldTexture = record.OldId,
                          NewTexture = record.NewId,
                      };
  
                      result.PropertiesTextureMap.Add(newEntity);
                  }
              }
  
  
              // Properties for all world objects that typically aren't modified over the original Biota
  
              if (biota.BiotaPropertiesCreateList != null && (instantiateEmptyCollections || biota.BiotaPropertiesCreateList.Count > 0))
              {
                  result.PropertiesCreateList = new Collection<PropertiesCreateList>();
  
                  foreach (var record in biota.BiotaPropertiesCreateList)
                  {
                      var newEntity = new PropertiesCreateList
                      {
                          DatabaseRecordId = record.Id,
  
                          DestinationType = (DestinationType)record.DestinationType,
                          WeenieClassId = record.WeenieClassId,
                          StackSize = record.StackSize,
                          Palette = record.Palette,
                          Shade = record.Shade,
                          TryToBond = record.TryToBond,
                      };
  
                      result.PropertiesCreateList.Add(newEntity);
                  }
              }
  
              if (biota.BiotaPropertiesEmote != null && (instantiateEmptyCollections || biota.BiotaPropertiesEmote.Count > 0))
              {
                  result.PropertiesEmote = new Collection<PropertiesEmote>();
  
                  foreach (var record in biota.BiotaPropertiesEmote)
                  {
                      var newEntity = new PropertiesEmote
                      {
                          DatabaseRecordId = record.Id,
  
                          Category = (EmoteCategory)record.Category,
                          Probability = record.Probability,
                          WeenieClassId = record.WeenieClassId,
                          Style = (MotionStance?)record.Style,
                          Substyle = (MotionCommand?)record.Substyle,
                          Quest = record.Quest,
                          VendorType = (VendorType?)record.VendorType,
                          MinHealth = record.MinHealth,
                          MaxHealth = record.MaxHealth,
                      };
  
                      foreach (var record2 in record.BiotaPropertiesEmoteAction.OrderBy(r => r.Order))
                      {
                          var newEntity2 = new PropertiesEmoteAction
                          {
                              DatabaseRecordId = record2.Id,
  
                              Type = record2.Type,
                              Delay = record2.Delay,
                              Extent = record2.Extent,
                              Motion = (MotionCommand?)record2.Motion,
                              Message = record2.Message,
                              TestString = record2.TestString,
                              Min = record2.Min,
                              Max = record2.Max,
                              Min64 = record2.Min64,
                              Max64 = record2.Max64,
                              MinDbl = record2.MinDbl,
                              MaxDbl = record2.MaxDbl,
                              Stat = record2.Stat,
                              Display = record2.Display,
                              Amount = record2.Amount,
                              Amount64 = record2.Amount64,
                              HeroXP64 = record2.HeroXP64,
                              Percent = record2.Percent,
                              SpellId = record2.SpellId,
                              WealthRating = record2.WealthRating,
                              TreasureClass = record2.TreasureClass,
                              TreasureType = record2.TreasureType,
                              PScript = (PlayScript?)record2.PScript,
                              Sound = (Sound?)record2.Sound,
                              DestinationType = record2.DestinationType,
                              WeenieClassId = record2.WeenieClassId,
                              StackSize = record2.StackSize,
                              Palette = record2.Palette,
                              Shade = record2.Shade,
                              TryToBond = record2.TryToBond,
                              ObjCellId = record2.ObjCellId,
                              OriginX = record2.OriginX,
                              OriginY = record2.OriginY,
                              OriginZ = record2.OriginZ,
                              AnglesW = record2.AnglesW,
                              AnglesX = record2.AnglesX,
                              AnglesY = record2.AnglesY,
                              AnglesZ = record2.AnglesZ,
                          };
  
                          newEntity.PropertiesEmoteAction.Add(newEntity2);
                      }
  
                      result.PropertiesEmote.Add(newEntity);
                  }
              }
  
              if (biota.BiotaPropertiesEventFilter != null && (instantiateEmptyCollections || biota.BiotaPropertiesEventFilter.Count > 0))
              {
                  result.PropertiesEventFilter = new HashSet<int>();
                  foreach (var value in biota.BiotaPropertiesEventFilter)
                      result.PropertiesEventFilter.Add(value.Event);
              }
  
              if (biota.BiotaPropertiesGenerator != null && (instantiateEmptyCollections || biota.BiotaPropertiesGenerator.Count > 0))
              {
                  result.PropertiesGenerator = new List<PropertiesGenerator>(biota.BiotaPropertiesGenerator.Count);
  
                  foreach (var record in biota.BiotaPropertiesGenerator) // TODO do we have the correct order?
                  {
                      var newEntity = new PropertiesGenerator
                      {
                          DatabaseRecordId = record.Id,
  
                          Probability = record.Probability,
                          WeenieClassId = record.WeenieClassId,
                          Delay = record.Delay,
                          InitCreate = record.InitCreate,
                          MaxCreate = record.MaxCreate,
                          WhenCreate = (RegenerationType)record.WhenCreate,
                          WhereCreate = (RegenLocationType)record.WhereCreate,
                          StackSize = record.StackSize,
                          PaletteId = record.PaletteId,
                          Shade = record.Shade,
                          ObjCellId = record.ObjCellId,
                          OriginX = record.OriginX,
                          OriginY = record.OriginY,
                          OriginZ = record.OriginZ,
                          AnglesW = record.AnglesW,
                          AnglesX = record.AnglesX,
                          AnglesY = record.AnglesY,
                          AnglesZ = record.AnglesZ,
                      };
  
                      result.PropertiesGenerator.Add(newEntity);
                  }
              }
  
  
              // Properties for creatures
  
              if (biota.BiotaPropertiesAttribute != null && (instantiateEmptyCollections || biota.BiotaPropertiesAttribute.Count > 0))
              {
                  result.PropertiesAttribute = new Dictionary<PropertyAttribute, PropertiesAttribute>(biota.BiotaPropertiesAttribute.Count);
  
                  foreach (var record in biota.BiotaPropertiesAttribute)
                  {
                      var newEntity = new PropertiesAttribute
                      {
                          InitLevel = record.InitLevel,
                          LevelFromCP = record.LevelFromCP,
                          CPSpent = record.CPSpent,
                      };
  
                      result.PropertiesAttribute[(PropertyAttribute)record.Type] = newEntity;
                  }
              }
  
              if (biota.BiotaPropertiesAttribute2nd != null && (instantiateEmptyCollections || biota.BiotaPropertiesAttribute2nd.Count > 0))
              {
                  result.PropertiesAttribute2nd = new Dictionary<PropertyAttribute2nd, PropertiesAttribute2nd>(biota.BiotaPropertiesAttribute2nd.Count);
  
                  foreach (var record in biota.BiotaPropertiesAttribute2nd)
                  {
                      var newEntity = new PropertiesAttribute2nd
                      {
                          InitLevel = record.InitLevel,
                          LevelFromCP = record.LevelFromCP,
                          CPSpent = record.CPSpent,
                          CurrentLevel = record.CurrentLevel,
                      };
  
                      result.PropertiesAttribute2nd[(PropertyAttribute2nd)record.Type] = newEntity;
                  }
              }
  
              if (biota.BiotaPropertiesBodyPart != null && (instantiateEmptyCollections || biota.BiotaPropertiesBodyPart.Count > 0))
              {
                  result.PropertiesBodyPart = new Dictionary<CombatBodyPart, PropertiesBodyPart>(biota.BiotaPropertiesBodyPart.Count);
  
                  foreach (var record in biota.BiotaPropertiesBodyPart)
                  {
                      var newEntity = new PropertiesBodyPart
                      {
                          DType = (DamageType)record.DType,
                          DVal = record.DVal,
                          DVar = record.DVar,
                          BaseArmor = record.BaseArmor,
                          ArmorVsSlash = record.ArmorVsSlash,
                          ArmorVsPierce = record.ArmorVsPierce,
                          ArmorVsBludgeon = record.ArmorVsBludgeon,
                          ArmorVsCold = record.ArmorVsCold,
                          ArmorVsFire = record.ArmorVsFire,
                          ArmorVsAcid = record.ArmorVsAcid,
                          ArmorVsElectric = record.ArmorVsElectric,
                          ArmorVsNether = record.ArmorVsNether,
                          BH = record.BH,
                          HLF = record.HLF,
                          MLF = record.MLF,
                          LLF = record.LLF,
                          HRF = record.HRF,
                          MRF = record.MRF,
                          LRF = record.LRF,
                          HLB = record.HLB,
                          MLB = record.MLB,
                          LLB = record.LLB,
                          HRB = record.HRB,
                          MRB = record.MRB,
                          LRB = record.LRB,
                      };
  
                      result.PropertiesBodyPart[(CombatBodyPart)record.Key] = newEntity;
                  }
              }
  
              if (biota.BiotaPropertiesSkill != null && (instantiateEmptyCollections || biota.BiotaPropertiesSkill.Count > 0))
              {
                  result.PropertiesSkill = new Dictionary<Skill, PropertiesSkill>(biota.BiotaPropertiesSkill.Count);
  
                  foreach (var record in biota.BiotaPropertiesSkill)
                  {
                      var newEntity = new PropertiesSkill
                      {
                          LevelFromPP = record.LevelFromPP,
                          SAC = (SkillAdvancementClass)record.SAC,
                          PP = record.PP,
                          InitLevel = record.InitLevel,
                          ResistanceAtLastCheck = record.ResistanceAtLastCheck,
                          LastUsedTime = record.LastUsedTime,
                      };
  
                      result.PropertiesSkill[(Skill)record.Type] = newEntity;
                  }
              }
  
  
              // Properties for books
  
              if (biota.BiotaPropertiesBook != null)
              {
                  result.PropertiesBook = new PropertiesBook
                  {
                      MaxNumPages = biota.BiotaPropertiesBook.MaxNumPages,
                      MaxNumCharsPerPage = biota.BiotaPropertiesBook.MaxNumCharsPerPage,
                  };
              }
  
              if (biota.BiotaPropertiesBookPageData != null && (instantiateEmptyCollections || biota.BiotaPropertiesBookPageData.Count > 0))
              {
                  result.PropertiesBookPageData = new List<PropertiesBookPageData>(biota.BiotaPropertiesBookPageData.Count);
  
                  foreach (var record in biota.BiotaPropertiesBookPageData.OrderBy(r => r.PageId))
                  {
                      var newEntity = new PropertiesBookPageData
                      {
                          AuthorId = record.AuthorId,
                          AuthorName = record.AuthorName,
                          AuthorAccount = record.AuthorAccount,
                          IgnoreAuthor = record.IgnoreAuthor,
                          PageText = record.PageText,
                      };
  
                      result.PropertiesBookPageData.Add(newEntity);
                  }
              }
  
  
              // Biota additions over Weenie
  
              if (biota.BiotaPropertiesAllegiance != null && (instantiateEmptyCollections || biota.BiotaPropertiesAllegiance.Count > 0))
              {
                  result.PropertiesAllegiance = new Dictionary<uint, PropertiesAllegiance>(biota.BiotaPropertiesAllegiance.Count);
  
                  foreach (var record in biota.BiotaPropertiesAllegiance)
                  {
                      var newEntity = new PropertiesAllegiance
                      {
                          Banned = record.Banned,
                          ApprovedVassal = record.ApprovedVassal,
                      };
  
                      result.PropertiesAllegiance[record.CharacterId] = newEntity;
                  }
              }
  
              if (biota.BiotaPropertiesEnchantmentRegistry != null && (instantiateEmptyCollections || biota.BiotaPropertiesEnchantmentRegistry.Count > 0))
              {
                  result.PropertiesEnchantmentRegistry = new Collection<PropertiesEnchantmentRegistry>();
  
                  foreach (var record in biota.BiotaPropertiesEnchantmentRegistry)
                  {
                      var newEntity = new PropertiesEnchantmentRegistry
                      {
                          EnchantmentCategory = record.EnchantmentCategory,
                          SpellId = record.SpellId,
                          LayerId = record.LayerId,
                          HasSpellSetId = record.HasSpellSetId,
                          SpellCategory = (SpellCategory)record.SpellCategory,
                          PowerLevel = record.PowerLevel,
                          StartTime = record.StartTime,
                          Duration = record.Duration,
                          CasterObjectId = record.CasterObjectId,
                          DegradeModifier = record.DegradeModifier,
                          DegradeLimit = record.DegradeLimit,
                          LastTimeDegraded = record.LastTimeDegraded,
                          StatModType = (EnchantmentTypeFlags)record.StatModType,
                          StatModKey = record.StatModKey,
                          StatModValue = record.StatModValue,
                          SpellSetId = (EquipmentSet)record.SpellSetId,
                      };
  
                      result.PropertiesEnchantmentRegistry.Add(newEntity);
                  }
              }
  
              if (biota.HousePermission != null && (instantiateEmptyCollections || biota.HousePermission.Count > 0))
              {
                  result.HousePermissions = new Dictionary<uint, bool>(biota.HousePermission.Count);
  
                  foreach (var record in biota.HousePermission)
                      result.HousePermissions[record.PlayerGuid] = record.Storage;
              }
  
  
              return result;
          }
  
          public static ACE.Database.Models.Shard.Biota ConvertFromEntityBiota(ACE.Entity.Models.Biota biota, bool includeDatabaseRecordIds = false)
          {
              var result = new ACE.Database.Models.Shard.Biota();
  
              result.Id = biota.Id;
              result.WeenieClassId = biota.WeenieClassId;
              result.WeenieType = (int)biota.WeenieType;
  
  
              if (biota.PropertiesBool != null)
              {
                  foreach (var kvp in biota.PropertiesBool)
                      result.SetProperty(kvp.Key, kvp.Value);
              }
              if (biota.PropertiesDID != null)
              {
                  foreach (var kvp in biota.PropertiesDID)
                      result.SetProperty(kvp.Key, kvp.Value);
              }
              if (biota.PropertiesFloat != null)
              {
                  foreach (var kvp in biota.PropertiesFloat)
                      result.SetProperty(kvp.Key, kvp.Value);
              }
              if (biota.PropertiesIID != null)
              {
                  foreach (var kvp in biota.PropertiesIID)
                      result.SetProperty(kvp.Key, kvp.Value);
              }
              if (biota.PropertiesInt != null)
              {
                  foreach (var kvp in biota.PropertiesInt)
                      result.SetProperty(kvp.Key, kvp.Value);
              }
              if (biota.PropertiesInt64 != null)
              {
                  foreach (var kvp in biota.PropertiesInt64)
                      result.SetProperty(kvp.Key, kvp.Value);
              }
              if (biota.PropertiesString != null)
              {
                  foreach (var kvp in biota.PropertiesString)
                      result.SetProperty(kvp.Key, kvp.Value);
              }
   
  
              if (biota.PropertiesPosition != null)
              {
                  foreach (var kvp in biota.PropertiesPosition)
                  {
                      var entity = new BiotaPropertiesPosition { ObjectId = biota.Id, PositionType = (ushort)kvp.Key, ObjCellId = kvp.Value.ObjCellId, OriginX = kvp.Value.PositionX, OriginY = kvp.Value.PositionY, OriginZ = kvp.Value.PositionZ, AnglesW = kvp.Value.RotationW, AnglesX = kvp.Value.RotationX, AnglesY = kvp.Value.RotationY, AnglesZ = kvp.Value.RotationZ };
  
                      result.BiotaPropertiesPosition.Add(entity);
                  }
              }
  
  
              if (biota.PropertiesSpellBook != null)
              {
                  foreach (var kvp in biota.PropertiesSpellBook)
                  {
                      var entity = new BiotaPropertiesSpellBook { ObjectId = biota.Id, Spell = kvp.Key, Probability = kvp.Value };
  
                      result.BiotaPropertiesSpellBook.Add(entity);
                  }
              }
  
  
              if (biota.PropertiesAnimPart != null)
              {
                  for (int i = 0; i < biota.PropertiesAnimPart.Count; i++)
                  {
  
gt:                     var value = biota.PropertiesAnimPart[i];