package d2isometricimg

import (
	
	
	
	
	
	

	
	
	
	
	
	
)

func nativeStructuredNode( d2isometric.Node) bool {
	return .Type == d2target.ShapeClass || .Type == d2target.ShapeSQLTable
}

// Row coordinates are the compiler's original document coordinates. Gutters
// consume existing vertical padding, never the allocated row centers or ports.
type nativeStructuredRow struct {
	z, depth    float64
	back, front float64
	section     string
}

func nativeStructuredRows( d2target.Shape) []nativeStructuredRow {
	 := len(.Columns)
	 := 1
	if .Type == d2target.ShapeClass {
		,  = len(.Fields)+len(.Methods), 2
	}
	 := float64(.Height) / float64(+)
	 :=  * float64()
	if .Type == d2target.ShapeClass {
		 = max(, float64(.LabelHeight)+10)
	}
	 := []nativeStructuredRow{{depth: , section: "header"}}
	for  := 0;  < ; ++ {
		 := "field"
		if .Type == d2target.ShapeClass &&  >= len(.Fields) {
			 = "method"
		}
		// This coordinate also defines the retained SVG viewport. Keep its
		// multiply and add identical on CPUs with and without fused arithmetic.
		 :=  + float64(float64()*)
		// A multiline class header can use more than its nominal two rows.
		// The ordinary renderer clips the last cells at the source viewport;
		// keep that same boundary instead of extending the physical component.
		 = append(, nativeStructuredRow{z: , depth: min(, max(0, float64(.Height)-)), section: })
	}
	for  := range  {
		 := &[]
		 := 3.8
		if  == 0 {
			 = 1.2
		}
		// Very small or explicitly tight rows keep all available text space.
		 := max(0, (.depth-float64(.FontSize))/2-1)
		.back, .front = min(, *.5), min(, *.5)
		if  > 1 && .section != [-1].section {
			.back = min(7.5, *.8)
		}
		if  > 0 && +1 < len() && .section != [+1].section {
			.front = min(7.5, *.8)
		}
	}
	return 
}

func nativeStructuredTextRow( string,  d2target.Shape) int {
	if strings.Contains(, "header-label") {
		return 0
	}
	 := strings.Split(, ":")
	if len() < 4 {
		return -1
	}
	,  := strconv.Atoi([2])
	if  != nil {
		return -1
	}
	if [1] == "class-method" {
		 += len(.Fields)
	}
	return  + 1
}

type nativeStructuredCell struct {
	node *d2scene.Node
	row  int
}

// Keep the existing source, row, font and texture admission limits. The scene
// supplies native TextRuns, including exact baselines and resolved font assets;
// only those individual cells are rasterized onto the physical row solids.
func ( *meshBuilder) ( d2isometric.Node) (*d2scene.Document, []nativeStructuredCell, error) {
	 := .rich
	if  == nil {
		return nil, nil, fmt.Errorf("native structured shape requires a rich label painter")
	}
	if .used >= .count {
		return nil, nil, fmt.Errorf("isometric rich label allocation exceeds its declared count")
	}
	, ,  := richSourceSize(.Metadata.Original)
	if  != nil {
		return nil, nil, 
	}
	if  > maxRichSourceBytes-.sourceBytes ||  > maxRichTotalRows-.rows {
		return nil, nil, fmt.Errorf("isometric rich labels exceed aggregate source or row budget")
	}
	.sourceBytes += 
	.rows += 
	.used++
	 := labelSurface{width: .Size.X, depth: .Size.Z}
	 := .printStyle(, .Metadata.Original.Text, .FontColor, .Opacity, "node")
	,  := richLabelDocumentWithResources(.ctx, .Metadata.Original, , .fallbackFonts, .themeID, .themeOverrides, .primary, .mono)
	if  != nil {
		return nil, nil, 
	}
	var  []nativeStructuredCell
	var  func(*d2scene.Node)
	 = func( *d2scene.Node) {
		if  == nil {
			return
		}
		if ,  := .Primitive.(d2scene.TextRun);  && .Text != "" {
			 = append(, nativeStructuredCell{node: , row: nativeStructuredTextRow(.ID, .Metadata.Original)})
		}
		for ,  := range .Children {
			()
		}
	}
	(.Root)
	return , , nil
}

