// Copyright (c) 2020-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/mathtools/MathtoolsMethods.ts,
// MathtoolsItems.ts, and MathtoolsUtil.ts.

package tex

import (
	

	
	
)

func mathtoolsEnvironmentHasSpecial( string) bool {
	for ,  := range []string{
		"\\Aboxed", "\\vdotswithin", "\\shortvdotswithin",
		"\\MTFlushSpaceAbove", "\\MTFlushSpaceBelow", "\\shoveleft", "\\shoveright",
	} {
		if strings.Contains(, ) {
			return true
		}
	}
	return false
}

// mathtoolsSmallMatrix ports MtSmallMatrix's Array arguments.  The starred
// forms read their alignment option; the fixed non-starred delimiter forms
// use the source-map's literal center alignment.
func ( *parser) ( string) ([]*mml.Node, error) {
	 := "c"
	if strings.HasSuffix(, "*") {
		 := .mathtoolsOption("smallmatrix-align")
		var  error
		, _,  = .readBrackets(&)
		if  != nil {
			return nil, 
		}
	}
	,  := .completeArrayAlignment()
	if  != nil {
		return nil, 
	}
	,  := .captureEnvironment()
	if  != nil {
		return nil, 
	}
	,  := .parseTable(, "S", ".2em")
	if  != nil {
		return nil, 
	}
	resetTableAttributes(,
		"columnalign", "center",
		"columnspacing", ".333em",
		"rowspacing", tableRowSpacing(),
		"displaystyle", false,
	)
	.SetProperty("useHeight", false)
	.SetProperty("scriptlevel", 1)
	 = applyColumnSpec(, )
	,  := matrixDelimiters()
	if  != "" ||  != "" {
		 = .leftRightFenced(, , , true)
	}
	return []*mml.Node{finishArrayRules()}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	 := .mathtoolsOption("multlined-pos")
	, ,  := .readBrackets(&)
	if  != nil {
		return nil, 
	}
	 := ""
	if  != "" {
		, _,  = .readBrackets(nil)
		if  != nil {
			return nil, 
		}
	}
	if  && !strings.Contains("cbt", ) {
		,  = , 
	}
	,  := .captureEnvironment()
	if  != nil {
		return nil, 
	}
	, ,  := .parseMultlineBody(, false)
	if  != nil {
		return nil, 
	}
	 := .Children
	if len() > 1 {
		 := [0].Children[0]
		if ,  := .Attributes.Get("columnalign");  != "right" {
			 := .mathtoolsOption("firstline-afterskip")
			if  == "" {
				 = .mathtoolsOption("multlinegap")
			}
			mathtoolsAppendCell(, mathtoolsSpace(), false)
		}
		 := [len()-1].Children[0]
		if ,  := .Attributes.Get("columnalign");  != "left" {
			 := .mathtoolsOption("lastline-preskip")
			if  == "" {
				 = .mathtoolsOption("multlinegap")
			}
			mathtoolsAppendCell(, mathtoolsSpace(), true)
		}
	}
	alignAMSMultlineCells()
	.Attributes.Set("displaystyle", true)
	.apply(, ".5em")
	if  == "" {
		 = "auto"
	}
	.Attributes.Set("width", )
	.Attributes.Set("columnwidth", "100%")
	if  == "t" {
		.Attributes.Set("align", "baseline 1")
	} else if  == "b" {
		.Attributes.Set("align", "baseline -1")
	} else {
		.Attributes.Set("align", "axis")
	}
	return []*mml.Node{finishArrayRules()}, nil
}

func mathtoolsAppendCell(,  *mml.Node,  bool) {
	if len(.Children) == 0 {
		.SetChildren([]*mml.Node{forcedRow([]*mml.Node{}, true)})
		return
	}
	 := .Children[0]
	 := unwrapInferred()
	if  {
		 = append([]*mml.Node{}, ...)
	} else {
		 = append(, )
	}
	.SetChildren([]*mml.Node{forcedRow(, true)})
}

