/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package model

import (
	"context"
	stdErrors "errors"
	"fmt"

	"github.com/pkg/errors"
	"github.com/rs/zerolog"

	. "github.com/apache/plc4x/plc4go/spi/codegen/fields"
	. "github.com/apache/plc4x/plc4go/spi/codegen/io"
	"github.com/apache/plc4x/plc4go/spi/utils"
)

// Code generated by code-generation. DO NOT EDIT.

// Variant is the corresponding interface of Variant
type Variant interface {
	VariantContract
	VariantRequirements
	fmt.Stringer
	utils.LengthAware
	utils.Serializable
	utils.Copyable
	// IsVariant is a marker method to prevent unintentional type checks (interfaces of same signature)
	IsVariant()
	// CreateBuilder creates a VariantBuilder
	CreateVariantBuilder() VariantBuilder
}

// VariantContract provides a set of functions which can be overwritten by a sub struct
type VariantContract interface {
	// GetArrayLengthSpecified returns ArrayLengthSpecified (property field)
	GetArrayLengthSpecified() bool
	// GetArrayDimensionsSpecified returns ArrayDimensionsSpecified (property field)
	GetArrayDimensionsSpecified() bool
	// GetNoOfArrayDimensions returns NoOfArrayDimensions (property field)
	GetNoOfArrayDimensions() *int32
	// GetArrayDimensions returns ArrayDimensions (property field)
	GetArrayDimensions() []bool
	// IsVariant is a marker method to prevent unintentional type checks (interfaces of same signature)
	IsVariant()
	// CreateBuilder creates a VariantBuilder
	CreateVariantBuilder() VariantBuilder
}

// VariantRequirements provides a set of functions which need to be implemented by a sub struct
type VariantRequirements interface {
	GetLengthInBits(ctx context.Context) uint16
	GetLengthInBytes(ctx context.Context) uint16
	// GetVariantType returns VariantType (discriminator field)
	GetVariantType() uint8
	// GetArrayLengthSpecified returns ArrayLengthSpecified (discriminator field)
	GetArrayLengthSpecified() bool
}

// _Variant is the data-structure of this message
type _Variant struct {
	_SubType interface {
		VariantContract
		VariantRequirements
	}
	ArrayLengthSpecified     bool
	ArrayDimensionsSpecified bool
	NoOfArrayDimensions      *int32
	ArrayDimensions          []bool
}

var _ VariantContract = (*_Variant)(nil)

// NewVariant factory function for _Variant
func NewVariant(arrayLengthSpecified bool, arrayDimensionsSpecified bool, noOfArrayDimensions *int32, arrayDimensions []bool) *_Variant {
	return &_Variant{ArrayLengthSpecified: arrayLengthSpecified, ArrayDimensionsSpecified: arrayDimensionsSpecified, NoOfArrayDimensions: noOfArrayDimensions, ArrayDimensions: arrayDimensions}
}

///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
/////////////////////// Builder
///////////////////////

