// Copyright 2017-2022 The MathJax Consortium
// SPDX-License-Identifier: Apache-2.0
// This file is a Go translation and modification of MathJax 3.2.2.

package mml

import 

// Property is a MathML attribute or internal-property value.
type Property = any

type inheritValue struct{}

// Inherit marks a default that resolves directly from the math node's global
// attributes, matching MathJax's _inherit_ sentinel.
var Inherit Property = inheritValue{}

func isInherit( Property) bool {
	,  := .(inheritValue)
	return 
}

// IsInherit reports whether value is the Inherit sentinel.
func ( Property) bool { return isInherit() }

// Attributes preserves MathJax's four attribute layers: explicit, inherited,
// per-node defaults, and global math attributes.
type Attributes struct {
	explicit  *ordered.Map[Property]
	inherited *ordered.Map[Property]
	defaults  *ordered.Map[Property]
	global    *ordered.Map[Property]
}

// NewAttributes constructs an attribute set. Inputs are cloned; nil inputs are
// treated as empty maps.
func (,  *ordered.Map[Property]) *Attributes {
	return &Attributes{
		explicit:  ordered.New[Property](),
		inherited: ordered.New[Property](),
		defaults:  .Clone(),
		global:    .Clone(),
	}
}

// Set sets an explicit attribute.
func ( *Attributes) ( string,  Property) { .explicit.Set(, ) }

// SetList sets explicit attributes in the source map's insertion order.
func ( *Attributes) ( *ordered.Map[Property]) {
	.Range(func( string,  Property) bool {
		.Set(, )
		return true
	})
}

func lookup( []*ordered.Map[Property],  string) (Property, bool) {
	for ,  := range  {
		if ,  := .Get();  {
			return , true
		}
	}
	return nil, false
}

// Get resolves explicit, inherited, default, and global layers in that order.
func ( *Attributes) ( string) (Property, bool) {
	,  := lookup([]*ordered.Map[Property]{.explicit, .inherited, .defaults, .global}, )
	if  && isInherit() {
		return .global.Get()
	}
	return , 
}

// GetExplicit returns only an explicitly set value.
func ( *Attributes) ( string) (Property, bool) { return .explicit.Get() }

// SetInherited sets an inherited value.
func ( *Attributes) ( string,  Property) { .inherited.Set(, ) }

// GetInherited resolves the inherited layer and its default/global prototypes.
func ( *Attributes) ( string) (Property, bool) {
	return lookup([]*ordered.Map[Property]{.inherited, .defaults, .global}, )
}

// GetDefault resolves the per-kind default and global layers.
func ( *Attributes) ( string) (Property, bool) {
	return lookup([]*ordered.Map[Property]{.defaults, .global}, )
}

// IsSet reports whether name is explicit or directly inherited.
func ( *Attributes) ( string) bool {
	return .explicit.Has() || .inherited.Has()
}

// HasDefault reports whether name has a kind or global default.
func ( *Attributes) ( string) bool {
	return .defaults.Has() || .global.Has()
}

func ( *Attributes) () []string  { return .explicit.Keys() }
func ( *Attributes) () []string { return .inherited.Keys() }
func ( *Attributes) () []string   { return .defaults.Keys() }
func ( *Attributes) () []string    { return .global.Keys() }

// Explicit returns the mutable explicit-attribute map.
func ( *Attributes) () *ordered.Map[Property] { return .explicit }

// Inherited returns the mutable inherited-attribute map.
func ( *Attributes) () *ordered.Map[Property] { return .inherited }

// Defaults returns the per-kind default map.
func ( *Attributes) () *ordered.Map[Property] { return .defaults }

// Globals returns the global math-attribute map.
func ( *Attributes) () *ordered.Map[Property] { return .global }

// Clone returns an independent shallow copy.
func ( *Attributes) () *Attributes {
	if  == nil {
		return NewAttributes(nil, nil)
	}
	return &Attributes{
		explicit:  .explicit.Clone(),
		inherited: .inherited.Clone(),
		defaults:  .defaults.Clone(),
		global:    .global.Clone(),
	}
}