// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cldrtree

import (
	"reflect"

	"golang.org/x/text/unicode/cldr"
)

// An Option configures an Index.
type Option func(*options)

type options struct {
	parent *Index

	name  string
	alias *cldr.Common

	sharedType  *typeInfo
	sharedEnums *enum
}

func (o *options) fill(opt []Option) {
	for _, f := range opt {
		f(o)
	}
}

// setAlias sets an alias from the given node, if the node defines one.
func (o *options) setAlias(n Element) {
	if n != nil && !reflect.ValueOf(n).IsNil() {
		o.alias = n.GetCommon()
	}
}

// Enum defines an enumeration type. The resulting option may be passed for the
// construction of multiple Indexes, which they will share the same enum values.
// Calling Gen on a Builder will generate the Enum for the given name. The
// optional values fix the values for the given identifier to the argument
// position (starting at 0). Other values may still be added and will be
// assigned to subsequent values.
func Enum(name string, value ...string) Option {
	return EnumFunc(name, nil, value...)
}

// EnumFunc is like Enum but also takes a function that allows rewriting keys.
func EnumFunc(name string, rename func(string) string, value ...string) Option {
	enum := &enum{name: name, rename: rename, keyMap: map[string]enumIndex{}}
	for _, e := range value {
		enum.lookup(e)
	}
	return func(o *options) {
		found := false
		for _, e := range o.parent.meta.b.enums {
			if e.name == enum.name {
				found = true
				break
			}
		}
		if !found {
			o.parent.meta.b.enums = append(o.parent.meta.b.enums, enum)
		}
		o.sharedEnums = enum
	}
}

// SharedType returns an option which causes all Indexes to which this option is
// passed to have the same type.
func SharedType() Option {
	info := &typeInfo{}
	return func(o *options) { o.sharedType = info }
}

func useSharedType() Option {
	return func(o *options) {
		sub := o.parent.meta.typeInfo.keyTypeInfo
		if sub == nil {
			sub = &typeInfo{}
			o.parent.meta.typeInfo.keyTypeInfo = sub
		}
		o.sharedType = sub
	}
}
