// Copyright (c) 2009-2022 The MathJax Consortium
// SPDX-License-Identifier: Apache-2.0
//
// This file is a Go translation and modification of MathJax 3.2.2.
// Sources: ts/input/tex/{NodeUtil,SymbolMap,Symbol,MapHandler,ParseMethods,
// Configuration}.ts and base/BaseConfiguration.ts.

package tex

import (
	
	

	
)

func lookupMJSourceEntry( mjSourceMapKind,  string) (mjSourceMap, mjSourceEntry, bool) {
	for  := len(mjSourceMaps) - 1;  >= 0; -- {
		 := mjSourceMaps[]
		if .Kind !=  || .Parser == "" {
			continue
		}
		for  := len(.Entries) - 1;  >= 0; -- {
			 := .Entries[]
			 := .Name
			if  == mjSourceDelimiterMap {
				if !strings.HasPrefix(, "\\") {
					continue
				}
				 = strings.TrimPrefix(, "\\")
			}
			if  ==  {
				return , , true
			}
		}
	}
	return mjSourceMap{}, mjSourceEntry{}, false
}

func lookupMJSourceSymbol( string) (*mml.Node, bool) {
	for ,  := range []mjSourceMapKind{mjSourceCharacterMap, mjSourceDelimiterMap} {
		, ,  := lookupMJSourceEntry(, )
		if ! {
			continue
		}
		, ,  := sourceSymbolValue(.Value)
		if ! {
			return nil, false
		}
		 := "mo"
		 := mml.TeXClassOrd
		switch {
		case strings.Contains(.Parser, "mathchar0mi"):
			 = "mi"
			// ParseMethods.mathchar0mi supplies italic when the source entry
			// has no attribute object.  This is an explicit parser attribute,
			// distinct from MmlMi's later one-character inheritance default.
			if  == nil {
				 = mjSourceObject{{Name: "mathvariant", Value: "italic"}}
			}
		case strings.Contains(.Parser, "mathchar7"):
			 = "mi"
			// ParseMethods.mathchar7 supplies normal for its current-family
			// symbols (notably upper-case Greek) unless the entry overrides it.
			if  == nil {
				 = mjSourceObject{{Name: "mathvariant", Value: "normal"}}
			}
		case strings.Contains(.Parser, "delimiter"):
			 = mml.TeXClassOrd
			if ,  := sourceObjectValue(, "fence"); ! {
				 = append(, mjSourceProperty{Name: "fence", Value: false})
			}
			if ,  := sourceObjectValue(, "stretchy"); ! {
				 = append(, mjSourceProperty{Name: "stretchy", Value: false})
			}
		}
		 := token(, )
		if strings.Contains(.Parser, "mathchar7") {
			ambientFontToken()
		}
		.TeXClass = 
		applySourceObject(, )
		if  == "mo" && strings.Contains(.Parser, "mathchar0mo") {
			.Attributes.Set("stretchy", false)
			.SetProperty("fixStretchy", true)
			.SetProperty("in-lists", "fixStretchy")
		}
		return , true
	}
	return nil, false
}

func sourceSymbolValue( any) (string, mjSourceObject, bool) {
	switch value := .(type) {
	case string:
		return , nil, true
	case mjSourceList:
		if len() == 0 {
			return "", nil, false
		}
		,  := [0].(string)
		if ! {
			return "", nil, false
		}
		var  mjSourceObject
		if len() > 1 {
			, _ = [1].(mjSourceObject)
		}
		return , , true
	}
	return "", nil, false
}

func applySourceObject( *mml.Node,  mjSourceObject) {
	for ,  := range  {
		switch .Name {
		case "texClass":
			if ,  := sourceInt(.Value);  {
				.TeXClass = mml.TeXClass()
				.SetProperty(.Name, )
			}
		case "movablelimits":
			.SetProperty(.Name, .Value)
			if .Kind == "mo" || .Kind == "mstyle" {
				.Attributes.Set(.Name, .Value)
			}
		case "autoOP", "fnOP", "movesupsub", "subsupOK", "texprimestyle", "useHeight", "variantForm", "withDelims", "mathaccent", "open", "close":
			.SetProperty(.Name, .Value)
		case "inferred":
			// NodeUtil.setProperties intentionally ignores this marker.
		default:
			.Attributes.Set(.Name, .Value)
		}
	}
}

func sourceObjectValue( mjSourceObject,  string) (any, bool) {
	for ,  := range  {
		if .Name ==  {
			return .Value, true
		}
	}
	return nil, false
}

func sourceInt( any) (int, bool) {
	switch value := .(type) {
	case int:
		return , true
	case float64:
		return int(),  == float64(int())
	}
	return 0, false
}

func sourceString( any) (string, bool) {
	,  := .(string)
	return , 
}

func sourceBool( any) (bool, bool) {
	,  := .(bool)
	return , 
}

func sourceHandler( any) (string, mjSourceList, bool) {
	switch value := .(type) {
	case string:
		return , nil, true
	case mjSourceList:
		if len() == 0 {
			return "", nil, false
		}
		,  := [0].(string)
		if ! {
			return "", nil, false
		}
		return , [1:], true
	}
	return "", nil, false
}

func sourceValueString( any) string {
	if  == nil {
		return ""
	}
	return fmt.Sprint()
}