// Copyright (c) 2018-2022 MathJax Consortium
// SPDX-License-Identifier: Apache-2.0
// This file is a Go translation and modification of MathJax 3.2.2.
//
// Source: ts/input/tex/physics/PhysicsMethods.ts and PhysicsMappings.ts.

package tex

import (
	
	
	

	
	
)

// physicsCommand is the narrow Physics command hook for the central parser.
// It must run before built-in function-name handling, since Physics overrides
// names such as \sin with its optional-exponent and automatic-fence method.
func ( *parser) ( string,  **derivativeAutoOpen) ( []*mml.Node,  bool,  error) {
	if ,  := physicsQuantities[];  {
		,  = .physicsQuantity(, , )
		return , true, 
	}
	if ,  := physicsApplicationOperators[];  {
		,  = .physicsOperatorApplication(, , )
		return , true, 
	}
	switch  {
	case "sin", "sinh", "arcsin", "asin", "cos", "cosh", "arccos", "acos", "tan", "tanh", "arctan", "atan",
		"csc", "csch", "arccsc", "acsc", "sec", "sech", "arcsec", "asec", "cot", "coth", "arccot", "acot",
		"exp", "log", "ln", "det", "Pr", "tr", "trace", "Tr", "Trace", "erf":
		,  = .physicsExpression()
	case "evaluated", "eval":
		,  = .physicsEval(, )
	case "outerproduct", "dyad", "ketbra", "op":
		,  = .physicsKetBra()
	case "matrixelement", "matrixel", "mel":
		,  = .physicsMatrixElement()
	case "identitymatrix", "imat", "xmatrix", "xmat", "zeromatrix", "zmat", "paulimatrix", "pmat", "diagonalmatrix", "dmat", "antidiagonalmatrix", "admat":
		var  string
		,  = .physicsMatrixExpansion()
		if  == nil &&  != "" {
			.source = .source[:.pos] +  + .source[.pos:]
		}
	default:
		return nil, false, nil
	}
	return , true, 
}

// physicsEnvironment owns only matrix environments whose body contains a
// Physics matrix generator.  The hook is required because the local table
// parser splits rows and cells before parsing commands, while MathJax's stack
// parser lets \imat, \xmat, \pmat, and \dmat inject alignment separators.
func ( *parser) ( string) ( []*mml.Node,  bool,  error) {
	if !physicsMatrixEnvironment() || !physicsBodyHasMatrixGenerator(.source[.pos:]) {
		return nil, false, nil
	}
	 := "c"
	if strings.HasSuffix(, "*") {
		 := "c"
		, _,  = .readBrackets(&)
		if  != nil {
			return nil, true, 
		}
		,  = .completeArrayAlignment()
		if  != nil {
			return nil, true, 
		}
	}
	,  := .captureEnvironment()
	if  != nil {
		return nil, true, 
	}
	,  = .physicsRewriteMatrixBody()
	if  != nil {
		return nil, true, 
	}
	 := "T"
	if strings.Contains(, "small") {
		 = "S"
	}
	,  := .parseTable(, )
	if  != nil {
		return nil, true, 
	}
	 = applyColumnSpec(, )
	,  := matrixDelimiters()
	if  != "" ||  != "" {
		 = .leftRightFenced(, , , true)
	}
	return []*mml.Node{}, true, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	 := 
	if  == "trace" {
		 = "tr"
	} else if  == "Trace" {
		 = "Tr"
	}
	 := true
	switch  {
	case "exp", "det", "Pr", "tr", "trace", "Tr", "Trace", "erf":
		 = false
	}
	 := ""
	if  {
		var  error
		, _,  = .readBrackets(nil)
		if  != nil {
			return nil, 
		}
	}
	 := token("mi", )
	.TeXClass = mml.TeXClassOp
	.SetProperty("texClass", mml.TeXClassOp)
	var  *mml.Node = 
	if  != "" {
		,  := .parseArgumentString()
		if  != nil {
			return nil, 
		}
		 = node("msup", , )
	}
	.skipNextSpaces()
	if .pos >= len(.source) || .source[.pos] != '(' {
		// PhysicsMethods.Expression pushes the operator as an FnItem.  The
		// surrounding parser row decides whether a following item requires
		// ApplyFunction; a group boundary finalizes the function without it.
		.commandNamedFunction = true
		return []*mml.Node{}, nil
	}
	.pos++
	,  := .readUpToByte(')')
	if  != nil {
		return nil, 
	}
	,  := .parseContinuationString()
	if  != nil {
		return nil, 
	}
	// Physics' AutoOpen item emits fixed fence tokens around the argument; it
	// does not mark the resulting mrow as a \left...\right INNER atom.  That
	// keeps the function-to-opening-delimiter spacing at zero.
	return []*mml.Node{, .operator("\u2061", mml.TeXClassNone, nil), .fenced("(", , ")", true)}, nil
}

