context: using System.Collections.Generic;
  using WowPacketParser.Enums;
  using WowPacketParser.Misc;
  using WowPacketParser.Parsing;
  using WowPacketParser.Store;
  using WowPacketParser.Store.Objects;
  using SpellCastFailureReason = WowPacketParser.Enums.Version.V6_1_0_19678.SpellCastFailureReason;
  
  namespace WowPacketParserModule.V6_0_2_19033.Parsers
  {
      public static class SpellHandler
      {
          public static void ReadSpellCastLogData(Packet packet, params object[] idx)
          {
              packet.ReadInt32("Health", idx);
              packet.ReadInt32("AttackPower", idx);
              packet.ReadInt32("SpellPower", idx);
  
              var int3 = packet.ReadInt32("SpellLogPowerData", idx);
  
              // SpellLogPowerData
              for (var i = 0; i < int3; ++i)
              {
                  packet.ReadInt32("PowerType", idx, i);
                  packet.ReadInt32("Amount", idx, i);
              }
  
              packet.ResetBitReader();
  
              var bit32 = packet.ReadBit("bit32", idx);
  
              if (bit32)
                  packet.ReadSingle("Float7", idx);
          }
  
          public static void ReadSpellTargetData(Packet packet, params object[] idx)
          {
              packet.ResetBitReader();
  
              packet.ReadBitsE<TargetFlag>("Flags", ClientVersion.AddedInVersion(ClientVersionBuild.V6_1_0_19678) ? 23 : 21, idx);
              var hasSrcLoc = packet.ReadBit("HasSrcLocation", idx);
              var hasDstLoc = packet.ReadBit("HasDstLocation", idx);
              var hasOrient = packet.ReadBit("HasOrientation", idx);
              var nameLength = packet.ReadBits(7);
  
              packet.ReadPackedGuid128("Unit", idx);
              packet.ReadPackedGuid128("Item", idx);
  
              if (hasSrcLoc)
                  ReadLocation(packet, "SrcLocation");
  
              if (hasDstLoc)
                  ReadLocation(packet, "DstLocation");
  
              if (hasOrient)
                  packet.ReadSingle("Orientation", idx);
  
              packet.ReadWoWString("Name", nameLength, idx);
          }
  
          public static void ReadMissileTrajectoryRequest(Packet packet, params object[] idx)
          {
              packet.ReadSingle("Pitch", idx);
              packet.ReadSingle("Speed", idx);
          }
  
          public static void ReadSpellWeight(Packet packet, params object[] idx)
          {
              packet.ResetBitReader();
              packet.ReadBits("Type", 2, idx); // Enum SpellweightTokenTypes
              packet.ReadInt32("ID", idx);
              packet.ReadInt32("Quantity", idx);
          }
  
          public static void ReadLocation(Packet packet, params object[] idx)
          {
              packet.ReadPackedGuid128("Transport", idx);
              packet.ReadVector3("Location", idx);
          }
  
          public static void ReadSpellPowerData(Packet packet, params object[] idx)
          {
              packet.ReadInt32("Cost", idx);
              packet.ReadByteE<PowerType>("Type", idx);
          }
  
          public static void ReadSpellCastRequest(Packet packet, params object[] idx)
          {
              packet.ReadByte("CastID", idx);
  
              if (ClientVersion.AddedInVersion(ClientVersionBuild.V6_2_0_20173))
              {
                  for (var i = 0; i < 2; i++)
                      packet.ReadInt32("Misc", idx, i);
              }
  
              packet.ReadInt32<SpellId>("SpellID", idx);
              packet.ReadInt32(ClientVersion.AddedInVersion(ClientVersionBuild.V6_2_0_20173) ? "SpellXSpellVisualID" : "Misc", idx);
  
              ReadSpellTargetData(packet, idx, "Target");
  
              ReadMissileTrajectoryRequest(packet, idx, "MissileTrajectory");
  
              packet.ReadPackedGuid128("Guid", idx);
  
              packet.ResetBitReader();
  
              packet.ReadBits("SendCastFlags", 5, idx);
              var hasMoveUpdate = packet.ReadBit("HasMoveUpdate", idx);
  
              var weightCount = packet.ReadBits("WeightCount", 2, idx);
  
              if (hasMoveUpdate)
                  MovementHandler.ReadMovementStats(packet, idx, "MoveUpdate");
  
              for (var i = 0; i < weightCount; ++i)
                  ReadSpellWeight(packet, idx, "Weight", i);
          }
  
          [Parser(Opcode.SMSG_LEARNED_SPELLS)]
          public static void HandleLearnedSpells(Packet packet)
          {
              var count = packet.ReadUInt32("Spell Count");
  
              for (var i = 0; i < count; ++i)
                  packet.ReadInt32<SpellId>("Spell ID", i);
              packet.ReadBit("SuppressMessaging");
          }
  
          [Parser(Opcode.SMSG_SEND_KNOWN_SPELLS)]
          public static void HandleInitialSpells(Packet packet)
          {
              packet.ReadBit("InitialLogin");
              var count = packet.ReadUInt32("Spell Count");
  
              for (var i = 0; i < count; i++)
              {
                  packet.ReadUInt32<SpellId>("Spell ID", i);
              }
          }
  
          [Parser(Opcode.SMSG_PET_CLEAR_SPELLS)]
          public static void HandleSpellZero(Packet packet)
          {
          }
  
          [Parser(Opcode.SMSG_CATEGORY_COOLDOWN)]
          public static void HandleSpellCategoryCooldown(Packet packet)
          {
              var count = packet.ReadUInt32("Spell Count");
  
              for (var i = 0; i < count; ++i)
              {
                  packet.ReadInt32("Category", i);
                  packet.ReadInt32("ModCooldown", i);
              }
          }
  
          [Parser(Opcode.SMSG_SET_PCT_SPELL_MODIFIER)]
          [Parser(Opcode.SMSG_SET_FLAT_SPELL_MODIFIER)]
          public static void HandleSetSpellModifierFlat(Packet packet)
          {
              var modCount = packet.ReadUInt32("Modifier type count");
  
              for (var j = 0; j < modCount; ++j)
              {
                  packet.ReadByteE<SpellModOp>("Spell Mod", j);
  
                  var modTypeCount = packet.ReadUInt32("Count", j);
                  for (var i = 0; i < modTypeCount; ++i)
                  {
                      packet.ReadSingle("Amount", j, i);
                      packet.ReadByte("Spell Mask bitpos", j, i);
                  }
              }
          }
  
          [HasSniffData]
          [Parser(Opcode.SMSG_AURA_UPDATE)]
          public static void HandleAuraUpdate(Packet packet)
          {
              packet.ReadBit("UpdateAll");
              var guid = packet.ReadPackedGuid128("UnitGUID");
              var count = packet.ReadUInt32("AurasCount");
  
              var auras = new List<Aura>();
              for (var i = 0; i < count; ++i)
              {
                  var aura = new Aura();
  
                  packet.ReadByte("Slot", i);
  
                  packet.ResetBitReader();
                  var hasAura = packet.ReadBit("HasAura", i);
                  if (hasAura)
                  {
                      aura.SpellId = (uint)packet.ReadInt32<SpellId>("SpellID", i);
                      if (ClientVersion.AddedInVersion(ClientVersionBuild.V6_2_0_20173))
                          packet.ReadUInt32("SpellXSpellVisualID", i);
                      aura.AuraFlags = packet.ReadByteE<AuraFlagMoP>("Flags", i);
                      packet.ReadInt32("ActiveFlags", i);
                      aura.Level = packet.ReadUInt16("CastLevel", i);
                      aura.Charges = packet.ReadByte("Applications", i);
  
                      var int72 = packet.ReadUInt32("Int56 Count", i);
                      var effectCount = packet.ReadUInt32("Effect Count", i);
  
                      for (var j = 0; j < int72; ++j)
                          packet.ReadSingle("Points", i, j);
  
                      for (var j = 0; j < effectCount; ++j)
                          packet.ReadSingle("EstimatedPoints", i, j);
  
                      packet.ResetBitReader();
                      var hasCasterGUID = packet.ReadBit("HasCastUnit", i);
                      var hasDuration = packet.ReadBit("HasDuration", i);
                      var hasMaxDuration = packet.ReadBit("HasRemaining", i);
  
                      if (hasCasterGUID)
                          packet.ReadPackedGuid128("CastUnit", i);
  
                      aura.Duration = hasDuration ? packet.ReadInt32("Duration", i) : 0;
                      aura.MaxDuration = hasMaxDuration ? packet.ReadInt32("Remaining", i) : 0;
  
                      auras.Add(aura);
                      packet.AddSniffData(StoreNameType.Spell, (int)aura.SpellId, "AURA_UPDATE");
                  }
              }
  
              if (Storage.Objects.ContainsKey(guid))
              {
                  var unit = Storage.Objects[guid].Item1 as Unit;
                  if (unit != null)
                  {
                      // If this is the first packet that sends auras
                      // (hopefully at spawn time) add it to the "Auras" field,
                      // if not create another row of auras in AddedAuras
                      // (similar to ChangedUpdateFields)
  
  
gt:                     if (unit.Auras == null)