package layoutgraph

import (
	
	

	
	
	
)

// Clone returns the layout graph projection used for an independent layout
// attempt. It deliberately copies the stable graph state, not transient
// optimizer state: derived caches, herd assignments, long-distance placement
// requirements, route diagnostics, and fixed-label bookkeeping are reset.
//
// The returned graph is published only after the complete bounded copy has
// succeeded. Every graph-owned node, cluster, and sequence is rebound to the
// returned graph; inactive cluster and sequence vessels remain detached.
func ( context.Context,  *Graph) (*Graph, error) {
	 := &Graph{}
	if  := cloneInto(, , );  != nil {
		return nil, 
	}
	return , nil
}

func cloneInto( context.Context, ,  *Graph) error {
	if  == nil {
		return fmt.Errorf("TALA CloneGraph requires a context")
	}
	if  == nil {
		return fmt.Errorf("cannot clone a nil graph")
	}
	if  := validateEngineGraph(, "CloneGraph", );  != nil {
		return 
	}
	,  := limits.NewWorkGuard(, "CloneGraph", limits.MaxEngineWorkUnits)
	if  != nil {
		return 
	}

	 := graphCloneState{
		source:            ,
		clone:             ,
		guard:             ,
		nodesByID:         make(map[EntityID]*Node),
		nodeRecordsByID:   make(map[EntityID]*Node),
		topLevelNodeIDs:   make(map[EntityID]struct{}),
		nodesBySource:     make(map[*Node]*Node),
		edgesBySource:     make(map[*Edge]*Edge),
		edgesByID:         make(map[EntityID]*Edge),
		clustersBySource:  make(map[*Cluster]*Cluster),
		sequencesBySource: make(map[*Sequence]*Sequence),
	}
	if  := .copy();  != nil {
		return 
	}
	if  := .Finish();  != nil {
		return 
	}
	return nil
}

type graphCloneState struct {
	source *Graph
	clone  *Graph
	guard  *limits.WorkGuard

	nodesByID       map[EntityID]*Node
	nodeRecordsByID map[EntityID]*Node
	// Cluster and sequence members join Graph.Nodes in the codec's top-level
	// node records; grouping vessels do not. Trees may reuse only the former.
	topLevelNodeIDs map[EntityID]struct{}
	nodesBySource   map[*Node]*Node
	nodeRecords     []*Node
	treeNodeRecords []*Node

	edgesBySource map[*Edge]*Edge
	edgesByID     map[EntityID]*Edge

	clustersBySource  map[*Cluster]*Cluster
	sequencesBySource map[*Sequence]*Sequence
}

func ( *graphCloneState) () error {
	 := make(map[*Node]struct{})
	for ,  := range .source.Nodes {
		if ,  := .addNodeRecord();  != nil {
			return 
		}
		[] = struct{}{}
	}
	for ,  := range .source.ClusterOrder() {
		[] = struct{}{}
		for ,  := range .source.Clusters[].Nodes {
			if ,  := [];  {
				continue
			}
			if ,  := .addNodeRecord();  != nil {
				return 
			}
			[] = struct{}{}
		}
	}
	for ,  := range .source.SequenceOrder() {
		[] = struct{}{}
		for ,  := range .source.Sequences[].Nodes {
			if ,  := [];  {
				continue
			}
			if ,  := .addNodeRecord();  != nil {
				return 
			}
			[] = struct{}{}
		}
	}

	.clone.Edges = make([]*Edge, 0, len(.source.Edges))
	for ,  := range .source.Edges {
		if  := .guard.Step();  != nil {
			return 
		}
		if  == nil {
			return fmt.Errorf("cannot clone a nil edge")
		}
		if ,  := .edgesBySource[];  {
			return fmt.Errorf("cannot clone duplicate edge record %d", .ID)
		}
		if .ID != 0 {
			if ,  := .edgesByID[.ID];  {
				return fmt.Errorf("cannot clone duplicate edge ID %d", .ID)
			}
		}
		,  := .copyEdge()
		if  != nil {
			return 
		}
		.edgesBySource[] = 
		if .ID != 0 {
			.edgesByID[.ID] = 
		}
		.From.addEdge()
		if !.isLoop() {
			.To.addEdge()
		}
		.clone.Edges = append(.clone.Edges, )
	}

	if  := .copyContainers();  != nil {
		return 
	}
	if  := .copyClusters();  != nil {
		return 
	}
	if  := .copySequences();  != nil {
		return 
	}
	if  := .copyHubs();  != nil {
		return 
	}
	if  := .copyAbductions();  != nil {
		return 
	}
	if  := .copyTrees();  != nil {
		return 
	}
	if  := .copyNears();  != nil {
		return 
	}
	if  := .copyHierarchies();  != nil {
		return 
	}
	if  := .copyDirections();  != nil {
		return 
	}

	 := make([]*Node, 0, len(.nodeRecords))
	for ,  := range .nodeRecords {
		if  := .guard.Step();  != nil {
			return 
		}
		 := .nodesBySource[]
		if .Cluster != nil && .Cluster.isActive() {
			continue
		}
		if .Sequence != nil && .Sequence.isActive() {
			continue
		}
		 = append(, )
	}
	.clone.Nodes = 
	.clone.CellSize = .source.CellSize
	.clone.IsRootHierarchy = .source.IsRootHierarchy
	.clone.CommonUncleSiblings = nil
	.clone.edgeLengthCache = make(map[uint64]float64)

	.source.costMu.RLock()
	.clone.crossingCost = .source.crossingCost
	.clone.turnCost = .source.turnCost
	.clone.nonCenterPortCost = .source.nonCenterPortCost
	.source.costMu.RUnlock()
	return nil
}

