package d2scenebuild

import (
	
	
	

	
	
	
	
	
	
)

type latexAssetKey struct {
	formula string
	color   color.NRGBA
}

type latexAsset struct {
	id     d2scene.AssetID
	width  float64
	height float64
}

func ( *builder) (, ,  string) (latexAsset, error) {
	if  := .ctx.Err();  != nil {
		return latexAsset{}, 
	}
	if  := .validateLatexInput(, );  != nil {
		return latexAsset{}, 
	}
	if  := .validateLatexImportOptions();  != nil {
		return latexAsset{}, 
	}
	,  := .latexCurrentColor(, +" latex currentColor")
	if  != nil {
		return latexAsset{}, 
	}
	 := latexAssetKey{formula: , color: }
	if ,  := .latexAssets[];  {
		return , nil
	}

	,  := d2latex.Render()
	if  != nil {
		return latexAsset{}, fmt.Errorf("scene: %s latex render: %w", , )
	}
	if  := .ctx.Err();  != nil {
		return latexAsset{}, 
	}
	,  := .remainingSVGImportLimits( + " latex")
	if  != nil {
		return latexAsset{}, 
	}
	,  := d2svgimport.ImportNodeWithOptions(.ctx, +" latex", []byte(), , d2svgimport.ImportOptions{
		CurrentColor: &,
	})
	if  != nil {
		return latexAsset{}, fmt.Errorf("scene: %s latex SVG: %w", , )
	}
	if  := .reserveSVGImport(+" latex", .Metrics);  != nil {
		return latexAsset{}, 
	}
	if  := .mergeSVGImportAssets(+" latex", .Assets);  != nil {
		return latexAsset{}, 
	}

	 := sha256.New()
	_, _ = .Write([]byte("d2-raster-latex\x00"))
	_, _ = .Write([]byte())
	_, _ = .Write([]byte{.R, .G, .B, .A})
	 := d2scene.AssetID(fmt.Sprintf("latex:%x", .Sum(nil)))
	 := d2scene.NewNode(nil)
	.ID = string() + ":content"
	.Transform = .ViewportTransform
	.Children = []*d2scene.Node{.Root}
	 := d2scene.Box{Width: .Width, Height: .Height}
	 := d2scene.NewNode(nil)
	.ID = string() + ":viewport"
	.Clip = boxClip()
	.Children = []*d2scene.Node{}
	.assets[] = d2scene.VectorAsset{ViewBox: , Root: }
	 := latexAsset{id: , width: .Width, height: .Height}
	.latexAssets[] = 
	return , nil
}

func ( *builder) (,  string) error {
	if  := d2latex.ValidateInput();  != nil {
		return fmt.Errorf("scene: %s %w", , )
	}
	return nil
}

func ( *builder) ( string) error {
	if .options.Assets == nil {
		return unsupported(, "label language latex without configured SVG import limits")
	}
	 := .options.Assets.SVGImportLimits
	if .MaxBytes <= 0 || .MaxDepth <= 0 || .MaxElements <= 0 || .MaxAttributes <= 0 ||
		.MaxAttributeBytes <= 0 || .MaxPathCommands <= 0 || .MaxTransformFunctions <= 0 ||
		.MaxUseDepth <= 0 || .MaxResources <= 0 {
		return fmt.Errorf("scene: %s latex label requires positive per-import SVG limits", )
	}
	 := .options.Assets.SVGImportBudget
	if .MaxSourceBytes <= 0 || .MaxElements <= 0 || .MaxAttributes <= 0 || .MaxAttributeBytes <= 0 ||
		.MaxPathCommands <= 0 || .MaxTransformFunctions <= 0 || .MaxDeclaredResources <= 0 || .MaxExpandedUseInstances <= 0 {
		return fmt.Errorf("scene: %s latex label requires positive document-wide SVG import budgets", )
	}
	return nil
}

func ( *builder) (,  string) (color.NRGBA, error) {
	if  == "" {
		return color.NRGBA{A: 255}, nil
	}
	,  := .paint(, )
	if  != nil {
		return color.NRGBA{}, 
	}
	if  == nil {
		// Invalid CSS colors such as color:none do not override the initial black.
		return color.NRGBA{A: 255}, nil
	}
	,  := .(d2scene.SolidPaint)
	if ! {
		return color.NRGBA{}, fmt.Errorf("scene: %s must resolve to a solid color", )
	}
	return .Color, nil
}

func ( *builder) (, , ,  string,  *geo.Point) (*d2scene.Node, error) {
	if  == nil || !finite(.X) || !finite(.Y) {
		return nil, invalidField(, "labelPosition", nil, "must resolve to a finite LaTeX label origin")
	}
	,  := .resolveLatexAsset(, , )
	if  != nil {
		return nil, 
	}
	 := d2scene.NewNode(d2scene.Image{
		Asset: .id,
		Box: d2scene.Box{
			X: .X, Y: .Y,
			Width: .width, Height: .height,
		},
		Aspect: defaultImageAspect,
	})
	.ID = 
	return , nil
}

// latexShapeLabelTopLeft places border labels against the inner box; 3D and
// multiple effects do not expand it.
func latexShapeLabelTopLeft( d2target.Shape) *geo.Point {
	 := label.FromString(.LabelPosition)
	if  == label.Unset {
		 = label.InsideMiddleCenter
	}
	 := targetGeometry()
	 := .GetInnerBox()
	if .IsOutside() {
		 = .GetBox()
	}
	return .GetPointOnBox(
		, label.PADDING,
		float64(.LabelWidth), float64(.LabelHeight),
	)
}