// VariantBuilder is a builder for Variant
type VariantBuilder interface {
	utils.Copyable
	// WithMandatoryFields adds all mandatory fields (convenience for using multiple builder calls)
	WithMandatoryFields(arrayLengthSpecified bool, arrayDimensionsSpecified bool, arrayDimensions []bool) VariantBuilder
	// WithArrayLengthSpecified adds ArrayLengthSpecified (property field)
	WithArrayLengthSpecified(bool) VariantBuilder
	// WithArrayDimensionsSpecified adds ArrayDimensionsSpecified (property field)
	WithArrayDimensionsSpecified(bool) VariantBuilder
	// WithNoOfArrayDimensions adds NoOfArrayDimensions (property field)
	WithOptionalNoOfArrayDimensions(int32) VariantBuilder
	// WithArrayDimensions adds ArrayDimensions (property field)
	WithArrayDimensions(...bool) VariantBuilder
	// AsVariantNull converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantNull() VariantNullBuilder
	// AsVariantBoolean converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantBoolean() VariantBooleanBuilder
	// AsVariantSByte converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantSByte() VariantSByteBuilder
	// AsVariantByte converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantByte() VariantByteBuilder
	// AsVariantInt16 converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantInt16() VariantInt16Builder
	// AsVariantUInt16 converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantUInt16() VariantUInt16Builder
	// AsVariantInt32 converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantInt32() VariantInt32Builder
	// AsVariantUInt32 converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantUInt32() VariantUInt32Builder
	// AsVariantInt64 converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantInt64() VariantInt64Builder
	// AsVariantUInt64 converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantUInt64() VariantUInt64Builder
	// AsVariantFloat converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantFloat() VariantFloatBuilder
	// AsVariantDouble converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantDouble() VariantDoubleBuilder
	// AsVariantString converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantString() VariantStringBuilder
	// AsVariantDateTime converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantDateTime() VariantDateTimeBuilder
	// AsVariantGuid converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantGuid() VariantGuidBuilder
	// AsVariantByteString converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantByteString() VariantByteStringBuilder
	// AsVariantXmlElement converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantXmlElement() VariantXmlElementBuilder
	// AsVariantNodeId converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantNodeId() VariantNodeIdBuilder
	// AsVariantExpandedNodeId converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantExpandedNodeId() VariantExpandedNodeIdBuilder
	// AsVariantStatusCode converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantStatusCode() VariantStatusCodeBuilder
	// AsVariantQualifiedName converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantQualifiedName() VariantQualifiedNameBuilder
	// AsVariantLocalizedText converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantLocalizedText() VariantLocalizedTextBuilder
	// AsVariantExtensionObject converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantExtensionObject() VariantExtensionObjectBuilder
	// AsVariantDataValue converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantDataValue() VariantDataValueBuilder
	// AsVariantVariant converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantVariant() VariantVariantBuilder
	// AsVariantDiagnosticInfo converts this build to a subType of Variant. It is always possible to return to current builder using Done()
	AsVariantDiagnosticInfo() VariantDiagnosticInfoBuilder
	// Build builds the Variant or returns an error if something is wrong
	PartialBuild() (VariantContract, error)
	// MustBuild does the same as Build but panics on error
	PartialMustBuild() VariantContract
	// Build builds the Variant or returns an error if something is wrong
	Build() (Variant, error)
	// MustBuild does the same as Build but panics on error
	MustBuild() Variant
}

// NewVariantBuilder() creates a VariantBuilder
func NewVariantBuilder() VariantBuilder {
	return &_VariantBuilder{_Variant: new(_Variant)}
}

type _VariantChildBuilder interface {
	utils.Copyable
	setParent(VariantContract)
	buildForVariant() (Variant, error)
}

type _VariantBuilder struct {
	*_Variant

	childBuilder _VariantChildBuilder

	collectedErr []error
}

var _ (VariantBuilder) = (*_VariantBuilder)(nil)

func (b *_VariantBuilder) WithMandatoryFields(arrayLengthSpecified bool, arrayDimensionsSpecified bool, arrayDimensions []bool) VariantBuilder {
	return b.WithArrayLengthSpecified(arrayLengthSpecified).WithArrayDimensionsSpecified(arrayDimensionsSpecified).WithArrayDimensions(arrayDimensions...)
}

func (b *_VariantBuilder) WithArrayLengthSpecified(arrayLengthSpecified bool) VariantBuilder {
	b.ArrayLengthSpecified = arrayLengthSpecified
	return b
}

func (b *_VariantBuilder) WithArrayDimensionsSpecified(arrayDimensionsSpecified bool) VariantBuilder {
	b.ArrayDimensionsSpecified = arrayDimensionsSpecified
	return b
}

func (b *_VariantBuilder) WithOptionalNoOfArrayDimensions(noOfArrayDimensions int32) VariantBuilder {
	b.NoOfArrayDimensions = &noOfArrayDimensions
	return b
}

func (b *_VariantBuilder) WithArrayDimensions(arrayDimensions ...bool) VariantBuilder {
	b.ArrayDimensions = arrayDimensions
	return b
}