func ( *graphCloneState) ( *Node) (*Node, error) {
	if  := .guard.Step();  != nil {
		return nil, 
	}
	if  == nil {
		return nil, fmt.Errorf("cannot clone a nil node")
	}
	if .ID == 0 {
		return nil, fmt.Errorf("cannot clone reserved node ID 0")
	}
	if ,  := .nodesByID[.ID];  {
		return nil, fmt.Errorf("cannot clone duplicate node ID %d", .ID)
	}
	 := copyNodeRecord(, .clone)
	.nodesByID[.ID] = 
	.nodeRecordsByID[.ID] = 
	.topLevelNodeIDs[.ID] = struct{}{}
	.nodesBySource[] = 
	.nodeRecords = append(.nodeRecords, )
	return , nil
}

// copyAuxiliaryNodeRecord copies a node record embedded in another graph
// record, such as a grouping vessel or tree node. References elsewhere in the
// graph are resolved by ID, but two distinct full records with the same ID
// cannot be merged without silently discarding one record's state.
func ( *graphCloneState) ( *Node,  string) (*Node, bool, error) {
	if  == nil {
		return nil, false, fmt.Errorf("cannot clone %s: nil node", )
	}
	if .ID == 0 {
		return nil, false, fmt.Errorf("cannot clone %s: reserved node ID 0", )
	}
	if ,  := .nodeRecordsByID[.ID];  {
		if  !=  {
			return nil, false, fmt.Errorf("cannot clone %s: distinct node record reuses ID %d", , .ID)
		}
		return .nodesByID[.ID], false, nil
	}

	 := copyNodeRecord(, .clone)
	.nodesByID[.ID] = 
	.nodeRecordsByID[.ID] = 
	.nodesBySource[] = 
	return , true, nil
}

func ( *graphCloneState) ( *Node,  string) (*Node, error) {
	if  == nil {
		return nil, nil
	}
	if  := .guard.Step();  != nil {
		return nil, 
	}
	,  := .nodesByID[.ID]
	if ! {
		return nil, fmt.Errorf("cannot clone %s: node %d is not included in the graph", , .ID)
	}
	.nodesBySource[] = 
	return , nil
}

func ( *graphCloneState) ( *Edge) (*Edge, error) {
	,  := .resolveNode(.From, "edge source")
	if  != nil {
		return nil, 
	}
	,  := .resolveNode(.To, "edge target")
	if  != nil {
		return nil, 
	}
	if  == nil ||  == nil {
		return nil, fmt.Errorf("cannot clone edge %d with a nil endpoint", .ID)
	}

	 := NewEdge(, )
	.ID = .ID
	.D2ID = cloneValue(.D2ID)
	.SourceArrowhead = .SourceArrowhead
	.TargetArrowhead = .TargetArrowhead
	.SourceArrowheadLabel = copyLabelRecord(.SourceArrowheadLabel)
	.TargetArrowheadLabel = copyLabelRecord(.TargetArrowheadLabel)
	.MinWidth = .MinWidth
	.MinHeight = .MinHeight
	.Label = copyLabelRecord(.Label)
	.LabelPercentage = .LabelPercentage
	.FromTableColumnIndex = cloneValue(.FromTableColumnIndex)
	.ToTableColumnIndex = cloneValue(.ToTableColumnIndex)
	.IsInvisible = .IsInvisible
	.Style = copyEdgeStyle(.Style)
	for ,  := range .Points {
		if  := .guard.Step();  != nil {
			return nil, 
		}
		.Points = append(.Points, .Copy())
	}
	return , nil
}

