package d2ir

import (
	
	

	
)

// The parser AST is mutable: substitution resolution coalesces strings in
// place. Import caches therefore retain an immutable parsed tree and compile a
// deep clone for each importer context.
func cloneASTMap( *d2ast.Map) *d2ast.Map {
	,  := cloneASTMapContext(context.Background(), )
	return 
}

type astCloner struct {
	ctx context.Context
	err error
}

func cloneASTMapContext( context.Context,  *d2ast.Map) (*d2ast.Map, error) {
	if  == nil {
		 = context.Background()
	}
	 := &astCloner{ctx: }
	 := .cloneMap()
	if .err != nil {
		return nil, .err
	}
	return , nil
}

func ( *astCloner) () bool {
	if .err != nil {
		return false
	}
	if  := .ctx.Err();  != nil {
		.err = 
		return false
	}
	return true
}

func ( *astCloner) ( *d2ast.Map) *d2ast.Map {
	if  == nil {
		return nil
	}
	if !.check() {
		return nil
	}
	 := &d2ast.Map{Range: .Range, Nodes: make([]d2ast.MapNodeBox, 0, len(.Nodes))}
	for ,  := range .Nodes {
		if !.check() {
			return nil
		}
		switch n := .Unbox().(type) {
		case *d2ast.Comment:
			 := *
			.Nodes = append(.Nodes, d2ast.MakeMapNodeBox(&))
		case *d2ast.BlockComment:
			 := *
			.Nodes = append(.Nodes, d2ast.MakeMapNodeBox(&))
		case *d2ast.Substitution:
			 := .cloneSubstitution()
			if .err != nil {
				return nil
			}
			.Nodes = append(.Nodes, d2ast.MakeMapNodeBox())
		case *d2ast.Import:
			 := .cloneImport()
			if .err != nil {
				return nil
			}
			.Nodes = append(.Nodes, d2ast.MakeMapNodeBox())
		case *d2ast.Key:
			 := .cloneKey()
			if .err != nil {
				return nil
			}
			.Nodes = append(.Nodes, d2ast.MakeMapNodeBox())
		}
		if .err != nil {
			return nil
		}
	}
	return 
}

func ( *astCloner) ( *d2ast.Array) *d2ast.Array {
	if  == nil {
		return nil
	}
	if !.check() {
		return nil
	}
	 := &d2ast.Array{Range: .Range, Nodes: make([]d2ast.ArrayNodeBox, 0, len(.Nodes))}
	for ,  := range .Nodes {
		if !.check() {
			return nil
		}
		switch n := .Unbox().(type) {
		case *d2ast.Comment:
			 := *
			.Nodes = append(.Nodes, d2ast.MakeArrayNodeBox(&))
		case *d2ast.BlockComment:
			 := *
			.Nodes = append(.Nodes, d2ast.MakeArrayNodeBox(&))
		case *d2ast.Substitution:
			 := .cloneSubstitution()
			if .err != nil {
				return nil
			}
			.Nodes = append(.Nodes, d2ast.MakeArrayNodeBox())
		case *d2ast.Import:
			 := .cloneImport()
			if .err != nil {
				return nil
			}
			.Nodes = append(.Nodes, d2ast.MakeArrayNodeBox())
		case *d2ast.Array:
			 := .()
			if .err != nil {
				return nil
			}
			.Nodes = append(.Nodes, d2ast.MakeArrayNodeBox())
		case *d2ast.Map:
			 := .cloneMap()
			if .err != nil {
				return nil
			}
			.Nodes = append(.Nodes, d2ast.MakeArrayNodeBox())
		case d2ast.Scalar:
			 := .cloneScalar()
			if .err != nil {
				return nil
			}
			.Nodes = append(.Nodes, d2ast.MakeArrayNodeBox(.(d2ast.ArrayNode)))
		}
		if .err != nil {
			return nil
		}
	}
	return 
}

func ( *astCloner) ( *d2ast.Key) *d2ast.Key {
	if  == nil {
		return nil
	}
	if !.check() {
		return nil
	}
	 := &d2ast.Key{
		Range:        .Range,
		Ampersand:    .Ampersand,
		NotAmpersand: .NotAmpersand,
		Key:          .cloneKeyPath(.Key),
		EdgeKey:      .cloneKeyPath(.EdgeKey),
		Primary:      .cloneScalarBox(.Primary),
		Value:        .cloneValueBox(.Value),
	}
	if .err != nil {
		return nil
	}
	if .EdgeIndex != nil {
		 := *.EdgeIndex
		if .EdgeIndex.Int != nil {
			 := *.EdgeIndex.Int
			.Int = &
		}
		.EdgeIndex = &
	}
	.Edges = make([]*d2ast.Edge, len(.Edges))
	for ,  := range .Edges {
		if !.check() {
			return nil
		}
		.Edges[] = &d2ast.Edge{
			Range:    .Range,
			Src:      .cloneKeyPath(.Src),
			SrcArrow: .SrcArrow,
			Dst:      .cloneKeyPath(.Dst),
			DstArrow: .DstArrow,
		}
		if .err != nil {
			return nil
		}
	}
	return 
}

