// SPDX-License-Identifier: Unlicense OR BSD-3-Clause

package tables

import (
	"encoding/binary"
	"fmt"
)

// Code generated by binarygen from aat_mortx_src.go. DO NOT EDIT

func (item *AATFeature) mustParse(src []byte) {
	_ = src[11] // early bound checking
	item.FeatureType = binary.BigEndian.Uint16(src[0:])
	item.FeatureSetting = binary.BigEndian.Uint16(src[2:])
	item.EnableFlags = binary.BigEndian.Uint32(src[4:])
	item.DisableFlags = binary.BigEndian.Uint32(src[8:])
}

func ParseMorx(src []byte, valuesCount int) (Morx, int, error) {
	var item Morx
	n := 0
	if L := len(src); L < 8 {
		return item, 0, fmt.Errorf("reading Morx: "+"EOF: expected length: 8, got %d", L)
	}
	_ = src[7] // early bound checking
	item.version = binary.BigEndian.Uint16(src[0:])
	item.unused = binary.BigEndian.Uint16(src[2:])
	item.nChains = binary.BigEndian.Uint32(src[4:])
	n += 8

	{
		arrayLength := int(item.nChains)

		offset := 8
		for i := 0; i < arrayLength; i++ {
			elem, read, err := ParseMorxChain(src[offset:], valuesCount)
			if err != nil {
				return item, 0, fmt.Errorf("reading Morx: %s", err)
			}
			item.Chains = append(item.Chains, elem)
			offset += read
		}
		n = offset
	}
	return item, n, nil
}

func ParseMorxChain(src []byte, valuesCount int) (MorxChain, int, error) {
	var item MorxChain
	n := 0
	if L := len(src); L < 16 {
		return item, 0, fmt.Errorf("reading MorxChain: "+"EOF: expected length: 16, got %d", L)
	}
	_ = src[15] // early bound checking
	item.Flags = binary.BigEndian.Uint32(src[0:])
	item.chainLength = binary.BigEndian.Uint32(src[4:])
	item.nFeatureEntries = binary.BigEndian.Uint32(src[8:])
	item.nSubtable = binary.BigEndian.Uint32(src[12:])
	n += 16

	{
		arrayLength := int(item.nFeatureEntries)

		if L := len(src); L < 16+arrayLength*12 {
			return item, 0, fmt.Errorf("reading MorxChain: "+"EOF: expected length: %d, got %d", 16+arrayLength*12, L)
		}

		item.Features = make([]AATFeature, arrayLength) // allocation guarded by the previous check
		for i := range item.Features {
			item.Features[i].mustParse(src[16+i*12:])
		}
		n += arrayLength * 12
	}
	{
		arrayLength := int(item.nSubtable)

		offset := n
		for i := 0; i < arrayLength; i++ {
			elem, read, err := ParseMorxChainSubtable(src[offset:], valuesCount)
			if err != nil {
				return item, 0, fmt.Errorf("reading MorxChain: %s", err)
			}
			item.Subtables = append(item.Subtables, elem)
			offset += read
		}
		n = offset
	}
	return item, n, nil
}