func ( *graphCloneState) () error {
	.clone.Containers = make(map[*Node][]*Node, len(.source.Containers))
	if len(.source.Containers) == 0 {
		return nil
	}
	,  := .source.containerRDFSOrderContext(nil, .guard)
	if  != nil {
		return 
	}
	if len(.source.Containers) != len()+1 {
		return fmt.Errorf("cannot clone containers: map length %d does not match hierarchy length %d", len(.source.Containers), len()+1)
	}
	 = append(, nil)
	for ,  := range  {
		,  := .resolveNode(, "container")
		if  != nil {
			return 
		}
		 := .source.Containers[]
		 := make([]*Node, 0, len())
		for ,  := range  {
			if  == nil || .nodeRecordsByID[.ID] !=  {
				return fmt.Errorf("cannot clone container child: exact node record is not available")
			}
			,  := .resolveNode(, "container child")
			if  != nil {
				return 
			}
			if  == nil {
				return fmt.Errorf("cannot clone a nil container child")
			}
			.Container = 
			 = append(, )
		}
		.clone.Containers[] = 
		if  != nil {
			.isContainer = true
		}
	}
	return nil
}

func ( *graphCloneState) () error {
	.clone.Clusters = make(map[*Node]*Cluster, len(.source.Clusters))
	for ,  := range .source.ClusterOrder() {
		if  := .guard.Step();  != nil {
			return 
		}
		 := .source.Clusters[]
		if  == nil {
			return fmt.Errorf("cannot clone nil cluster for vessel %d", .ID)
		}
		if .Vessel !=  {
			return fmt.Errorf("cannot clone cluster under vessel %d because its record vessel differs", .ID)
		}
		if .Container != nil && .Container.ID == .ID {
			return fmt.Errorf("cannot clone cluster %d because it cannot contain itself", .ID)
		}
		, ,  := .copyAuxiliaryNodeRecord(, "cluster vessel")
		if  != nil {
			return 
		}
		if  {
			.Graph = nil
		}
		.isClusterVessel = true

		,  := .resolveNode(.Container, "cluster container")
		if  != nil {
			return 
		}
		 := make([]*Node, 0, len(.Nodes))
		for ,  := range .Nodes {
			,  := .resolveNode(, "cluster member")
			if  != nil {
				return 
			}
			 = append(, )
		}
		 := &Cluster{
			Vessel:             ,
			Nodes:              ,
			Arrangement:        .Arrangement,
			DesiredArrangement: .DesiredArrangement,
			Graph:              .clone,
			Padding:            .Padding,
			FixedSize:          .FixedSize,
			Container:          ,
		}
		.clone.Clusters[] = 
		.clustersBySource[] = 
		for ,  := range  {
			if  := .guard.Step();  != nil {
				return 
			}
			.Cluster = 
		}
	}
	return nil
}

func ( *graphCloneState) () error {
	.clone.Sequences = make(map[*Node]*Sequence, len(.source.Sequences))
	for ,  := range .source.SequenceOrder() {
		if  := .guard.Step();  != nil {
			return 
		}
		 := .source.Sequences[]
		if  == nil {
			return fmt.Errorf("cannot clone nil sequence for vessel %d", .ID)
		}
		if .Vessel !=  {
			return fmt.Errorf("cannot clone sequence under vessel %d because its record vessel differs", .ID)
		}
		if .Container != nil && .Container.ID == .ID {
			return fmt.Errorf("cannot clone sequence %d because it cannot contain itself", .ID)
		}
		if len(.Nodes) < 2 {
			return fmt.Errorf("cannot clone sequence %d with %d steps; want at least 2", .ID, len(.Nodes))
		}
		, ,  := .copyAuxiliaryNodeRecord(, "sequence vessel")
		if  != nil {
			return 
		}
		if  {
			.Graph = nil
		}

		,  := .resolveNode(.Container, "sequence container")
		if  != nil {
			return 
		}
		 := make([]*Node, 0, len(.Nodes))
		for ,  := range .Nodes {
			,  := .resolveNode(, "sequence member")
			if  != nil {
				return 
			}
			 = append(, )
		}
		 := &Sequence{
			Vessel:    ,
			Nodes:     ,
			Graph:     .clone,
			Container: ,
		}
		.clone.Sequences[] = 
		.sequencesBySource[] = 
		for ,  := range  {
			if  := .guard.Step();  != nil {
				return 
			}
			.Sequence = 
		}
	}
	return nil
}

