public override async Task GenerateWrapperFields(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration typeGen,
            Accessor dataAccessor,
            int?passedLength,
            string passedLengthAccessor,
            DataType data = null)
        {
            DictType dict = typeGen as DictType;

            if (GetDictType(dict) != DictBinaryType.EnumMap)
            {
                // Special case for Groups
                return;
            }

            if (!this.Module.TryGetTypeGeneration(dict.ValueTypeGen.GetType(), out var subTransl))
            {
                throw new ArgumentException("Unsupported type generator: " + dict.ValueTypeGen);
            }

            var posStr = data == null ? passedLengthAccessor : $"_{typeGen.Name}Location";

            if (data != null)
            {
                DataBinaryTranslationGeneration.GenerateWrapperExtraMembers(fg, data, objGen, typeGen, passedLengthAccessor);
            }

            using (var args = new ArgsWrapper(fg,
                                              $"public IReadOnlyDictionary<{dict.KeyTypeGen.TypeName(getter: true)}, {dict.ValueTypeGen.TypeName(getter: true)}> {typeGen.Name} => DictBinaryTranslation<{dict.ValueTypeGen.TypeName(getter: false)}>.Instance.Parse<{dict.KeyTypeGen.TypeName(false)}>"))
            {
                args.Add($"new {nameof(MutagenFrame)}(new {nameof(MutagenMemoryReadStream)}({dataAccessor}{(posStr == null ? null : $".Slice({posStr})")}, _package.{nameof(BinaryOverlayFactoryPackage.MetaData)}))");
        public async Task GenerateForCustomFlagWrapperFields(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration typeGen,
            Accessor dataAccessor,
            int?currentPosition,
            string passedLenAccessor,
            DataType dataType = null)
        {
            var    fieldData = typeGen.GetFieldData();
            var    gen       = this.Module.GetTypeGeneration(typeGen.GetType());
            string loc;

            if (fieldData.HasTrigger)
            {
                using (var args = new ArgsWrapper(fg,
                                                  $"partial void {typeGen.Name}CustomParse"))
                {
                    args.Add($"{nameof(OverlayStream)} stream");
                    args.Add($"long finalPos");
                    args.Add($"int offset");
                }
                if (typeGen.Nullable && !typeGen.CanBeNullable(getter: true))
                {
                    fg.AppendLine($"public bool {typeGen.Name}_IsSet => Get{typeGen.Name}IsSetCustom();");
                }
                loc = $"_{typeGen.Name}Location.Value";
            }
            else if (dataType != null)
            {
                loc = $"_{typeGen.Name}Location";
                DataBinaryTranslationGeneration.GenerateWrapperExtraMembers(fg, dataType, objGen, typeGen, passedLenAccessor);
            }
            else
            {
                loc = passedLenAccessor;
            }
            using (var args = new ArgsWrapper(fg,
                                              $"public {typeGen.OverrideStr}{typeGen.TypeName(getter: true)}{(typeGen.IsNullable ? "?" : null)} {typeGen.Name} => Get{typeGen.Name}Custom"))
            {
                if (!fieldData.HasTrigger && dataType == null)
                {
                    args.Add($"location: {loc ?? "0x0"}");
                }
            }
            if (!fieldData.HasTrigger)
            {
                currentPosition += fieldData.Length ?? await gen.ExpectedLength(objGen, typeGen);
            }
        }
        public override async Task GenerateWrapperFields(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration typeGen,
            Accessor dataAccessor,
            int? currentPosition,
            string passedLengthAccessor,
            DataType dataType)
        {
            var eType = typeGen as EnumType;
            var data = typeGen.GetFieldData();
            var nullable = typeGen.Nullable && eType.NullableFallbackInt == null;
            switch (data.BinaryOverlayFallback)
            {
                case BinaryGenerationType.Normal:
                    break;
                case BinaryGenerationType.NoGeneration:
                    return;
                case BinaryGenerationType.Custom:
                    await this.Module.CustomLogic.GenerateForCustomFlagWrapperFields(
                        fg,
                        objGen,
                        typeGen,
                        dataAccessor,
                        currentPosition,
                        passedLengthAccessor,
                        dataType);
                    return;
                default:
                    throw new NotImplementedException();
            }

            if (dataType == null && data.HasVersioning && !typeGen.Nullable)
            {
                fg.AppendLine($"private bool _{typeGen.Name}_IsSet => {VersioningModule.GetVersionIfCheck(data, "_package.FormVersion!.FormVersion!.Value")};");
            }
            if (data.HasTrigger)
            {
                fg.AppendLine($"private int? _{typeGen.Name}Location;");
            }
            var posStr = dataType == null ? passedLengthAccessor : $"_{typeGen.Name}Location";
            string slice;
            if (data.RecordType.HasValue)
            {
                slice = $"{nameof(HeaderTranslation)}.{nameof(HeaderTranslation.ExtractSubrecordMemory)}({dataAccessor}, _{typeGen.Name}Location!.Value, _package.{nameof(BinaryOverlayFactoryPackage.MetaData)}.{nameof(ParsingBundle.Constants)})";
            }
            else
            {
                slice = $"{dataAccessor}.Span.Slice({posStr ?? "0x0"}, 0x{eType.ByteLength:X})";
            }
            var getType = GenerateForTypicalWrapper(objGen, typeGen, slice, "_package");

            if (dataType != null)
            {
                DataBinaryTranslationGeneration.GenerateWrapperExtraMembers(fg, dataType, objGen, typeGen, passedLengthAccessor);
            }

            bool isSetCheck = dataType != null || data.HasVersioning;

            if (eType.NullableFallbackInt != null)
            {
                fg.AppendLine($"public {eType.TypeName(getter: true)}? {eType.Name}");
                using (new BraceWrapper(fg))
                {
                    fg.AppendLine("get");
                    using (new BraceWrapper(fg))
                    {
                        fg.AppendLine($"var val = {getType};");
                        fg.AppendLine($"if (((int)val) == {eType.NullableFallbackInt}) return null;");
                        fg.AppendLine("return val;");
                    }
                }
            }
            else if (data.HasTrigger)
            {
                if (typeGen.CanBeNullable(getter: true))
                {
                    fg.AppendLine($"public {eType.TypeName(getter: true)}{(nullable ? "?" : null)} {eType.Name} => _{typeGen.Name}Location.HasValue ? {getType} : default({eType.TypeName(getter: true)}{(nullable ? "?" : null)});");
                }
                else
                {
                    fg.AppendLine($"public {eType.TypeName(getter: true)} {eType.Name} => {getType};");
                }
            }
            else
            {
                if (!isSetCheck)
                {
                    fg.AppendLine($"public {eType.TypeName(getter: true)} {eType.Name} => {getType};");
                }
                else
                {
                    fg.AppendLine($"public {eType.TypeName(getter: true)} {eType.Name} => _{typeGen.Name}_IsSet ? {getType} : default;");
                }
            }

        }
        public override async Task GenerateWrapperFields(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration typeGen,
            Accessor dataAccessor,
            int?currentPosition,
            string passedLengthAccessor,
            DataType dataType)
        {
            var data = typeGen.GetFieldData();

            switch (data.BinaryOverlayFallback)
            {
            case BinaryGenerationType.Normal:
                break;

            case BinaryGenerationType.NoGeneration:
                return;

            case BinaryGenerationType.Custom:
                await this.Module.CustomLogic.GenerateForCustomFlagWrapperFields(
                    fg,
                    objGen,
                    typeGen,
                    dataAccessor,
                    currentPosition,
                    passedLengthAccessor,
                    dataType);

                return;

            default:
                throw new NotImplementedException();
            }
            if (data.HasTrigger)
            {
                fg.AppendLine($"private int? _{typeGen.Name}Location;");
                if (typeGen.CanBeNullable(getter: true))
                {
                    dataAccessor = $"{nameof(HeaderTranslation)}.{nameof(HeaderTranslation.ExtractSubrecordMemory)}({dataAccessor}, _{typeGen.Name}Location.Value, _package.{nameof(BinaryOverlayFactoryPackage.MetaData)}.{nameof(ParsingBundle.Constants)})";
                    fg.AppendLine($"public {typeGen.TypeName(getter: true)}{(typeGen.Nullable ? "?" : null)} {typeGen.Name} => _{typeGen.Name}Location.HasValue ? {dataAccessor}[0] : default(Byte{(typeGen.Nullable ? "?" : null)});");
                }
                else
                {
                    fg.AppendLine($"public bool {typeGen.Name}_IsSet => _{typeGen.Name}Location.HasValue;");
                    if (dataType != null)
                    {
                        throw new ArgumentException();
                    }
                    dataAccessor = $"{nameof(HeaderTranslation)}.{nameof(HeaderTranslation.ExtractSubrecordMemory)}({dataAccessor}, _{typeGen.Name}Location.Value, _package.{nameof(BinaryOverlayFactoryPackage.MetaData)}.{nameof(ParsingBundle.Constants)})";
                    fg.AppendLine($"public {typeGen.TypeName(getter: true)} {typeGen.Name} => _{typeGen.Name}Location.HasValue ? {dataAccessor}[0] : default(Byte{(typeGen.Nullable ? "?" : null)});");
                }
            }
            else
            {
                if (dataType == null)
                {
                    fg.AppendLine($"public {typeGen.TypeName(getter: true)} {typeGen.Name} => {dataAccessor}.Span[{passedLengthAccessor ?? "0x0"}];");
                }
                else
                {
                    DataBinaryTranslationGeneration.GenerateWrapperExtraMembers(fg, dataType, objGen, typeGen, passedLengthAccessor);
                    fg.AppendLine($"public {typeGen.TypeName(getter: true)} {typeGen.Name} => _{typeGen.Name}_IsSet ? {dataAccessor}.Span[_{typeGen.Name}Location] : default;");
                }
            }
        }
        public override async Task GenerateWrapperFields(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration typeGen,
            Accessor dataAccessor,
            int?currentPosition,
            string passedLengthAccessor,
            DataType dataType)
        {
            LoquiType loqui = typeGen as LoquiType;
            var       data  = typeGen.GetFieldData();

            switch (data.BinaryOverlayFallback)
            {
            case BinaryGenerationType.Normal:
                break;

            case BinaryGenerationType.NoGeneration:
                return;

            case BinaryGenerationType.Custom:
                await this.Module.CustomLogic.GenerateForCustomFlagWrapperFields(
                    fg,
                    objGen,
                    typeGen,
                    dataAccessor,
                    currentPosition,
                    passedLengthAccessor,
                    dataType);

                return;

            default:
                throw new NotImplementedException();
            }

            string DataAccessor(Accessor accessor, string positionStr, string lenStr)
            {
                if (objGen.GetObjectType() == ObjectType.Mod)
                {
                    return($"{nameof(PluginBinaryOverlay)}.{nameof(PluginBinaryOverlay.LockExtractMemory)}({accessor}, {positionStr}, {lenStr})");
                }
                else
                {
                    return($"{accessor}.Slice({positionStr})");
                }
            }

            string recConverter = $"default({nameof(RecordTypeConverter)})";

            if (loqui.GetFieldData()?.RecordTypeConverter != null &&
                loqui.GetFieldData().RecordTypeConverter.FromConversions.Count > 0)
            {
                recConverter = $"{objGen.RegistrationName}.{loqui.Name}Converter";
            }

            var isRequiredRecord = !loqui.Nullable && data.HasTrigger;

            if (dataType == null)
            {
                if (loqui.GetFieldData()?.HasTrigger ?? false)
                {
                    if (loqui.TargetObjectGeneration.IsTypelessStruct())
                    {
                        if (loqui.Singleton ||
                            isRequiredRecord)
                        {
                            fg.AppendLine($"private {loqui.Interface(getter: true, internalInterface: true)}? _{typeGen.Name};");
                        }
                        else if (loqui.Nullable)
                        {
                            fg.AppendLine($"public {loqui.Interface(getter: true, internalInterface: true)}? {typeGen.Name} {{ get; private set; }}");
                        }
                    }
                    else
                    {
                        var severalSubTypes = data.GenerationTypes
                                              .Select(i => i.Value)
                                              .WhereCastable <TypeGeneration, LoquiType>()
                                              .Where(loqui => !loqui?.TargetObjectGeneration?.Abstract ?? true)
                                              .CountGreaterThan(1);
                        if (severalSubTypes)
                        {
                            fg.AppendLine($"private {nameof(RecordType)} _{typeGen.Name}Type;");
                        }
                        fg.AppendLine($"private {GetLocationObjectString(objGen)}? _{typeGen.Name}Location;");
                        using (new LineWrapper(fg))
                        {
                            if (loqui.IsNullable)
                            {
                                fg.Append($"public ");
                            }
                            else
                            {
                                fg.Append($"private ");
                            }
                            fg.Append($"{loqui.Interface(getter: true, internalInterface: true)}{(typeGen.CanBeNullable(getter: true) ? "?" : null)} ");
                            if (!loqui.IsNullable ||
                                isRequiredRecord)
                            {
                                fg.Append("_");
                            }
                            fg.Append($"{typeGen.Name}");
                            if (!severalSubTypes)
                            {
                                fg.Append($" => _{typeGen.Name}Location.HasValue ? ");
                                fg.Append($"{this.Module.BinaryOverlayClassName(loqui)}.{loqui.TargetObjectGeneration.Name}Factory(new {nameof(OverlayStream)}({DataAccessor(dataAccessor, $"_{typeGen.Name}Location!.Value.Min", $"_{typeGen.Name}Location!.Value.Max")}, _package), _package");
                                if (!recConverter.StartsWith("default("))
                                {
                                    fg.Append($", {recConverter}");
                                }
                                fg.Append($") ");
                                fg.Append($": default;");
                            }
                        }
                        if (severalSubTypes)
                        {
                            using (new BraceWrapper(fg))
                            {
                                fg.AppendLine("get");
                                using (new BraceWrapper(fg))
                                {
                                    fg.AppendLine($"if (!_{typeGen.Name}Location.HasValue) return default;");
                                    fg.AppendLine($"switch (_{typeGen.Name}Type.TypeInt)");
                                    using (new BraceWrapper(fg))
                                    {
                                        foreach (var gen in data.GenerationTypes)
                                        {
                                            if (!(gen.Value is LoquiType subLoq))
                                            {
                                                continue;
                                            }
                                            if (subLoq?.TargetObjectGeneration?.Abstract ?? false)
                                            {
                                                continue;
                                            }
                                            foreach (var trigger in gen.Key)
                                            {
                                                fg.AppendLine($"case 0x{trigger.TypeInt.ToString("X")}: // {trigger.Type}");
                                            }
                                            using (new DepthWrapper(fg))
                                                using (new LineWrapper(fg))
                                                {
                                                    fg.Append($"return {this.Module.BinaryOverlayClassName(subLoq)}.{subLoq.TargetObjectGeneration.Name}Factory(new {nameof(OverlayStream)}({DataAccessor(dataAccessor, $"_{subLoq.Name}Location!.Value.Min", $"_{subLoq.Name}Location!.Value.Max")}, _package), _package");
                                                    if (!loqui.Singleton)
                                                    {
                                                        fg.Append($", {recConverter}");
                                                    }
                                                    fg.Append($");");
                                                }
                                        }
                                        fg.AppendLine("default:");
                                        using (new DepthWrapper(fg))
                                        {
                                            fg.AppendLine("throw new ArgumentException();");
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                else
                {
                    if (!loqui.Singleton)
                    {
                        fg.AppendLine($"public {loqui.Interface(getter: true, internalInterface: true)} {typeGen.Name} => {this.Module.BinaryOverlayClassName(loqui)}.{loqui.TargetObjectGeneration.Name}Factory(new {nameof(OverlayStream)}({dataAccessor}.Slice({passedLengthAccessor ?? "0x0"}), _package), _package, {recConverter});");
                    }
                    else
                    {
                        fg.AppendLine($"private {loqui.Interface(getter: true, internalInterface: true)} _{typeGen.Name} {{ get; private set; }}");
                    }
                }
            }
            else
            {
                isRequiredRecord = true;
                DataBinaryTranslationGeneration.GenerateWrapperExtraMembers(fg, dataType, objGen, typeGen, passedLengthAccessor);
                fg.AppendLine($"private {loqui.Interface(getter: true, internalInterface: true)}? _{typeGen.Name} => _{typeGen.Name}_IsSet ? {this.Module.BinaryOverlayClassName(loqui)}.{loqui.TargetObjectGeneration.Name}Factory(new {nameof(OverlayStream)}({DataAccessor(dataAccessor, $"_{typeGen.Name}Location", null)}, _package), _package) : default;");
            }

            if (loqui.Singleton ||
                isRequiredRecord)
            {
                fg.AppendLine($"public {loqui.Interface(getter: true, internalInterface: true)} {typeGen.Name} => _{typeGen.Name} ?? new {loqui.DirectTypeName}({(loqui.ThisConstruction ? "this" : null)});");
            }
        }
        public override async Task GenerateWrapperFields(
            FileGeneration fg,
            ObjectGeneration objGen,
            TypeGeneration typeGen,
            Accessor dataAccessor,
            int?currentPosition,
            string passedLengthAccessor,
            DataType dataType = null)
        {
            passedLengthAccessor ??= "0x0";
            var data = typeGen.GetFieldData();

            switch (data.BinaryOverlayFallback)
            {
            case BinaryGenerationType.Normal:
                break;

            case BinaryGenerationType.NoGeneration:
                return;

            case BinaryGenerationType.Custom:
                await this.Module.CustomLogic.GenerateForCustomFlagWrapperFields(
                    fg,
                    objGen,
                    typeGen,
                    dataAccessor,
                    currentPosition,
                    passedLengthAccessor,
                    dataType);

                return;

            default:
                throw new NotImplementedException();
            }
            if (data.HasTrigger)
            {
                fg.AppendLine($"private int? _{typeGen.Name}Location;");
            }
            if (data.RecordType.HasValue)
            {
                if (dataType != null)
                {
                    throw new ArgumentException();
                }
                dataAccessor = $"{nameof(HeaderTranslation)}.{nameof(HeaderTranslation.ExtractSubrecordMemory)}({dataAccessor}, _{typeGen.Name}Location.Value, _package.{nameof(BinaryOverlayFactoryPackage.MetaData)}.{nameof(ParsingBundle.Constants)})";
                fg.AppendLine($"public {typeGen.TypeName(getter: true)}{(typeGen.Nullable ? "?" : null)} {typeGen.Name} => _{typeGen.Name}Location.HasValue ? {GenerateForTypicalWrapper(objGen, typeGen, dataAccessor, "_package")} : {typeGen.GetDefault(getter: true)};");
            }
            else
            {
                var expectedLen = await this.ExpectedLength(objGen, typeGen);

                if (this.CustomWrapper != null)
                {
                    if (CustomWrapper(fg, objGen, typeGen, dataAccessor, passedLengthAccessor))
                    {
                        return;
                    }
                }
                if (dataType == null)
                {
                    if (typeGen.Nullable)
                    {
                        if (!typeGen.CanBeNullable(getter: true))
                        {
                            throw new NotImplementedException();
                            //fg.AppendLine($"public bool {typeGen.Name}_IsSet => {dataAccessor}.Length >= {(currentPosition + this.ExpectedLength(objGen, typeGen).Value)};");
                            //fg.AppendLine($"public {typeGen.TypeName(getter: true)} {typeGen.Name} => {GenerateForTypicalWrapper(objGen, typeGen, $"{dataAccessor}.Span.Slice({currentPosition}, {this.ExpectedLength(objGen, typeGen).Value})", "_package")};");
                        }
                        else
                        {
                            string passed = int.TryParse(passedLengthAccessor.TrimStart("0x"), System.Globalization.NumberStyles.HexNumber, null, out var passedInt) ? (passedInt + expectedLen.Value).ToString() : $"({passedLengthAccessor} + {expectedLen.Value})";
                            fg.AppendLine($"public {typeGen.TypeName(getter: true)}? {typeGen.Name} => {dataAccessor}.Length >= {passed} ? {GenerateForTypicalWrapper(objGen, typeGen, $"{dataAccessor}.Slice({passedLengthAccessor}{(expectedLen != null ? $", 0x{expectedLen.Value:X}" : null)})", "_package")} : {typeGen.GetDefault(getter: true)};");
                        }
                    }
                    else
                    {
                        fg.AppendLine($"public {typeGen.TypeName(getter: true)} {typeGen.Name} => {GenerateForTypicalWrapper(objGen, typeGen, $"{dataAccessor}.Slice({passedLengthAccessor ?? "0x0"}{(expectedLen != null ? $", 0x{expectedLen.Value:X}" : null)})", "_package")};");
                    }
                }
                else
                {
                    DataBinaryTranslationGeneration.GenerateWrapperExtraMembers(fg, dataType, objGen, typeGen, passedLengthAccessor);
                    fg.AppendLine($"public {typeGen.TypeName(getter: true)} {typeGen.Name} => _{typeGen.Name}_IsSet ? {GenerateForTypicalWrapper(objGen, typeGen, $"{dataAccessor}.Slice(_{typeGen.Name}Location{(expectedLen.HasValue ? $", {expectedLen.Value}" : null)})", "_package")} : {typeGen.GetDefault(getter: true)};");
                }
            }
        }