func ParseMorxChainSubtable(src []byte, valuesCount int) (MorxChainSubtable, int, error) {
	var item MorxChainSubtable
	n := 0
	if L := len(src); L < 12 {
		return item, 0, fmt.Errorf("reading MorxChainSubtable: "+"EOF: expected length: 12, got %d", L)
	}
	_ = src[11] // early bound checking
	item.length = binary.BigEndian.Uint32(src[0:])
	item.Coverage = src[4]
	item.ignored[0] = src[5]
	item.ignored[1] = src[6]
	item.version = MorxSubtableVersion(src[7])
	item.SubFeatureFlags = binary.BigEndian.Uint32(src[8:])
	n += 12

	{
		var (
			read int
			err  error
		)
		switch item.version {
		case MorxSubtableVersionContextual:
			item.Data, read, err = ParseMorxSubtableContextual(src[12:], valuesCount)
		case MorxSubtableVersionInsertion:
			item.Data, read, err = ParseMorxSubtableInsertion(src[12:], valuesCount)
		case MorxSubtableVersionLigature:
			item.Data, read, err = ParseMorxSubtableLigature(src[12:], valuesCount)
		case MorxSubtableVersionNonContextual:
			item.Data, read, err = ParseMorxSubtableNonContextual(src[12:], valuesCount)
		case MorxSubtableVersionRearrangement:
			item.Data, read, err = ParseMorxSubtableRearrangement(src[12:], valuesCount)
		default:
			err = fmt.Errorf("unsupported MorxSubtableVersion %d", item.version)
		}
		if err != nil {
			return item, 0, fmt.Errorf("reading MorxChainSubtable: %s", err)
		}
		n += read
	}
	var err error
	n, err = item.parseEnd(src, valuesCount)
	if err != nil {
		return item, 0, fmt.Errorf("reading MorxChainSubtable: %s", err)
	}

	return item, n, nil
}

func ParseMorxSubtableContextual(src []byte, valuesCount int) (MorxSubtableContextual, int, error) {
	var item MorxSubtableContextual
	n := 0
	{
		var (
			err  error
			read int
		)
		item.AATStateTableExt, read, err = ParseAATStateTableExt(src[0:], int(valuesCount), int(4))
		if err != nil {
			return item, 0, fmt.Errorf("reading MorxSubtableContextual: %s", err)
		}
		n += read
	}
	if L := len(src); L < n+4 {
		return item, 0, fmt.Errorf("reading MorxSubtableContextual: "+"EOF: expected length: n + 4, got %d", L)
	}
	offsetSubstitutions := int(binary.BigEndian.Uint32(src[n:]))
	n += 4

	{
		if offsetSubstitutions != 0 { // ignore null offset
			if L := len(src); L < offsetSubstitutions {
				return item, 0, fmt.Errorf("reading MorxSubtableContextual: "+"EOF: expected length: %d, got %d", offsetSubstitutions, L)
			}

			var err error
			item.Substitutions, _, err = ParseSubstitutionsTable(src[offsetSubstitutions:], int(item.nSubs()), int(valuesCount))
			if err != nil {
				return item, 0, fmt.Errorf("reading MorxSubtableContextual: %s", err)
			}

		}
	}
	return item, n, nil
}

func ParseMorxSubtableInsertion(src []byte, valuesCount int) (MorxSubtableInsertion, int, error) {
	var item MorxSubtableInsertion
	n := 0
	{
		var (
			err  error
			read int
		)
		item.AATStateTableExt, read, err = ParseAATStateTableExt(src[0:], int(valuesCount), int(4))
		if err != nil {
			return item, 0, fmt.Errorf("reading MorxSubtableInsertion: %s", err)
		}
		n += read
	}
	if L := len(src); L < n+4 {
		return item, 0, fmt.Errorf("reading MorxSubtableInsertion: "+"EOF: expected length: n + 4, got %d", L)
	}
	offsetInsertions := int(binary.BigEndian.Uint32(src[n:]))
	n += 4

	{
		if offsetInsertions != 0 { // ignore null offset
			if L := len(src); L < offsetInsertions {
				return item, 0, fmt.Errorf("reading MorxSubtableInsertion: "+"EOF: expected length: %d, got %d", offsetInsertions, L)
			}

			arrayLength := int(item.nInsertions())

			if L := len(src); L < offsetInsertions+arrayLength*2 {
				return item, 0, fmt.Errorf("reading MorxSubtableInsertion: "+"EOF: expected length: %d, got %d", offsetInsertions+arrayLength*2, L)
			}

			item.Insertions = make([]uint16, arrayLength) // allocation guarded by the previous check
			for i := range item.Insertions {
				item.Insertions[i] = binary.BigEndian.Uint16(src[offsetInsertions+i*2:])
			}
			offsetInsertions += arrayLength * 2
		}
	}
	return item, n, nil
}