func ( *graphCloneState) () error {
	.clone.Hubs = make(map[*Node][]*Node, len(.source.Hubs))
	for ,  := range .source.HubOrder() {
		,  := .resolveNode(, "hub")
		if  != nil {
			return 
		}
		 := make([]*Node, 0, len(.source.Hubs[]))
		for ,  := range .source.Hubs[] {
			if  == nil || .nodeRecordsByID[.ID] !=  {
				return fmt.Errorf("cannot clone hub spoke: exact node record is not included in the graph")
			}
			,  := .resolveNode(, "hub spoke")
			if  != nil {
				return 
			}
			 = append(, )
		}
		.clone.Hubs[] = 
	}
	return nil
}

func ( *graphCloneState) () error {
	 := func( []*EdgeAbduction) ([]*EdgeAbduction, error) {
		 := make([]*EdgeAbduction, 0, len())
		for ,  := range  {
			if  := .guard.Step();  != nil {
				return nil, 
			}
			 := .edgesBySource[.Edge]
			if  == nil && .Edge.ID != 0 {
				 = .edgesByID[.Edge.ID]
			}
			if  == nil {
				return nil, fmt.Errorf("cannot clone edge abduction for edge %d before the edge is copied", .Edge.ID)
			}
			,  := .resolveNode(.OriginallyFrom, "abduction original source")
			if  != nil {
				return nil, 
			}
			,  := .resolveNode(.OriginallyTo, "abduction original target")
			if  != nil {
				return nil, 
			}
			,  := .resolveNode(.CurrentFrom, "abduction current source")
			if  != nil {
				return nil, 
			}
			,  := .resolveNode(.CurrentTo, "abduction current target")
			if  != nil {
				return nil, 
			}
			 = append(, &EdgeAbduction{
				Edge:           ,
				OriginallyFrom: ,
				OriginallyTo:   ,
				CurrentFrom:    ,
				CurrentTo:      ,
			})
		}
		return , nil
	}

	for ,  := range .source.ClusterOrder() {
		 := .source.Clusters[]
		,  := (.EdgeAbductions)
		if  != nil {
			return 
		}
		.clustersBySource[].EdgeAbductions = 
	}
	for ,  := range .source.SequenceOrder() {
		 := .source.Sequences[]
		,  := (.EdgeAbductions)
		if  != nil {
			return 
		}
		.sequencesBySource[].EdgeAbductions = 
	}
	return nil
}

func ( *graphCloneState) () error {
	.clone.Trees = make(map[*Node][]*Tree, len(.source.Trees))
	.clone.NodeToTree = make(map[*Node]*Tree)
	 := make(map[EntityID]struct{})

	var  func( *Tree,  *Tree) (*Tree, error)
	 = func( *Tree,  *Tree) (*Tree, error) {
		if  := .guard.Step();  != nil {
			return nil, 
		}
		if .SentinelEdge == nil {
			return nil, fmt.Errorf("cannot clone a tree with a nil sentinel edge")
		}
		if .Node == nil {
			return nil, fmt.Errorf("cannot clone a tree with a nil node")
		}
		if ,  := [.Node.ID];  {
			return nil, fmt.Errorf("cannot clone tree node %d with more than one tree owner", .Node.ID)
		}
		[.Node.ID] = struct{}{}
		if  := .nodeRecordsByID[.Node.ID];  == .Node {
			if ,  := .topLevelNodeIDs[.Node.ID]; ! {
				return nil, fmt.Errorf("cannot clone tree node %d because it repeats a non-top-level node record", .Node.ID)
			}
		}

		, ,  := .copyAuxiliaryNodeRecord(.Node, "tree node")
		if  != nil {
			return nil, 
		}
		if  {
			.treeNodeRecords = append(.treeNodeRecords, .Node)
		}

		 := .edgesBySource[.SentinelEdge]
		if  == nil && .SentinelEdge.ID != 0 && .edgesByID[.SentinelEdge.ID] != nil {
			return nil, fmt.Errorf("cannot clone tree sentinel edge: distinct edge record reuses ID %d", .SentinelEdge.ID)
		}
		if  == nil {
			,  = .copyEdge(.SentinelEdge)
			if  != nil {
				return nil, 
			}
			.edgesBySource[.SentinelEdge] = 
			if .SentinelEdge.ID != 0 {
				.edgesByID[.SentinelEdge.ID] = 
			}
		}
		 := &Tree{
			Node:         ,
			Parent:       ,
			SentinelEdge: ,
			Orientation:  .Orientation,
		}
		.clone.NodeToTree[] = 
		for ,  := range .Children {
			,  := (, )
			if  != nil {
				return nil, 
			}
			.Children = append(.Children, )
		}
		return , nil
	}

	for ,  := range .source.TreeOrder() {
		,  := .resolveNode(, "tree root sentinel")
		if  != nil {
			return 
		}
		var  []*Tree
		for ,  := range .source.Trees[] {
			,  := (, nil)
			if  != nil {
				return 
			}
			 = append(, )
		}
		if len() > 0 {
			.clone.Trees[] = 
		}
	}
	return nil
}