func ( *meshBuilder) ( d2isometric.Node) {
	if .err != nil || .Opacity <= 0 {
		return
	}
	if .Opacity < 1 {
		// Opacity belongs to the source object. Resolve visibility between
		// its plinth, rails and printed cells before applying that fade once.
		 := &nativeOpacityGroup{Opacity: .Opacity}
		 := len(.triangles)
		.Opacity = 1
		defer func() {
			for  := ;  < len(.triangles); ++ {
				.triangles[].OpacityGroup = 
			}
		}()
	}
	, ,  := .structuredDocument()
	if  != nil {
		.err = fmt.Errorf("native structured shape %q: %w", .ID, )
		return
	}
	 := .Metadata.Original
	 := nativeStructuredRows()
	 := .faceMaxPixels
	if  > 0 {
		 := 1
		if .Multiple {
			++
		}
		.faceMaxPixels = max(1, /int64(*(len()+1)))
		defer func() { .faceMaxPixels =  }()
	}
	,  := .Size.X/float64(.Width), .Size.Z/float64(.Height)
	 := .Position.Y - .Size.Y/2
	 := nativeCanonicalHeight(, .scale)
	// The shared flat route plane is .01 above the compiled node floor.
	// Begin each row wall there so row ports meet that row's physical wall,
	// rather than ending on a continuous backing below all of the rows.
	, ,  := +.01, +, +*.32/.46
	for  := 1;  >= 0; -- {
		if  == 1 && !.Multiple {
			continue
		}
		 := 
		.Position.X += float64() * d2target.MULTIPLE_OFFSET * 
		.Position.Z -= float64() * d2target.MULTIPLE_OFFSET * 
		 := -float64() * min(.045, *.25)
		.structuredRail(, 0, float64(.Height), ++.nodeSupportDrop, +, .Fill)
		for ,  := range  {
			,  := , .Stroke
			if  == 0 {
				,  = , .Fill
			}
			.structuredRail(, .z+.back, .depth-.back-.front, +, +, )
		}
	}
	for ,  := range  {
		if .row < 0 || .row >= len() {
			.err = fmt.Errorf("native structured shape %q has an unassigned text cell %q", .ID, .node.ID)
			return
		}
		 := 
		if .row == 0 {
			 = 
		}
		.structuredCell(, .node, [.row], , , len())
	}
	if .Icon != nil {
		 := nativeStructuredIconSurface(, +.003)
		,  := .icons.texture(.Icon, .width, .depth, 0)
		if  != nil {
			.err = fmt.Errorf("isometric icon for %q: %w", .ID, )
			return
		}
		.surfaceTexture(, , .Opacity)
	}
}

func nativeStructuredIconSurface( d2isometric.Node,  float64) labelSurface {
	 := .Metadata.Original
	 := labelSurface{center: nv(.Position.X, , .Position.Z), width: .Size.X, depth: .Size.Z}
	 := label.FromString(.IconPosition)
	if !.IsOutside() {
		// The full source face is needed to locate the existing header;
		// passing only its strip would subdivide that strip a second time.
		,  := surfaceIconLayout(, , .Size.X/float64(.Width), "node")
		return 
	}
	// The compiler reserves outside icon space independently of the header.
	// Keep its native placement: narrow SQL headers have no spare inside lane
	// in which to move an outside icon without covering their source label.
	 := geo.NewBox(geo.NewPoint(0, 0), float64(.Width), float64(.Height))
	 := float64(d2target.GetIconSize(, .IconPosition))
	 := .GetPointOnBox(, label.PADDING, , )
	,  := .Size.X/float64(.Width), .Size.Z/float64(.Height)
	return labelSurface{center: nv(.Position.X-.Size.X/2+(.X+/2)*, , .Position.Z-.Size.Z/2+(.Y+/2)*), width:  * , depth:  * }
}

