package d2svg

import (
	
	
	
	
	
	
	
	

	
	
	
	
)

func renderIsometric( *d2target.Diagram,  *RenderOpts) ([]byte, error) {
	return renderIsometricValidated(context.Background(), , , nil)
}

// RenderIsometric produces the native vector geometry with the same document
// options as Render. Native options can supply an asset resolver, fallback fonts,
// and a maximum canvas; their dimensions are unscaled. Rendering preserves
// the compiled layout, including nested containers. Like other native exports,
// this function does not load external assets unless a resolver is supplied.
//
// Responsive dark themes, SVG appendices, and multi-board SVG animation are not
// yet implemented by this renderer. Static multi-board SVG files are supported
// through RenderMultiboard.
func ( context.Context,  *d2target.Diagram,  *RenderOpts,  *d2isometricimg.Options) ([]byte, error) {
	if  == nil {
		return nil, fmt.Errorf("isometric rendering requires a diagram")
	}
	if  := validateRenderLinks();  != nil {
		return nil, 
	}
	if  := d2target.ValidateRenderTarget();  != nil {
		return nil, 
	}
	if  := validateRenderPaints(, );  != nil {
		return nil, 
	}
	return renderIsometricValidated(, , , )
}

func renderIsometricValidated( context.Context,  *d2target.Diagram,  *RenderOpts,  *d2isometricimg.Options) ([]byte, error) {
	if  == nil {
		 = &RenderOpts{}
	}
	if .Sketch != nil && *.Sketch {
		return nil, fmt.Errorf("sketch cannot be combined with isometric rendering")
	}
	if .DarkThemeID != nil || .DarkThemeOverrides != nil {
		return nil, fmt.Errorf("isometric rendering does not yet support responsive dark themes; select a single theme instead")
	}
	if .MasterID != "" {
		return nil, fmt.Errorf("isometric rendering does not yet support multi-board SVG animation")
	}
	if .Scale != nil && (math.IsNaN(*.Scale) || math.IsInf(*.Scale, 0) || *.Scale <= 0) {
		return nil, fmt.Errorf("isometric SVG scale must be finite and positive")
	}
	 := d2isometricimg.Options{FitContent: true}
	if  != nil {
		 = *
	}
	.Format = d2isometricimg.SVG
	.Render.ThemeID, .Render.ThemeOverrides = .ThemeID, .ThemeOverrides
	,  := d2isometricimg.Render(, , &)
	if  != nil {
		return nil, 
	}
	return wrapIsometricSVG(, , )
}

var isometricSVGRoot = regexp.MustCompile(`^<svg\b[^>]*>`)
var isometricSVGID = regexp.MustCompile(`\bid="([^"]+)"`)

// The native writer emits controlled SVG markup. Rewrite resource definitions
// and references together so multiple salted documents can share an HTML page.
// Actual link destinations are left alone unless they name a defined resource.
func namespaceIsometricSVG( []byte,  string) []byte {
	 := isometricSVGID.FindAllSubmatch(, -1)
	if len() == 0 {
		return 
	}
	 := make([]string, 0, len()*6)
	 := make(map[string]bool, len())
	for ,  := range  {
		 := string([1])
		if [] {
			continue
		}
		[] = true
		 = append(,
			`id="`++`"`, `id="`+++`"`,
			`url(#`++`)`, `url(#`+++`)`,
			`href="#`++`"`, `href="#`+++`"`)
	}
	return []byte(strings.NewReplacer(...).Replace(string()))
}