func (b *_VariantBuilder) PartialBuild() (VariantContract, error) {
	if err := stdErrors.Join(b.collectedErr...); err != nil {
		return nil, errors.Wrap(err, "error occurred during build")
	}
	return b._Variant.deepCopy(), nil
}

func (b *_VariantBuilder) PartialMustBuild() VariantContract {
	build, err := b.PartialBuild()
	if err != nil {
		panic(err)
	}
	return build
}

func (b *_VariantBuilder) AsVariantNull() VariantNullBuilder {
	if cb, ok := b.childBuilder.(VariantNullBuilder); ok {
		return cb
	}
	cb := NewVariantNullBuilder().(*_VariantNullBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantBoolean() VariantBooleanBuilder {
	if cb, ok := b.childBuilder.(VariantBooleanBuilder); ok {
		return cb
	}
	cb := NewVariantBooleanBuilder().(*_VariantBooleanBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantSByte() VariantSByteBuilder {
	if cb, ok := b.childBuilder.(VariantSByteBuilder); ok {
		return cb
	}
	cb := NewVariantSByteBuilder().(*_VariantSByteBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantByte() VariantByteBuilder {
	if cb, ok := b.childBuilder.(VariantByteBuilder); ok {
		return cb
	}
	cb := NewVariantByteBuilder().(*_VariantByteBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantInt16() VariantInt16Builder {
	if cb, ok := b.childBuilder.(VariantInt16Builder); ok {
		return cb
	}
	cb := NewVariantInt16Builder().(*_VariantInt16Builder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantUInt16() VariantUInt16Builder {
	if cb, ok := b.childBuilder.(VariantUInt16Builder); ok {
		return cb
	}
	cb := NewVariantUInt16Builder().(*_VariantUInt16Builder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantInt32() VariantInt32Builder {
	if cb, ok := b.childBuilder.(VariantInt32Builder); ok {
		return cb
	}
	cb := NewVariantInt32Builder().(*_VariantInt32Builder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantUInt32() VariantUInt32Builder {
	if cb, ok := b.childBuilder.(VariantUInt32Builder); ok {
		return cb
	}
	cb := NewVariantUInt32Builder().(*_VariantUInt32Builder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantInt64() VariantInt64Builder {
	if cb, ok := b.childBuilder.(VariantInt64Builder); ok {
		return cb
	}
	cb := NewVariantInt64Builder().(*_VariantInt64Builder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantUInt64() VariantUInt64Builder {
	if cb, ok := b.childBuilder.(VariantUInt64Builder); ok {
		return cb
	}
	cb := NewVariantUInt64Builder().(*_VariantUInt64Builder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantFloat() VariantFloatBuilder {
	if cb, ok := b.childBuilder.(VariantFloatBuilder); ok {
		return cb
	}
	cb := NewVariantFloatBuilder().(*_VariantFloatBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantDouble() VariantDoubleBuilder {
	if cb, ok := b.childBuilder.(VariantDoubleBuilder); ok {
		return cb
	}
	cb := NewVariantDoubleBuilder().(*_VariantDoubleBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantString() VariantStringBuilder {
	if cb, ok := b.childBuilder.(VariantStringBuilder); ok {
		return cb
	}
	cb := NewVariantStringBuilder().(*_VariantStringBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantDateTime() VariantDateTimeBuilder {
	if cb, ok := b.childBuilder.(VariantDateTimeBuilder); ok {
		return cb
	}
	cb := NewVariantDateTimeBuilder().(*_VariantDateTimeBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantGuid() VariantGuidBuilder {
	if cb, ok := b.childBuilder.(VariantGuidBuilder); ok {
		return cb
	}
	cb := NewVariantGuidBuilder().(*_VariantGuidBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantByteString() VariantByteStringBuilder {
	if cb, ok := b.childBuilder.(VariantByteStringBuilder); ok {
		return cb
	}
	cb := NewVariantByteStringBuilder().(*_VariantByteStringBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantXmlElement() VariantXmlElementBuilder {
	if cb, ok := b.childBuilder.(VariantXmlElementBuilder); ok {
		return cb
	}
	cb := NewVariantXmlElementBuilder().(*_VariantXmlElementBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantNodeId() VariantNodeIdBuilder {
	if cb, ok := b.childBuilder.(VariantNodeIdBuilder); ok {
		return cb
	}
	cb := NewVariantNodeIdBuilder().(*_VariantNodeIdBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantExpandedNodeId() VariantExpandedNodeIdBuilder {
	if cb, ok := b.childBuilder.(VariantExpandedNodeIdBuilder); ok {
		return cb
	}
	cb := NewVariantExpandedNodeIdBuilder().(*_VariantExpandedNodeIdBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantStatusCode() VariantStatusCodeBuilder {
	if cb, ok := b.childBuilder.(VariantStatusCodeBuilder); ok {
		return cb
	}
	cb := NewVariantStatusCodeBuilder().(*_VariantStatusCodeBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantQualifiedName() VariantQualifiedNameBuilder {
	if cb, ok := b.childBuilder.(VariantQualifiedNameBuilder); ok {
		return cb
	}
	cb := NewVariantQualifiedNameBuilder().(*_VariantQualifiedNameBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantLocalizedText() VariantLocalizedTextBuilder {
	if cb, ok := b.childBuilder.(VariantLocalizedTextBuilder); ok {
		return cb
	}
	cb := NewVariantLocalizedTextBuilder().(*_VariantLocalizedTextBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantExtensionObject() VariantExtensionObjectBuilder {
	if cb, ok := b.childBuilder.(VariantExtensionObjectBuilder); ok {
		return cb
	}
	cb := NewVariantExtensionObjectBuilder().(*_VariantExtensionObjectBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantDataValue() VariantDataValueBuilder {
	if cb, ok := b.childBuilder.(VariantDataValueBuilder); ok {
		return cb
	}
	cb := NewVariantDataValueBuilder().(*_VariantDataValueBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantVariant() VariantVariantBuilder {
	if cb, ok := b.childBuilder.(VariantVariantBuilder); ok {
		return cb
	}
	cb := NewVariantVariantBuilder().(*_VariantVariantBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) AsVariantDiagnosticInfo() VariantDiagnosticInfoBuilder {
	if cb, ok := b.childBuilder.(VariantDiagnosticInfoBuilder); ok {
		return cb
	}
	cb := NewVariantDiagnosticInfoBuilder().(*_VariantDiagnosticInfoBuilder)
	cb.parentBuilder = b
	b.childBuilder = cb
	return cb
}

func (b *_VariantBuilder) Build() (Variant, error) {
	v, err := b.PartialBuild()
	if err != nil {
		return nil, errors.Wrap(err, "error occurred during partial build")
	}
	if b.childBuilder == nil {
		return nil, errors.New("no child builder present")
	}
	b.childBuilder.setParent(v)
	return b.childBuilder.buildForVariant()
}

func (b *_VariantBuilder) MustBuild() Variant {
	build, err := b.Build()
	if err != nil {
		panic(err)
	}
	return build
}

func (b *_VariantBuilder) DeepCopy() any {
	_copy := b.CreateVariantBuilder().(*_VariantBuilder)
	_copy.childBuilder = b.childBuilder.DeepCopy().(_VariantChildBuilder)
	_copy.childBuilder.setParent(_copy)
	if b.collectedErr != nil {
		copy(_copy.collectedErr, b.collectedErr)
	}
	return _copy
}

// CreateVariantBuilder creates a VariantBuilder
func (b *_Variant) CreateVariantBuilder() VariantBuilder {
	if b == nil {
		return NewVariantBuilder()
	}
	return &_VariantBuilder{_Variant: b.deepCopy()}
}

///////////////////////
///////////////////////
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
/////////////////////// Accessors for property fields.
///////////////////////

func (m *_Variant) GetArrayLengthSpecified() bool {
	return m.ArrayLengthSpecified
}

func (m *_Variant) GetArrayDimensionsSpecified() bool {
	return m.ArrayDimensionsSpecified
}

func (m *_Variant) GetNoOfArrayDimensions() *int32 {
	return m.NoOfArrayDimensions
}

func (m *_Variant) GetArrayDimensions() []bool {
	return m.ArrayDimensions
}

///////////////////////
///////////////////////
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////

// Deprecated: use the interface for direct cast
func CastVariant(structType any) Variant {
	if casted, ok := structType.(Variant); ok {
		return casted
	}
	if casted, ok := structType.(*Variant); ok {
		return *casted
	}
	return nil
}

func (m *_Variant) GetTypeName() string {
	return "Variant"
}

func (m *_Variant) getLengthInBits(ctx context.Context) uint16 {
	lengthInBits := uint16(0)

	// Simple field (arrayLengthSpecified)
	lengthInBits += 1

	// Simple field (arrayDimensionsSpecified)
	lengthInBits += 1
	// Discriminator Field (VariantType)
	lengthInBits += 6

	// Optional Field (noOfArrayDimensions)
	if m.NoOfArrayDimensions != nil {
		lengthInBits += 32
	}

	// Array field
	if len(m.ArrayDimensions) > 0 {
		lengthInBits += 1 * uint16(len(m.ArrayDimensions))
	}

	return lengthInBits
}

func (m *_Variant) GetLengthInBits(ctx context.Context) uint16 {
	return m._SubType.GetLengthInBits(ctx)
}

func (m *_Variant) GetLengthInBytes(ctx context.Context) uint16 {
	return m._SubType.GetLengthInBits(ctx) / 8
}

func VariantParse[T Variant](ctx context.Context, theBytes []byte) (T, error) {
	return VariantParseWithBuffer[T](ctx, utils.NewReadBufferByteBased(theBytes))
}

func VariantParseWithBufferProducer[T Variant]() func(ctx context.Context, readBuffer utils.ReadBuffer) (T, error) {
	return func(ctx context.Context, readBuffer utils.ReadBuffer) (T, error) {
		v, err := VariantParseWithBuffer[T](ctx, readBuffer)
		if err != nil {
			var zero T
			return zero, err
		}
		return v, nil
	}
}

func VariantParseWithBuffer[T Variant](ctx context.Context, readBuffer utils.ReadBuffer) (T, error) {
	v, err := (new(_Variant)).parse(ctx, readBuffer)
	if err != nil {
		var zero T
		return zero, err
	}
	vc, ok := v.(T)
	if !ok {
		var zero T
		return zero, errors.Errorf("Unexpected type %T. Expected type %T", v, *new(T))
	}
	return vc, nil
}

func (m *_Variant) parse(ctx context.Context, readBuffer utils.ReadBuffer) (__variant Variant, err error) {
	positionAware := readBuffer
	_ = positionAware
	if pullErr := readBuffer.PullContext("Variant"); pullErr != nil {
		return nil, errors.Wrap(pullErr, "Error pulling for Variant")
	}
	currentPos := positionAware.GetPos()
	_ = currentPos

	arrayLengthSpecified, err := ReadSimpleField(ctx, "arrayLengthSpecified", ReadBoolean(readBuffer))
	if err != nil {
		return nil, errors.Wrap(err, fmt.Sprintf("Error parsing 'arrayLengthSpecified' field"))
	}
	m.ArrayLengthSpecified = arrayLengthSpecified

	arrayDimensionsSpecified, err := ReadSimpleField(ctx, "arrayDimensionsSpecified", ReadBoolean(readBuffer))
	if err != nil {
		return nil, errors.Wrap(err, fmt.Sprintf("Error parsing 'arrayDimensionsSpecified' field"))
	}
	m.ArrayDimensionsSpecified = arrayDimensionsSpecified

	VariantType, err := ReadDiscriminatorField[uint8](ctx, "VariantType", ReadUnsignedByte(readBuffer, uint8(6)))
	if err != nil {
		return nil, errors.Wrap(err, fmt.Sprintf("Error parsing 'VariantType' field"))
	}

	// Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
	var _child Variant
	switch {
	case VariantType == uint8(0): // VariantNull
		if _child, err = new(_VariantNull).parse(ctx, readBuffer, m); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantNull for type-switch of Variant")
		}
	case VariantType == uint8(1): // VariantBoolean
		if _child, err = new(_VariantBoolean).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantBoolean for type-switch of Variant")
		}
	case VariantType == uint8(2): // VariantSByte
		if _child, err = new(_VariantSByte).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantSByte for type-switch of Variant")
		}
	case VariantType == uint8(3): // VariantByte
		if _child, err = new(_VariantByte).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantByte for type-switch of Variant")
		}
	case VariantType == uint8(4): // VariantInt16
		if _child, err = new(_VariantInt16).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantInt16 for type-switch of Variant")
		}
	case VariantType == uint8(5): // VariantUInt16
		if _child, err = new(_VariantUInt16).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantUInt16 for type-switch of Variant")
		}
	case VariantType == uint8(6): // VariantInt32
		if _child, err = new(_VariantInt32).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantInt32 for type-switch of Variant")
		}
	case VariantType == uint8(7): // VariantUInt32
		if _child, err = new(_VariantUInt32).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantUInt32 for type-switch of Variant")
		}
	case VariantType == uint8(8): // VariantInt64
		if _child, err = new(_VariantInt64).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantInt64 for type-switch of Variant")
		}
	case VariantType == uint8(9): // VariantUInt64
		if _child, err = new(_VariantUInt64).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantUInt64 for type-switch of Variant")
		}
	case VariantType == uint8(10): // VariantFloat
		if _child, err = new(_VariantFloat).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantFloat for type-switch of Variant")
		}
	case VariantType == uint8(11): // VariantDouble
		if _child, err = new(_VariantDouble).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantDouble for type-switch of Variant")
		}
	case VariantType == uint8(12): // VariantString
		if _child, err = new(_VariantString).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantString for type-switch of Variant")
		}
	case VariantType == uint8(13): // VariantDateTime
		if _child, err = new(_VariantDateTime).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantDateTime for type-switch of Variant")
		}
	case VariantType == uint8(14): // VariantGuid
		if _child, err = new(_VariantGuid).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantGuid for type-switch of Variant")
		}
	case VariantType == uint8(15): // VariantByteString
		if _child, err = new(_VariantByteString).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantByteString for type-switch of Variant")
		}
	case VariantType == uint8(16): // VariantXmlElement
		if _child, err = new(_VariantXmlElement).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantXmlElement for type-switch of Variant")
		}
	case VariantType == uint8(17): // VariantNodeId
		if _child, err = new(_VariantNodeId).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantNodeId for type-switch of Variant")
		}
	case VariantType == uint8(18): // VariantExpandedNodeId
		if _child, err = new(_VariantExpandedNodeId).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantExpandedNodeId for type-switch of Variant")
		}
	case VariantType == uint8(19): // VariantStatusCode
		if _child, err = new(_VariantStatusCode).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantStatusCode for type-switch of Variant")
		}
	case VariantType == uint8(20): // VariantQualifiedName
		if _child, err = new(_VariantQualifiedName).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantQualifiedName for type-switch of Variant")
		}
	case VariantType == uint8(21): // VariantLocalizedText
		if _child, err = new(_VariantLocalizedText).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantLocalizedText for type-switch of Variant")
		}
	case VariantType == uint8(22): // VariantExtensionObject
		if _child, err = new(_VariantExtensionObject).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantExtensionObject for type-switch of Variant")
		}
	case VariantType == uint8(23): // VariantDataValue
		if _child, err = new(_VariantDataValue).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantDataValue for type-switch of Variant")
		}
	case VariantType == uint8(24): // VariantVariant
		if _child, err = new(_VariantVariant).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantVariant for type-switch of Variant")
		}
	case VariantType == uint8(25): // VariantDiagnosticInfo
		if _child, err = new(_VariantDiagnosticInfo).parse(ctx, readBuffer, m, arrayLengthSpecified); err != nil {
			return nil, errors.Wrap(err, "Error parsing sub-type VariantDiagnosticInfo for type-switch of Variant")
		}
	default:
		return nil, errors.Errorf("Unmapped type for parameters [VariantType=%v, arrayLengthSpecified=%v]", VariantType, arrayLengthSpecified)
	}

	var noOfArrayDimensions *int32
	noOfArrayDimensions, err = ReadOptionalField[int32](ctx, "noOfArrayDimensions", ReadSignedInt(readBuffer, uint8(32)), arrayDimensionsSpecified)
	if err != nil {
		return nil, errors.Wrap(err, fmt.Sprintf("Error parsing 'noOfArrayDimensions' field"))
	}
	m.NoOfArrayDimensions = noOfArrayDimensions

	arrayDimensions, err := ReadCountArrayField[bool](ctx, "arrayDimensions", ReadBoolean(readBuffer), uint64(utils.InlineIf(bool((noOfArrayDimensions) == (nil)), func() any { return int32(int32(0)) }, func() any { return int32((*noOfArrayDimensions)) }).(int32)))
	if err != nil {
		return nil, errors.Wrap(err, fmt.Sprintf("Error parsing 'arrayDimensions' field"))
	}
	m.ArrayDimensions = arrayDimensions

	if closeErr := readBuffer.CloseContext("Variant"); closeErr != nil {
		return nil, errors.Wrap(closeErr, "Error closing for Variant")
	}

	return _child, nil
}

func (pm *_Variant) serializeParent(ctx context.Context, writeBuffer utils.WriteBuffer, child Variant, serializeChildFunction func() error) error {
	// We redirect all calls through client as some methods are only implemented there
	m := child
	_ = m
	positionAware := writeBuffer
	_ = positionAware
	log := zerolog.Ctx(ctx)
	_ = log
	if pushErr := writeBuffer.PushContext("Variant"); pushErr != nil {
		return errors.Wrap(pushErr, "Error pushing for Variant")
	}

	if err := WriteSimpleField[bool](ctx, "arrayLengthSpecified", m.GetArrayLengthSpecified(), WriteBoolean(writeBuffer)); err != nil {
		return errors.Wrap(err, "Error serializing 'arrayLengthSpecified' field")
	}

	if err := WriteSimpleField[bool](ctx, "arrayDimensionsSpecified", m.GetArrayDimensionsSpecified(), WriteBoolean(writeBuffer)); err != nil {
		return errors.Wrap(err, "Error serializing 'arrayDimensionsSpecified' field")
	}

	if err := WriteDiscriminatorField(ctx, "VariantType", m.GetVariantType(), WriteUnsignedByte(writeBuffer, 6)); err != nil {
		return errors.Wrap(err, "Error serializing 'VariantType' field")
	}

	// Switch field (Depending on the discriminator values, passes the serialization to a sub-type)
	if _typeSwitchErr := serializeChildFunction(); _typeSwitchErr != nil {
		return errors.Wrap(_typeSwitchErr, "Error serializing sub-type field")
	}

	if err := WriteOptionalField[int32](ctx, "noOfArrayDimensions", m.GetNoOfArrayDimensions(), WriteSignedInt(writeBuffer, 32), true); err != nil {
		return errors.Wrap(err, "Error serializing 'noOfArrayDimensions' field")
	}

	if err := WriteSimpleTypeArrayField(ctx, "arrayDimensions", m.GetArrayDimensions(), WriteBoolean(writeBuffer)); err != nil {
		return errors.Wrap(err, "Error serializing 'arrayDimensions' field")
	}

	if popErr := writeBuffer.PopContext("Variant"); popErr != nil {
		return errors.Wrap(popErr, "Error popping for Variant")
	}
	return nil
}

func (m *_Variant) IsVariant() {}

func (m *_Variant) DeepCopy() any {
	return m.deepCopy()
}

func (m *_Variant) deepCopy() *_Variant {
	if m == nil {
		return nil
	}
	_VariantCopy := &_Variant{
		nil, // will be set by child
		m.ArrayLengthSpecified,
		m.ArrayDimensionsSpecified,
		utils.CopyPtr[int32](m.NoOfArrayDimensions),
		utils.DeepCopySlice[bool, bool](m.ArrayDimensions),
	}
	return _VariantCopy
}