func ( *meshBuilder) ( d2isometric.Node, , , ,  float64,  string) {
	if  <= 0 ||  <=  || .err != nil {
		return
	}
	 := .Metadata.Original
	,  := .Size.X/float64(.Width), .Size.Z/float64(.Height)
	// Use D2's rounded rectangle contour, retaining the source radius and
	// modifiers without replacing a rounded outline with a beveled cuboid.
	 := nativeFaceSource(, )
	.Type, .Text = d2target.ShapeRectangle, d2target.Text{}
	.Fill, .Stroke = , .Fill
	.Width, .Height = .Width, max(1, int(math.Round()))
	.LabelPosition = ""
	.BorderRadius = min(.BorderRadius, .Height/2)
	,  := nativeShapeProfiles()
	if  != nil {
		.err = 
		return
	}
	 := len(.triangles)
	 := nativeMaterial(, .72, 0, .Opacity)
	 := .Opacity < 1 || nativePaint(.Fill, "#263c4e").A < 255 || .StrokeDash != 0 || .DoubleBorder || .FillPattern != ""
	 := 
	if  {
		 = nil
	}
	for ,  := range  {
		 := make([]Vec, len())
		for ,  := range  {
			[] = nv(.Position.X-.Size.X/2+float64(.X*), , .Position.Z-.Size.Z/2+float64((+.Z*/float64(.Height))*))
		}
		.extrudedProfile(, , , )
	}
	if  {
		, ,  := .nativeFaceLayers(, .Opacity)
		.center = nv(.Position.X-.Size.X/2+float64(.center.X*), +.0005, .Position.Z-.Size.Z/2+float64((+.center.Z*/float64(.Height))*))
		.width, .depth = .width*, .depth*/float64(.Height)*
		 := len(.triangles)
		.surfaceTexture(, , .Opacity)
		for  := ;  < len(.triangles); ++ {
			.triangles[].Material.Unlit = false
			.triangles[].NoDepthWrite = false
			.triangles[].CastShadow = true
		}
		.surfaceTexture(, , .Opacity)
	}
	 := 
	.Type, .Fill, .Stroke, .StrokeExplicit = d2target.ShapeRectangle, , .Fill, true
	.Metadata.Original = 
	.classicInkEdges(, .triangles[:])
}

func ( *meshBuilder) ( *d2scene.Document,  *d2scene.Node,  nativeStructuredRow,  d2isometric.Node,  float64,  int) {
	if .err != nil {
		return
	}
	 := .Metadata.Original
	,  := .Size.X/float64(.Width), .Size.Z/float64(.Height)
	 := d2scene.Box{Y: .z, Width: float64(.Width), Height: .depth}
	if .Height <= 0 {
		return
	}
	 := max(1, min(4*1024*1024, maxRichPixels/max(1, .rich.count))/max(1, ))
	,  := surfaceTextureDimensionsAtDensity(.Size.X, .depth*, 4096, , .outputDensity)
	if * > maxRichPixels-.rich.pixels {
		.err = fmt.Errorf("isometric rich labels exceed texture pixel budget")
		return
	}
	.rich.pixels +=  * 
	// A cell owns just its text primitive. No header, border, row fill or
	// other cell is included in this transparent decal.
	 := *
	.Root = 
	.ViewBox, .LogicalWidth, .LogicalHeight = , float64(), float64()
	.ViewportFit = d2scene.ViewportStretch
	,  := d2raster.Render(.ctx, &, richRasterOptions())
	if  != nil {
		.err = 
		return
	}
	 := image.NewRGBA(.Bounds())
	draw.Draw(, .Bounds(), , .Bounds().Min, draw.Src)
	if  := retainNativeVectorSurface(.ctx, , &);  != nil {
		.err = 
		return
	}
	 := labelSurface{center: nv(.Position.X, +.003, .Position.Z-.Size.Z/2+(.z+.depth/2)*), width: .Width * , depth: .Height * }
	.surfaceTexture(, , .Opacity)
}