func ( *astCloner) ( *d2ast.KeyPath) *d2ast.KeyPath {
	if  == nil {
		return nil
	}
	if !.check() {
		return nil
	}
	 := &d2ast.KeyPath{Range: .Range, Path: make([]*d2ast.StringBox, len(.Path))}
	for ,  := range .Path {
		if !.check() {
			return nil
		}
		.Path[] = .cloneStringBox()
	}
	return 
}

func ( *astCloner) ( *d2ast.StringBox) *d2ast.StringBox {
	if  == nil || .Unbox() == nil {
		return nil
	}
	if !.check() {
		return nil
	}
	 := .cloneScalar(.Unbox())
	if .err != nil {
		return nil
	}
	return d2ast.MakeValueBox().StringBox()
}

func ( *astCloner) ( *d2ast.Substitution) *d2ast.Substitution {
	if  == nil {
		return nil
	}
	if !.check() {
		return nil
	}
	 := &d2ast.Substitution{Range: .Range, Spread: .Spread, Path: make([]*d2ast.StringBox, len(.Path))}
	for ,  := range .Path {
		if !.check() {
			return nil
		}
		.Path[] = .cloneStringBox()
	}
	return 
}

func ( *astCloner) ( *d2ast.Import) *d2ast.Import {
	if  == nil {
		return nil
	}
	if !.check() {
		return nil
	}
	 := &d2ast.Import{Range: .Range, Spread: .Spread, Pre: .Pre, Path: make([]*d2ast.StringBox, len(.Path))}
	for ,  := range .Path {
		if !.check() {
			return nil
		}
		.Path[] = .cloneStringBox()
	}
	return 
}

func ( *astCloner) ( d2ast.ScalarBox) d2ast.ScalarBox {
	if .Unbox() == nil {
		return d2ast.ScalarBox{}
	}
	if !.check() {
		return d2ast.ScalarBox{}
	}
	 := .cloneScalar(.Unbox())
	if .err != nil {
		return d2ast.ScalarBox{}
	}
	return d2ast.MakeValueBox().ScalarBox()
}

func ( *astCloner) ( d2ast.ValueBox) d2ast.ValueBox {
	if !.check() {
		return d2ast.ValueBox{}
	}
	switch value := .Unbox().(type) {
	case nil:
		return d2ast.ValueBox{}
	case *d2ast.Map:
		 := .cloneMap()
		if .err != nil {
			return d2ast.ValueBox{}
		}
		return d2ast.MakeValueBox()
	case *d2ast.Array:
		 := .cloneArray()
		if .err != nil {
			return d2ast.ValueBox{}
		}
		return d2ast.MakeValueBox()
	case *d2ast.Import:
		 := .cloneImport()
		if .err != nil {
			return d2ast.ValueBox{}
		}
		return d2ast.MakeValueBox()
	case d2ast.Scalar:
		 := .cloneScalar()
		if .err != nil {
			return d2ast.ValueBox{}
		}
		return d2ast.MakeValueBox()
	default:
		panic("unhandled AST value")
	}
}

func cloneASTScalar( d2ast.Scalar) d2ast.Scalar {
	return (&astCloner{ctx: context.Background()}).cloneScalar()
}

func ( *astCloner) ( d2ast.Scalar) d2ast.Scalar {
	if  == nil {
		return nil
	}
	if !.check() {
		return nil
	}
	switch value := .(type) {
	case *d2ast.Null:
		 := *
		return &
	case *d2ast.Suspension:
		 := *
		return &
	case *d2ast.Boolean:
		 := *
		return &
	case *d2ast.Number:
		 := *
		if .Value != nil {
			.Value = new(big.Rat).Set(.Value)
		}
		if !.check() {
			return nil
		}
		return &
	case *d2ast.UnquotedString:
		 := *
		.Pattern = append([]string(nil), .Pattern...)
		.Value = .cloneInterpolation(.Value)
		return &
	case *d2ast.DoubleQuotedString:
		 := *
		.Value = .cloneInterpolation(.Value)
		return &
	case *d2ast.SingleQuotedString:
		 := *
		return &
	case *d2ast.BlockString:
		 := *
		return &
	default:
		panic("unhandled AST scalar")
	}
}

func ( *astCloner) ( []d2ast.InterpolationBox) []d2ast.InterpolationBox {
	if !.check() {
		return nil
	}
	 := make([]d2ast.InterpolationBox, len())
	for ,  := range  {
		if !.check() {
			return nil
		}
		if .String != nil {
			 := *.String
			[].String = &
		}
		if .StringRaw != nil {
			 := *.StringRaw
			[].StringRaw = &
		}
		[].Substitution = .cloneSubstitution(.Substitution)
		if .err != nil {
			return nil
		}
	}
	return 
}

