package d2ir

func structureCounts( *Map) (,  int) {
	if  == nil {
		return 0, 0
	}
	return .FieldCountRecursive(), .EdgeCountRecursive()
}

func markStructureCountDelta( *Map, ,  int,  *Map) {
	,  := structureCounts()
	if  !=  ||  !=  {
		.markStructureChanged()
	}
}

func (,  *Map) {
	overlayMap(, , false)
}

func overlayMapIndexed(,  *Map) {
	overlayMap(, , true)
}

func overlayMap(,  *Map,  bool) {
	for ,  := range .Fields {
		var  *Field
		if  {
			 = .getFieldIndexed(.Name)
		} else {
			 = .GetField(.Name)
		}
		if  == nil {
			.appendField(.Copy().(*Field))
			continue
		}
		overlayField(, , )
	}

	for ,  := range .Edges {
		var  []*Edge
		if  {
			 = .getEdgesIndexed(.ID)
		} else {
			 = .GetEdges(.ID, nil, nil)
		}
		if len() == 0 {
			.appendEdge(.Copy().(*Edge))
			continue
		}
		 := [0]
		overlayEdge(, , )
	}
}

func (,  *Map,  *Field) {
	expandSubstitution(, , , false)
}

func expandSubstitutionIndexed(,  *Map,  *Field) {
	expandSubstitution(, , , true)
}

func expandSubstitution(,  *Map,  *Field,  bool) {
	 := -1
	for  := 0;  < len(.Fields); ++ {
		if .Fields[] ==  {
			 = 
			break
		}
	}

	for ,  := range .Fields {
		var  *Field
		if  {
			 = .getFieldIndexed(.Name)
		} else {
			 = .GetField(.Name)
		}
		if  == nil {
			.insertField(, .Copy().(*Field))
			++
			continue
		}
		overlayField(, , )
	}

	// NOTE this doesn't expand edges in place, and just appends
	// I suppose to do this, there needs to be an edge placeholder too on top of the field placeholder
	// Will wait to see if a problem
	for ,  := range .Edges {
		var  []*Edge
		if  {
			 = .getEdgesIndexed(.ID)
		} else {
			 = .GetEdges(.ID, nil, nil)
		}
		if len() == 0 {
			.appendEdge(.Copy().(*Edge))
			continue
		}
		 := [0]
		overlayEdge(, , )
	}
}

// OverlayField applies one field overlay directly to another field.
//
// Deprecated: construct overlays as maps and apply them with OverlayMap.
// OverlayField is an internal IR mutation detail and will be removed after one
// compatibility release.
func (,  *Field) {
	overlayField(, , false)
}

func overlayFieldIndexed(,  *Field) {
	overlayField(, , true)
}

func overlayField(,  *Field,  bool) {
	if .Primary_ != nil {
		.Primary_ = .Primary_.Copy().(*Scalar)
	}

	if .Composite != nil {
		if .Map() != nil && .Map() != nil {
			overlayMap(.Map(), .Map(), )
		} else {
			,  := structureCounts(.Map())
			.Composite = .Composite.Copy().(Composite)
			markStructureCountDelta(ParentMap(), , , .Map())
		}
	}

	.References = append(.References, .References...)
}

// OverlayEdge applies one edge overlay directly to another edge.
//
// Deprecated: construct overlays as maps and apply them with OverlayMap.
// OverlayEdge is an internal IR mutation detail and will be removed after one
// compatibility release.
func (,  *Edge) {
	overlayEdge(, , false)
}

func overlayEdge(,  *Edge,  bool) {
	if .Primary_ != nil {
		.Primary_ = .Primary_.Copy().(*Scalar)
	}
	if .Map_ != nil {
		if .Map_ != nil {
			overlayMap(.Map(), .Map_, )
		} else {
			,  := structureCounts(.Map())
			.Map_ = .Map_.Copy().(*Map)
			markStructureCountDelta(ParentMap(), , , .Map())
		}
	}
	.References = append(.References, .References...)
}