func ( *parser) ( string) ([]*mml.Node, error) {
	// GetDimen reports parser.currentCS (\begin), not its descriptive name.
	,  := .readDimension("begin")
	if  != nil {
		return nil, 
	}
	,  := .parseEnvironmentContinuation(.environmentOwner)
	if  != nil {
		return nil, 
	}
	// SpreadLines applies to the popped item's mtable, or to each immediate
	// child if toMml() returned an inferred row. It never descends through
	// authored fences, scripts, or other wrappers.
	if  := mathtoolsSpreadPop(, &);  != nil {
		return nil, 
	}
	return unwrapInferred(), nil
}

// mathtoolsAddRowSpacing ports MathtoolsUtil.addRowSpacing.  Spreadlines adds
// its dimension to each existing table-row spacing rather than replacing the
// package-specific base spacing.
func mathtoolsAddRowSpacing( *mml.Node,  string) {
	,  := .Attributes.Get("rowspacing")
	 := strings.Fields(sourceValueString())
	if len() == 0 {
		 = []string{"1ex"}
	}
	 := layout.Length2Em(, 0, 1, 16)
	for ,  := range  {
		 := layout.Length2Em(, 0, 1, 16) + 
		if  < 0 {
			 = 0
		}
		[] = layout.Em()
	}
	.Attributes.Set("rowspacing", strings.Join(, " "))
}

func ( *parser) ( string) ([]*mml.Node, error) {
	,  := .captureEnvironment()
	if  != nil {
		return nil, 
	}
	 := node("mtable")
	var  []*mml.Node
	 := &arrayRowSpacing{}
	 = .parseArrayBody(, arrayBodyOwner{
		rules: newArrayRules(),
		prepare: func( *parser) ([]*mml.Node, error) {
			if len() != 1 {
				return nil, nil
			}
			return .prepareMatrixCasesText()
		},
		hasEntries: func() bool { return len() != 0 },
		endEntry: func( []*mml.Node,  *arrayCellState) error {
			 = append(, arrayCellNode(.finish(matrixCellContent(), len())))
			return nil
		},
		endRow: func() error {
			.AppendChild(node("mtr", ...))
			 = nil
			.rows++
			return nil
		},
		addSpacing: .add,
	})
	if  != nil {
		return nil, 
	}
	.apply(, ".2em")
	.Attributes.Set("columnspacing", "1em")
	.Attributes.Set("columnalign", "left")
	if strings.HasPrefix(, "d") {
		.Attributes.Set("displaystyle", true)
	}
	,  := "{", ""
	if strings.Contains(, "rcases") {
		,  = "", "}"
	}
	return []*mml.Node{.leftRightFenced(, finishArrayRules(), , true)}, nil
}

func ( *parser) ( string) ([]*mml.Node, error) {
	if  := .checkEquationEnvironment();  != nil {
		return nil, 
	}
	,  := .captureEnvironment()
	if  != nil {
		return nil, 
	}
	return .mathtoolsMultlineBody()
}

func ( *parser) ( string) ([]*mml.Node, error) {
	, ,  := .parseMultlineBody(, true)
	if  != nil {
		return nil, 
	}
	finishAMSMultlineTable()
	.apply(, ".5em")

	return []*mml.Node{finishArrayRules()}, nil
}

func mathtoolsCommandArgument(,  string) (string, error) {
	, , ,  := mathtoolsCommandParts(, )
	return , 
}

func mathtoolsCommandParts(,  string) (string, string, string, error) {
	 := strings.Index(, "\\"+)
	if  < 0 {
		return "", "", "", texError("MissingArgFor", "Missing argument for \\%s", )
	}
	 := &parser{source: , pos:  + len() + 1}
	, ,  := .readArgument(, false)
	if  != nil {
		return "", "", "", 
	}
	return [:], , [.pos:], nil
}

func mathtoolsOnlyCommandArgument(,  string) (string, error) {
	return mathtoolsCommandArgument(strings.TrimSpace(), )
}