// Code generated by cuelang.org/go/pkg/gen. DO NOT EDIT.

//go:build !cuebootstrap

package filetypes

import (
	_ "embed"
	"cmp"
	"maps"
	"fmt"
	"slices"

	"cuelang.org/go/cue/build"
	"cuelang.org/go/cue/errors"
	"cuelang.org/go/cue/token"
	"cuelang.org/go/internal/filetypes/internal"
	"cuelang.org/go/internal/filetypes/internal/opt"
	"cuelang.org/go/internal/filetypes/internal/genstruct"
)

// TODO use string instead of []byte so that we can
// use the init data directly without copying into
// read-write memory.

// The toFile lookup is split across three tables to avoid embedding the
// redundant full cross product of (mode, file extension, tag set). Results that
// are the same for every extension are stored once in fileinfo_indep.dat, keyed
// by (mode, tag set); the rest are in fileinfo_dep.dat, keyed per-extension.
// Both reference a result by index into fileinfo_results.dat.

//go:embed fileinfo_dep.dat
var fileInfoDepBytes []byte

//go:embed fileinfo_indep.dat
var fileInfoIndepBytes []byte

//go:embed fileinfo_results.dat
var fileInfoResultsBytes []byte

//go:embed fromfile.dat
var fromFileDataBytes []byte

func init() {
	tagTypes = map[string]TagType{
		{{range $k, $v := .TagTypes}}{{printf "\t%q: %v,\n" $k $v}}{{end}}
	}
}

{{.ToFileDepParams.GenInit .Generated}}

{{.ToFileIndepParams.GenInit .Generated}}

{{.ToFileResult.GenInit .Generated}}

{{.FromFileParams.GenInit .Generated}}

{{.FromFileResult.GenInit .Generated}}

func toFileGenerated(mode Mode, sc *scope, filename string) (*build.File, errors.Error) {
	var resultIndex int
	depKey := make([]byte, {{.ToFileDepParams.Size}})
	{{.ToFileDepParams.Tags.GenPut "depKey" "maps.Keys(sc.topLevel)"}}
	{{.ToFileDepParams.FileExt.GenPut "depKey" "fileExt(filename)"}}
	{{.ToFileDepParams.Mode.GenPut "depKey" "mode"}}
	if data, ok := genstruct.FindRecord(fileInfoDepBytes, {{.ToFileDepParams.Size}}+{{.ToFileResultIndex.Size}}, depKey); ok {
		// The result is in the extension-dependent table.
		resultIndex = {{.ToFileResultIndex.Index.GenGet "data"}}
	} else {
		// The result does not depend on the extension,
		// so fall back to the extension-independent table.
		indepKey := make([]byte, {{.ToFileIndepParams.Size}})
		{{.ToFileIndepParams.Tags.GenPut "indepKey" "maps.Keys(sc.topLevel)"}}
		{{.ToFileIndepParams.Mode.GenPut "indepKey" "mode"}}
		data, ok := genstruct.FindRecord(fileInfoIndepBytes, {{.ToFileIndepParams.Size}}+{{.ToFileResultIndex.Size}}, indepKey)
		if !ok {
			return nil, errors.Newf(token.NoPos, "invalid tag combination")		// TODO what error would be best?
		}
		resultIndex = {{.ToFileResultIndex.Index.GenGet "data"}}
	}
	data := fileInfoResultsBytes[resultIndex*{{.ToFileResult.Size}}:]

	switch e := {{.ToFileResult.Error.GenGet "data"}}; e {
	default:
		return nil, errors.Newf(token.NoPos, "unknown filetype error %d", e)
	case internal.ErrUnknownFileExtension:
		return nil, errors.Newf(token.NoPos, "unknown file extension %s", fileExt(filename))
	case internal.ErrCouldNotDetermineFileType:
		return nil, errors.Newf(token.NoPos, "could not determine file type for file %q", filename)
	case internal.ErrNoEncodingSpecified:
		return nil, errors.Newf(token.NoPos, "no encoding specified for file %q", filename)
	case 0:
		// no error
	}

	var f build.File
	f.Filename = filename
	f.Encoding = {{.ToFileResult.Encoding.GenGet "data"}}
	f.Interpretation = {{.ToFileResult.Interpretation.GenGet "data"}}
	f.Form = {{.ToFileResult.Form.GenGet "data"}}
	if index := {{.ToFileResult.SubsidiaryTagFuncIndex.GenGet "data"}}; index > 0 {
		tagFunc := subsidiaryTagFuncs[index-1]
		var t subsidiaryTags
		if err := t.unmarshalFromMap(sc.subsidiaryString); err != nil {
			return nil, errors.Promote(err, "")
		}
		t, err := tagFunc(t)
		if err != nil {
			return nil, errors.Promote(err, "")
		}
		f.Tags = t.marshalToMap()

	} else if len(sc.subsidiaryString) > 0 {
		return nil, errors.Newf(token.NoPos, "tag %s is not allowed in this context", someKey(sc.subsidiaryString))
	}
	if index := {{.ToFileResult.SubsidiaryBoolTagFuncIndex.GenGet "data"}}; index > 0 {
		tagFunc := subsidiaryBoolTagFuncs[index-1]
		var t subsidiaryBoolTags
		if err := t.unmarshalFromMap(sc.subsidiaryBool); err != nil {
			return nil, errors.Promote(err, "")
		}
		t, err := tagFunc(t)
		if err != nil {
			return nil, errors.Promote(err, "")
		}
		f.BoolTags = t.marshalToMap()
	} else if len(sc.subsidiaryBool) > 0 {
		return nil, errors.Newf(token.NoPos, "tag %s is not allowed in this context", someKey(sc.subsidiaryBool))
	}

	return &f, nil
}

func fromFileGenerated(b *build.File, mode Mode) (*FileInfo, error) {
	key := make([]byte, {{.FromFileParams.Size}})
	{{.FromFileParams.Mode.GenPut "key" "mode"}}
	{{.FromFileParams.Encoding.GenPut "key" "b.Encoding"}}
	{{.FromFileParams.Interpretation.GenPut "key" "b.Interpretation"}}
	{{.FromFileParams.Form.GenPut "key" "b.Form"}}

	data, ok := genstruct.FindRecord(fromFileDataBytes, {{.FromFileParams.Size}}+{{.FromFileResult.Size}}, key)
	if !ok {
		return nil, errors.Newf(token.NoPos, "no encoding specified")
	}
	fi := &FileInfo{
		Filename: b.Filename,
		Encoding: {{.FromFileResult.Encoding.GenGet "data"}},
		Interpretation: {{.FromFileResult.Interpretation.GenGet "data"}},
		Form: {{.FromFileResult.Form.GenGet "data"}},
	}
	fi.SetAspects({{.FromFileResult.Aspects.GenGet "data"}})
	return fi, nil
}

func someKey[K cmp.Ordered, V any](m map[K] V) K {
	return slices.Sorted(maps.Keys(m))[0]
}

var subsidiaryBoolTagFuncs = []func(subsidiaryBoolTags) (subsidiaryBoolTags, error) {
{{range .SubsidiaryBoolTagFuncCount}}unifySubsidiaryBoolTags_{{.}},
{{end}}
}

var subsidiaryTagFuncs = []func(subsidiaryTags) (subsidiaryTags, error) {
{{range .SubsidiaryTagFuncCount}}unifySubsidiaryTags_{{.}},
{{end}}
}