func ParseMorxSubtableLigature(src []byte, valuesCount int) (MorxSubtableLigature, int, error) {
	var item MorxSubtableLigature
	n := 0
	{
		var (
			err  error
			read int
		)
		item.AATStateTableExt, read, err = ParseAATStateTableExt(src[0:], int(valuesCount), int(2))
		if err != nil {
			return item, 0, fmt.Errorf("reading MorxSubtableLigature: %s", err)
		}
		n += read
	}
	if L := len(src); L < n+12 {
		return item, 0, fmt.Errorf("reading MorxSubtableLigature: "+"EOF: expected length: n + 12, got %d", L)
	}
	_ = src[n+11] // early bound checking
	item.ligActionOffset = Offset32(binary.BigEndian.Uint32(src[n:]))
	item.componentOffset = Offset32(binary.BigEndian.Uint32(src[n+4:]))
	item.ligatureOffset = Offset32(binary.BigEndian.Uint32(src[n+8:]))
	n += 12

	{

		err := item.parseLigActions(src[:], valuesCount)
		if err != nil {
			return item, 0, fmt.Errorf("reading MorxSubtableLigature: %s", err)
		}
	}
	{

		err := item.parseComponents(src[:], valuesCount)
		if err != nil {
			return item, 0, fmt.Errorf("reading MorxSubtableLigature: %s", err)
		}
	}
	{

		err := item.parseLigatures(src[:], valuesCount)
		if err != nil {
			return item, 0, fmt.Errorf("reading MorxSubtableLigature: %s", err)
		}
	}
	return item, n, nil
}

func ParseMorxSubtableNonContextual(src []byte, valuesCount int) (MorxSubtableNonContextual, int, error) {
	var item MorxSubtableNonContextual
	n := 0
	{
		var (
			err  error
			read int
		)
		item.Class, read, err = ParseAATLookup(src[0:], valuesCount)
		if err != nil {
			return item, 0, fmt.Errorf("reading MorxSubtableNonContextual: %s", err)
		}
		n += read
	}
	return item, n, nil
}

func ParseMorxSubtableRearrangement(src []byte, valuesCount int) (MorxSubtableRearrangement, int, error) {
	var item MorxSubtableRearrangement
	n := 0
	{
		var (
			err  error
			read int
		)
		item.AATStateTableExt, read, err = ParseAATStateTableExt(src[0:], int(valuesCount), int(0))
		if err != nil {
			return item, 0, fmt.Errorf("reading MorxSubtableRearrangement: %s", err)
		}
		n += read
	}
	return item, n, nil
}

func ParseSubstitutionsTable(src []byte, substitutionsCount int, valuesCount int) (SubstitutionsTable, int, error) {
	var item SubstitutionsTable
	n := 0
	{

		if L := len(src); L < substitutionsCount*4 {
			return item, 0, fmt.Errorf("reading SubstitutionsTable: "+"EOF: expected length: %d, got %d", substitutionsCount*4, L)
		}

		item.Substitutions = make([]AATLookup, substitutionsCount) // allocation guarded by the previous check
		for i := range item.Substitutions {
			offset := int(binary.BigEndian.Uint32(src[i*4:]))
			// ignore null offsets
			if offset == 0 {
				continue
			}

			if L := len(src); L < offset {
				return item, 0, fmt.Errorf("reading SubstitutionsTable: "+"EOF: expected length: %d, got %d", offset, L)
			}

			var err error
			item.Substitutions[i], _, err = ParseAATLookup(src[offset:], valuesCount)
			if err != nil {
				return item, 0, fmt.Errorf("reading SubstitutionsTable: %s", err)
			}
		}
		n += substitutionsCount * 4
	}
	return item, n, nil
}
