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

package svg

import (
	
	

	
)

// multiscriptPair is one sub/sup pair.  A nil entry is the empty mrow that
// MathJax inserts when fixMmultiscripts repairs an odd script list.
type multiscriptPair struct {
	sub, sup       *wrapper
	subbox, supbox *layout.BBox
	width          float64
}

type multiscriptData struct {
	base      *wrapper
	post, pre []multiscriptPair
	postSub   *layout.BBox
	postSup   *layout.BBox
	preSub    *layout.BBox
	preSup    *layout.BBox
}

func ( *wrapper) () multiscriptData {
	 := multiscriptData{
		postSub: layout.EmptyBBox(), postSup: layout.EmptyBBox(),
		preSub: layout.EmptyBBox(), preSup: layout.EmptyBBox(),
	}
	if len(.children) == 0 {
		return 
	}
	.base = .children[0]
	,  := false, true
	for ,  := range .children[1:] {
		if .node.Kind == "mprescripts" {
			,  = true, true
			continue
		}
		 := &.post
		if  {
			 = &.pre
		}
		if  {
			* = append(*, multiscriptPair{sub: })
		} else {
			if len(*) == 0 {
				* = append(*, multiscriptPair{})
			}
			(*)[len(*)-1].sup = 
		}
		 = !
	}
	.postSub, .postSup = combineMultiscriptPairs(.post)
	.preSub, .preSup = combineMultiscriptPairs(.pre)
	return 
}

func emptyScriptBBox() *layout.BBox { return layout.ZeroBBox() }

func scriptPairBBox( *wrapper) *layout.BBox {
	if  == nil {
		return emptyScriptBBox()
	}
	return .outerBBox()
}

func combineMultiscriptPairs( []multiscriptPair) (*layout.BBox, *layout.BBox) {
	,  := layout.EmptyBBox(), layout.EmptyBBox()
	for  := range  {
		 := &[]
		.subbox, .supbox = scriptPairBBox(.sub), scriptPairBBox(.sup)
		 := .subbox.W * .subbox.RScale
		 := .supbox.W * .supbox.RScale
		.width = math.Max(, )
		.W += .width
		.W += .width
		.H = math.Max(.H, .subbox.H*.subbox.RScale)
		.D = math.Max(.D, .subbox.D*.subbox.RScale)
		.H = math.Max(.H, .supbox.H*.supbox.RScale)
		.D = math.Max(.D, .supbox.D*.supbox.RScale)
	}
	return , 
}

func combineMultiscriptPrePost(,  *layout.BBox) *layout.BBox {
	 := layout.NewBBox(.W, .H, .D)
	.Combine(, 0, 0)
	return 
}

// multiscriptPrimary is CommonScriptbase.scriptChild.  MathJax 3.2.2 keeps
// that inherited getter for mmultiscripts, so the first post-script supplies
// the initial TeX drop calculation even when the combined lists are wider.
func ( *wrapper) () *wrapper {
	if len(.children) < 2 {
		return nil
	}
	return .children[1]
}

func ( *wrapper) () float64 {
	 := .multiscriptPrimary()
	if  == nil {
		return 0
	}
	return .supShift()
}

func ( *wrapper) () float64 {
	 := .multiscriptPrimary()
	if  == nil {
		return 0
	}
	return .subShift(, .renderer.params.Sub1)
}

// multiscriptUVQ returns the superscript and subscript baseline offsets.  The
// single-script branches intentionally preserve MathJax 3.2.2's source-shaped
// CommonMmultiscripts.getUVQ behavior.
func ( *wrapper) (,  *layout.BBox) (, ,  float64) {
	if .H == 0 && .D == 0 {
		return .multiscriptGetU(), 0, 0
	}
	if .H == 0 && .D == 0 {
		return -.multiscriptGetV(), 0, 0
	}

	 := .multiscriptPrimary()
	if  == nil || .scriptBaseCore() == nil {
		return 0, 0, 0
	}
	 := .renderer.params
	 = .multiscriptGetU()
	 := .baseCharZero(.scriptBaseCore().outerBBox().D*.baseScale() + .SubDrop*.RScale)
	 := layout.Length2Em(attribute(.node, "subscriptshift", ""), .Sub2, .bbox.Scale, .renderer.pxPerEm)
	 := math.Max(, )
	 := 3 * .Rule
	 = ( - .D*.RScale) - (.H*.RScale - )
	if  <  {
		 +=  - 
		 := .8*.XHeight - ( - .D*.RScale)
		if  > 0 {
			 += 
			 -= 
		}
	}
	 = math.Max(layout.Length2Em(attribute(.node, "superscriptshift", ""), , .bbox.Scale, .renderer.pxPerEm), )
	 = math.Max(layout.Length2Em(attribute(.node, "subscriptshift", ""), , .bbox.Scale, .renderer.pxPerEm), )
	 = ( - .D*.RScale) - (.H*.RScale - )
	return , -, 
}

func ( *wrapper) ( *layout.BBox) {
	 := .getMultiscriptData()
	if .base == nil {
		.Empty()
		.Clean()
		return
	}
	 := combineMultiscriptPrePost(.preSub, .postSub)
	 := combineMultiscriptPrePost(.preSup, .postSup)
	, ,  := .multiscriptUVQ(, )
	 := .renderer.params.ScriptSpace

	.Empty()
	if len(.pre) != 0 {
		.Combine(.preSup, , )
		.Combine(.preSub, , )
	}
	.Append(.base.outerBBox())
	if len(.post) != 0 {
		 := .W
		.Combine(.postSup, , )
		.Combine(.postSub, , )
		.W += 
	}
	.Clean()
}

func multiscriptAlign( string, ,  float64) float64 {
	// MathJax rounds the scaled width before AlignX subtracts it. Keep that
	// rounding even when this helper is inlined into a multiplication.
	 = float64()
	switch  {
	case "center":
		return ( - ) / 2
	case "right":
		return  - 
	default:
		return 0
	}
}

func ( *wrapper) () (,  string) {
	 := "right left"
	if ,  := .node.Property("scriptalign");  {
		if ,  := .(string);  &&  != "" {
			 = 
		}
	}
	 := strings.Fields( + " " + )
	return [0], [1]
}

func ( *wrapper) ( *Element,  []multiscriptPair, , ,  float64,  string) float64 {
	 := NewElement("g")
	 := NewElement("g")
	.Append(, )
	.place(, , )
	.place(, , )
	 := 0.0
	for ,  := range  {
		,  := scriptPairBBox(.sub), scriptPairBBox(.sup)
		 := math.Max(.W*.RScale, .W*.RScale)
		if .sub != nil {
			.sub.toSVG()
			.sub.place(+multiscriptAlign(, .W*.RScale, ), 0)
		}
		if .sup != nil {
			.sup.toSVG()
			.sup.place(+multiscriptAlign(, .W*.RScale, ), 0)
		}
		 += 
	}
	return  + 
}

func ( *wrapper) ( *Element) {
	 := .standardSVG()
	 := .getMultiscriptData()
	if .base == nil {
		return
	}
	,  := .multiscriptAlignment()
	 := combineMultiscriptPrePost(.preSub, .postSub)
	 := combineMultiscriptPrePost(.preSup, .postSup)
	, ,  := .multiscriptUVQ(, )

	 := 0.0
	if len(.pre) != 0 {
		 = .addMultiscripts(, .pre, .renderer.params.ScriptSpace, , , )
	}
	.base.toSVG()
	.base.place(, 0)
	 += .base.outerBBox().W
	if len(.post) != 0 {
		.addMultiscripts(, .post, , , , )
	}
}