func ( *parser) ( string,  **derivativeAutoOpen) ([]*mml.Node, error) {
	 := .readStar()
	// Eval calls GetNext after GetStar; both skip source JavaScript whitespace.
	for .pos < len(.source) && internalTextSpace(.peekRune()) {
		.consumeRune()
	}
	if .pos >= len(.source) {
		return nil, texError("MissingArgFor", "Missing argument for \\%s", )
	}
	switch .source[.pos] {
	case '{':
		, ,  := .readArgument(, false)
		if  != nil {
			return nil, 
		}
		if  {
			 = "\\smash{" +  + "}"
		}
		// This expansion remains on the caller's input and macro budget.
		// Its Left item, rather than an eagerly parsed MML node, reaches
		// any pending script/function/position recipient.
		 := "\\left. " +  + " \\vphantom{\\int}\\right|"
		.source = .source[:.pos] +  + .source[.pos:]
		return nil, nil
	case '(', '[':
		 := .source[.pos]
		.pos++
		* = &derivativeAutoOpen{open: , closer: '|', openingConsumed: true,
			smash: , right: "\\vphantom{\\int}"}
		return nil, nil
	default:
		return nil, texError("MissingArgFor", "Missing argument for \\%s", )
	}
}

func ( *parser) ( string) ([]*mml.Node, error) {
	 := .readStar()
	, ,  := .readArgument(, false)
	if  != nil {
		return nil, 
	}
	// Source GetNext commits whitespace but reads a second argument only
	// after a literal opening brace. An explicitly empty bra stays empty.
	for .pos < len(.source) && internalTextSpace(.peekRune()) {
		.consumeRune()
	}
	 := 
	if .pos < len(.source) && .source[.pos] == '{' {
		, _,  = .readArgument(, true)
		if  != nil {
			return nil, 
		}
	}
	 := "\\left\\vert{" +  + "}\\middle\\rangle\\!\\middle\\langle{" +  + "}\\right\\vert"
	if  {
		 = "\\vert{" +  + "}\\rangle\\!\\langle{" +  + "}\\vert"
	}
	// One fresh source TexParser copies the full lexical environment and
	// shares its own macro budget across both generated operands.
	,  := .parseChild()
	if  != nil {
		return nil, 
	}
	return unwrapInferred(), nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	 := .readStar()
	 :=  && .readStar()
	 := make([]string, 3)
	for  := range  {
		var  error
		[], _,  = .readArgument(, false)
		if  != nil {
			return nil, 
		}
	}
	 := "\\left\\langle{" + [0] + "}\\right\\vert{" + [1] + "}\\left\\vert{" + [2] + "}\\right\\rangle"
	if  &&  {
		 = "\\left\\langle{" + [0] + "}\\middle\\vert{" + [1] + "}\\middle\\vert{" + [2] + "}\\right\\rangle"
	} else if  {
		 = "\\langle{" + [0] + "}\\vert{" + [1] + "}\\vert{" + [2] + "}\\rangle"
	}
	,  := .parseChild()
	if  != nil {
		return nil, 
	}
	return unwrapInferred(), nil
}

func physicsMatrixEnvironment( string) bool {
	 = strings.TrimSuffix(, "*")
	switch  {
	case "matrix", "smallmatrix", "pmatrix", "bmatrix", "Bmatrix", "vmatrix", "Vmatrix",
		"psmallmatrix", "bsmallmatrix", "Bsmallmatrix", "vsmallmatrix", "Vsmallmatrix":
		return true
	}
	return false
}

func physicsBodyHasMatrixGenerator( string) bool {
	for ,  := range []string{"imat", "identitymatrix", "xmat", "xmatrix", "zmat", "zeromatrix", "pmat", "paulimatrix", "dmat", "diagonalmatrix", "admat", "antidiagonalmatrix"} {
		if strings.Contains(, "\\"+) {
			return true
		}
	}
	return false
}

func ( *parser) ( string) (string, error) {
	var  strings.Builder
	 := 0
	for  := 0;  < len(); {
		if [] != '\\' {
			++
			continue
		}
		 := &parser{source: , pos:  + 1, state: .state, display: .display}
		 := .readControlSequence()
		if !physicsMatrixGenerator() {
			 = .pos
			continue
		}
		,  := .physicsMatrixExpansion()
		if  != nil {
			return "", 
		}
		.WriteString([:])
		.WriteString()
		 = .pos
		 = .pos
	}
	.WriteString([:])
	return .String(), nil
}