func ( *graphCloneState) () error {
	for ,  := range append(.nodeRecords, .treeNodeRecords...) {
		 := .nodesBySource[]
		for ,  := range .orderedNears() {
			if  := .guard.Step();  != nil {
				return 
			}
			,  := .resolveNode(, "near relation")
			if  != nil {
				return 
			}
			.AddNear()
		}
	}
	return nil
}

func ( *graphCloneState) () error {
	 := make(map[*Hierarchy]struct{})
	for ,  := range .source.Nodes {
		if  := .guard.Step();  != nil {
			return 
		}
		 := .Hierarchy
		if  == nil {
			continue
		}
		if ,  := [];  {
			continue
		}
		[] = struct{}{}
		 := make(map[*Node]int, len(.level))
		 := &Hierarchy{level: }
		for ,  := range .level {
			,  := .resolveNode(, "hierarchy member")
			if  != nil {
				return 
			}
			[] = 
			.Hierarchy = 
		}
	}
	return nil
}

func ( *graphCloneState) () error {
	.clone.Directions = make(map[*Node]geo.Orientation, len(.source.Directions))
	for ,  := range .source.Directions {
		,  := .resolveNode(, "direction container")
		if  != nil {
			return 
		}
		.clone.Directions[] = canonicalDirection()
	}
	return nil
}

func copyNodeRecord( *Node,  *Graph) *Node {
	 := NewNode(.ID, .Width, .Height)
	.D2ID = cloneValue(.D2ID)
	.TopLeft = cloneValue(.TopLeft)
	.FixedTopLeft = cloneValue(.FixedTopLeft)
	.Graph = 
	.FontSize = cloneValue(.FontSize)
	.DesiredWidth = cloneValue(.DesiredWidth)
	.DesiredHeight = cloneValue(.DesiredHeight)
	.SetShape(.ShapeType())
	.SetNumColumns(.NumColumns())
	.ForceHierarchy = .ForceHierarchy
	.Label = copyLabelRecord(.Label)
	.Icon = copyIconRecord(.Icon)
	.Is3D = .Is3D
	.IsMultiple = .IsMultiple
	.IsInvisible = .IsInvisible
	return 
}

func copyLabelRecord( *Label) *Label {
	if  == nil {
		return nil
	}
	return &Label{
		Text:     .Text,
		Position: label.FromString(.Position.String()),
		Width:    .Width,
		Height:   .Height,
	}
}

func copyIconRecord( *Icon) *Icon {
	if  == nil {
		return nil
	}
	return &Icon{Position: label.FromString(.Position.String())}
}

func copyEdgeStyle( EdgeStyle) EdgeStyle {
	return EdgeStyle{
		Opacity:       cloneValue(.Opacity),
		Stroke:        cloneValue(.Stroke),
		Fill:          cloneValue(.Fill),
		FillPattern:   cloneValue(.FillPattern),
		StrokeWidth:   cloneValue(.StrokeWidth),
		StrokeDash:    cloneValue(.StrokeDash),
		BorderRadius:  cloneValue(.BorderRadius),
		Shadow:        cloneValue(.Shadow),
		ThreeDee:      cloneValue(.ThreeDee),
		Multiple:      cloneValue(.Multiple),
		Font:          cloneValue(.Font),
		FontSize:      cloneValue(.FontSize),
		FontColor:     cloneValue(.FontColor),
		Animated:      cloneValue(.Animated),
		Bold:          cloneValue(.Bold),
		Italic:        cloneValue(.Italic),
		Underline:     cloneValue(.Underline),
		Filled:        cloneValue(.Filled),
		DoubleBorder:  cloneValue(.DoubleBorder),
		TextTransform: cloneValue(.TextTransform),
	}
}

func cloneValue[ any]( *) * {
	if  == nil {
		return nil
	}
	 := *
	return &
}

func canonicalDirection( geo.Orientation) geo.Orientation {
	switch  {
	case geo.Top, geo.Bottom, geo.Left, geo.Right:
		return 
	default:
		return geo.NONE
	}
}