// A selective non-spread import only copies the chosen field into its
// destination. Once the complete library has been compiled and validated, its
// unrelated siblings need not be copied again for each use. Keep full copies
// for boards, globs, and maps in arrays, whose retained contexts can refer
// outside that field. Imports into arrays also retain the source ancestry.
type importTemplate struct {
	ir               *Map
	selective        bool
	selectionChecked bool
}

func ( *importTemplate) () bool {
	if !.selectionChecked {
		.selective = canSelectImport(.ir)
		.selectionChecked = true
	}
	return .selective
}

func canSelectImport( Node) bool {
	return canSelectImportNode(, false)
}

func canSelectImportNode( Node,  bool) bool {
	switch n := .(type) {
	case *Map:
		// nilScopeMap does not descend into arrays. Those references retain
		// the complete imported ancestry, so use the complete clone for them.
		if  || len(.globs) != 0 {
			return false
		}
		for ,  := range .Fields {
			if !canSelectImport() {
				return false
			}
		}
		for ,  := range .Edges {
			if !canSelectImport() {
				return false
			}
		}
	case *Field:
		if NodeBoardKind() != "" {
			return false
		}
		return .Composite == nil || canSelectImport(.Composite)
	case *Edge:
		return .Map_ == nil || canSelectImport(.Map_)
	case *Array:
		for ,  := range .Values {
			if !(, true) {
				return false
			}
		}
	}
	return true
}

func cloneImportField( *Field) *Field {
	 := .Copy(nil).(*Field)
	cloneImportContexts(, )
	return 
}

// cloneImportMap deep-copies mutable IR and remaps reference/glob contexts to
// the copy. The ordinary Map.Copy intentionally shares source contexts; import
// templates need stronger isolation because nilScopeMap and substitutions
// mutate them after each import.
func cloneImportMap( *Map) *Map {
	 := .Copy(nil).(*Map)
	cloneImportContexts(, )
	return 
}

func cloneImportContexts(,  Node) {
	 := make(map[*Map]*Map)
	collectMapCopies(, , )
	 := make(map[*RefContext]*RefContext)
	 := func( *RefContext) *RefContext {
		if  == nil {
			return nil
		}
		if  := [];  != nil {
			return 
		}
		 := *
		if  := [.ScopeMap];  != nil {
			.ScopeMap = 
		}
		[] = &
		return &
	}

	cloneNodeReferences(, , )
	cloneGlobContexts(, , , )
}

func collectMapCopies(,  Node,  map[*Map]*Map) {
	switch src := .(type) {
	case *Map:
		 := .(*Map)
		[] = 
		for  := range .Fields {
			(.Fields[], .Fields[], )
		}
		for  := range .Edges {
			(.Edges[], .Edges[], )
		}
	case *Field:
		 := .(*Field)
		if .Composite != nil {
			(.Composite, .Composite, )
		}
	case *Edge:
		 := .(*Edge)
		if .Map_ != nil {
			(.Map_, .Map_, )
		}
	case *Array:
		 := .(*Array)
		for  := range .Values {
			(.Values[], .Values[], )
		}
	}
}

func cloneNodeReferences(,  Node,  func(*RefContext) *RefContext) {
	switch src := .(type) {
	case *Map:
		 := .(*Map)
		for  := range .Fields {
			(.Fields[], .Fields[], )
		}
		for  := range .Edges {
			(.Edges[], .Edges[], )
		}
	case *Field:
		 := .(*Field)
		.References = make([]*FieldReference, len(.References))
		for ,  := range .References {
			 := *
			.Context_ = (.Context_)
			.References[] = &
		}
		if .Composite != nil {
			(.Composite, .Composite, )
		}
	case *Edge:
		 := .(*Edge)
		.References = make([]*EdgeReference, len(.References))
		for ,  := range .References {
			 := *
			.Context_ = (.Context_)
			.References[] = &
		}
		if .Map_ != nil {
			(.Map_, .Map_, )
		}
	case *Array:
		 := .(*Array)
		for  := range .Values {
			(.Values[], .Values[], )
		}
	}
}

func cloneGlobContexts(,  Node,  map[*Map]*Map,  func(*RefContext) *RefContext) {
	 := make(map[*globContext]*globContext)
	var  func(*globContext) *globContext
	 = func( *globContext) *globContext {
		if  == nil {
			return nil
		}
		if  := [];  != nil {
			return 
		}
		 := *
		[] = &
		.refctx = (.refctx)
		.appliedFields = cloneStringSet(.appliedFields)
		.appliedEdges = cloneStringSet(.appliedEdges)
		.root = (.root)
		return &
	}

	for ,  := range  {
		.globs = make([]*globContext, len(.globs))
		for ,  := range .globs {
			.globs[] = ()
		}
	}
}

func cloneStringSet( map[string]struct{}) map[string]struct{} {
	if  == nil {
		return nil
	}
	 := make(map[string]struct{}, len())
	for  := range  {
		[] = struct{}{}
	}
	return 
}