func physicsMatrixGenerator( string) bool {
	switch  {
	case "identitymatrix", "imat", "xmatrix", "xmat", "zeromatrix", "zmat", "paulimatrix", "pmat", "diagonalmatrix", "dmat", "antidiagonalmatrix", "admat":
		return true
	}
	return false
}

func ( *parser) ( string) (string, error) {
	switch  {
	case "identitymatrix", "imat":
		, ,  := .readArgument(, false)
		if  != nil {
			return "", 
		}
		,  := physicsParseInt()
		if ! {
			return "", texError("InvalidNumber", "Invalid number")
		}
		if  <= 1 {
			return "1", nil
		}
		,  := physicsMatrixDimension()
		if ! {
			return "", texError("InvalidNumber", "Invalid number")
		}
		 := make([]string, )
		for  := 0;  < ; ++ {
			 := make([]string, )
			for  := range  {
				[] = "0"
			}
			[] = "1"
			[] = strings.Join(, " & ")
		}
		return strings.Join(, "\\\\ "), nil

	case "xmatrix", "xmat", "zeromatrix", "zmat":
		 := .readStar()
		 := "0"
		var  error
		if  == "xmatrix" ||  == "xmat" {
			, _,  = .readArgument(, false)
			if  != nil {
				return "", 
			}
		}
		, ,  := .readArgument(, false)
		if  != nil {
			return "", 
		}
		, ,  := .readArgument(, false)
		if  != nil {
			return "", 
		}
		,  := physicsParseInt()
		,  := physicsParseInt()
		if ! || ! || jscompat.NumberString() !=  || jscompat.NumberString() !=  {
			return "", texError("InvalidNumber", "Invalid number")
		}
		,  := physicsMatrixDimension()
		,  := physicsMatrixDimension()
		if ! || ! {
			return "", texError("InvalidNumber", "Invalid number")
		}
		 := make([]string, )
		for  := 1;  <= ; ++ {
			 := make([]string, )
			for  := 1;  <= ; ++ {
				 := 
				if  && ( > 1 ||  > 1) {
					if  == 1 {
						 += "_{" + strconv.Itoa() + "}"
					} else if  == 1 {
						 += "_{" + strconv.Itoa() + "}"
					} else {
						 += "_{{" + strconv.Itoa() + "}{" + strconv.Itoa() + "}}"
					}
				}
				[-1] = 
			}
			[-1] = strings.Join(, " & ")
		}
		return strings.Join(, "\\\\ "), nil

	case "paulimatrix", "pmat":
		, ,  := .readArgument(, false)
		if  != nil {
			return "", 
		}
		if  == "" {
			return "", nil
		}
		 := [1:]
		switch [0] {
		case '0':
			 += " 1 & 0\\\\ 0 & 1"
		case '1', 'x':
			 += " 0 & 1\\\\ 1 & 0"
		case '2', 'y':
			 += " 0 & -i\\\\ i & 0"
		case '3', 'z':
			 += " 1 & 0\\\\ 0 & -1"
		}
		return , nil

	case "diagonalmatrix", "dmat", "antidiagonalmatrix", "admat":
		.skipNextSpaces()
		if .pos >= len(.source) || .source[.pos] != '{' {
			return "", nil
		}
		, ,  := .readArgument(, false)
		if  != nil {
			return "", 
		}
		 := splitTopLevel(, ',')
		 :=  == "antidiagonalmatrix" ||  == "admat"
		 := make([]string, len())
		for ,  := range  {
			 := 
			if  {
				 = len() -  - 1
			}
			[] = strings.Repeat("&", ) + "\\mqty{" +  + "}"
		}
		return strings.Join(, "\\\\ "), nil
	}
	return "", nil
}

// Physics parses dimensions with parseInt(text, 10), which produces a Number
// even for a negative decimal prefix outside Go's integer range.
func physicsParseInt( string) (float64, bool) {
	 = strings.TrimLeftFunc(, internalTextSpace)
	if  == "" {
		return 0, false
	}
	 := 0
	if [0] == '+' || [0] == '-' {
		++
	}
	 := 
	for  < len() && [] >= '0' && [] <= '9' {
		++
	}
	if  ==  {
		return 0, false
	}
	,  := strconv.ParseFloat([:], 64)
	return ,  == nil || math.IsInf(, 0)
}

func physicsMatrixDimension( float64) (int, bool) {
	if  <= 1 {
		return 1, true
	}
	// Preserve the existing positive Go integer representability boundary;
	// negative values have already taken the source's one-cell branch.
	if  >= math.Ldexp(1, strconv.IntSize-1) {
		return 0, false
	}
	return int(), true
}