func wrapIsometricSVG( *d2target.Diagram,  []byte,  *RenderOpts) ([]byte, error) {
	var  struct {
		  int64 `xml:"width,attr"`
		 int64 `xml:"height,attr"`
	}
	 := xml.NewDecoder(bytes.NewReader())
	,  := .Token()
	if  != nil {
		return nil, fmt.Errorf("read isometric SVG dimensions: %w", )
	}
	,  := .(xml.StartElement)
	if ! || .Name.Local != "svg" {
		return nil, fmt.Errorf("native isometric output is not an SVG")
	}
	for ,  := range .Attr {
		switch .Name.Local {
		case "width":
			.,  = strconv.ParseInt(.Value, 10, 64)
		case "height":
			.,  = strconv.ParseInt(.Value, 10, 64)
		}
		if  != nil {
			return nil, fmt.Errorf("read isometric SVG dimensions: %w", )
		}
	}
	 := int64(DEFAULT_PADDING)
	if .Pad != nil {
		 = *.Pad
	}
	// Bound arithmetic before calculating two-sided padding, just as the flat
	// SVG renderer does. Negative padding deliberately crops the viewport.
	 := int64(^uint(0) >> 1)
	 := - - 1
	,  := checkedIntAdd(, , , )
	if ! {
		return nil, invalidPaddingError()
	}
	,  := checkedIntAdd(., , , )
	if ! ||  <= 0 {
		return nil, invalidPaddingError()
	}
	,  := checkedIntAdd(., , , )
	if ! ||  <= 0 {
		return nil, invalidPaddingError()
	}
	var  []svg.Attribute
	if .Scale != nil {
		,  := math.Ceil(float64()**.Scale), math.Ceil(float64()**.Scale)
		if math.IsInf(, 0) || math.IsInf(, 0) ||  > float64() ||  > float64() {
			return nil, fmt.Errorf("isometric SVG scale produces invalid dimensions")
		}
		 = []svg.Attribute{svg.Attr("width", strconv.FormatFloat(, 'f', 0, 64)), svg.Attr("height", strconv.FormatFloat(, 'f', 0, 64))}
	}
	,  := .HashID(.Salt)
	if  != nil {
		return nil, 
	}
	 = namespaceIsometricSVG(, +"-isometric-")
	 := isometricSVGRoot.FindIndex()
	if  == nil || !bytes.HasSuffix(, []byte("</svg>")) {
		return nil, fmt.Errorf("native isometric output has an invalid SVG envelope")
	}
	 := [[1] : len()-len("</svg>")]
	 := "<rect" + svg.RenderAttributes(svg.IntAttr("x", int(-)), svg.IntAttr("y", int(-)), svg.IntAttr("width", int()), svg.IntAttr("height", int()))
	 = bytes.Replace(, []byte(`<rect width="100%" height="100%"`), []byte(), 1)
	var  bytes.Buffer
	if .NoXMLTag == nil || !*.NoXMLTag {
		.WriteString(`<?xml version="1.0" encoding="utf-8"?>`)
	}
	 := "xMinYMin"
	if .Center != nil && *.Center {
		 = "xMidYMid"
	}
	 := []svg.Attribute{svg.Attr("xmlns", "http://www.w3.org/2000/svg"), svg.Attr("xmlns:xlink", "http://www.w3.org/1999/xlink")}
	if .OmitVersion == nil || !*.OmitVersion {
		 = append(, svg.Attr("data-d2-version", version.Version))
	}
	 = append(, svg.Attr("preserveAspectRatio", +" meet"), svg.Attr("viewBox", fmt.Sprintf("0 0 %d %d", , )))
	 = append(, ...)
	.WriteString(svg.OpenElement("svg", ...))
	.WriteString(svg.OpenElement("svg", svg.Attr("class", +" d2-svg d2-isometric"), svg.IntAttr("width", int()), svg.IntAttr("height", int()), svg.Attr("viewBox", fmt.Sprintf("%d %d %d %d", -, -, , )), svg.Attr("role", "img")))
	.Write()
	.WriteString(`</svg></svg>`)
	if .Len() > d2isometricimg.MaxOutputBytes {
		return nil, fmt.Errorf("isometric SVG document exceeds output byte limit")
	}
	return .Bytes(), nil
}