// Copyright (c) 2017, 2020 Kiel University and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0.
//
// SPDX-License-Identifier: EPL-2.0

package core

import (
	
	
	
	
	

	
	
	
)

// Codec imports ELK JSON into the algorithm graph and transfers computed
// layout back into the same public graph objects.
type Codec struct {
	Options     *OptionRegistry
	nodeIDs     map[graphjson.ID]graph.NodeID
	portIDs     map[graphjson.ID]graph.PortID
	nodeJSON    []*graphjson.Node
	portJSON    []*graphjson.Port
	edgeJSON    []*graphjson.Edge
	edgeParents []graph.NodeID
	labelJSON   []*graphjson.Label
	sectionJSON []*graphjson.EdgeSection
}

func ( *OptionRegistry) *Codec {
	if  == nil {
		 = NewOptionRegistry()
	}
	return &Codec{Options: }
}

func ( *Codec) () {
	.nodeIDs = make(map[graphjson.ID]graph.NodeID)
	.portIDs = make(map[graphjson.ID]graph.PortID)
	.nodeJSON = nil
	.portJSON = nil
	.edgeJSON = nil
	.edgeParents = nil
	.labelJSON = nil
	.sectionJSON = nil
}

// Import validates graph references and constructs the native arena.
func ( *Codec) ( *graphjson.Graph) (*graph.Model, error) {
	if  == nil {
		return nil, fmt.Errorf("ELK graph must not be nil")
	}
	if  := .rejectUnconstructableJSONProperties();  != nil {
		return nil, 
	}
	.reset()
	 := graph.NewModel()
	if  := .importNode(, .Root, );  != nil {
		return nil, 
	}
	if  := .importEdges(, .Root, );  != nil {
		return nil, 
	}
	return , nil
}

func ( *Codec) ( *graphjson.Node) error {
	if  == nil {
		return nil
	}
	for ,  := range .layoutOptionKeys(.LayoutOptions, .LayoutOptionKeys()) {
		 := .Options.BySuffix()
		if  == nil || .LayoutOptions[] == nil {
			continue
		}
		switch .ID {
		case TopdownSizeApproximator.ID:
			return fmt.Errorf("Couldn't create new instance of property '%s'. Make sure its type is registered with the ElkReflect utility class.",
				TopdownSizeApproximator.ID)
		case "org.eclipse.elk.layered.considerModelOrder.groupModelOrder.cmEnforcedGroupOrders":
			return fmt.Errorf("Severe implementation error in the Json to ElkGraph importer.")
		}
	}
	for ,  := range .Children {
		if  := .();  != nil {
			return 
		}
	}
	return nil
}

func ( *Codec) ( *graph.Model,  graph.NodeID,  *graphjson.Node) error {
	if  == nil {
		return nil
	}
	if !.ID.IsValid() {
		return fmt.Errorf("every node must have an id")
	}
	if ,  := .nodeIDs[.ID];  {
		return fmt.Errorf("duplicate node id: %s", .ID.String())
	}
	.nodeIDs[.ID] = 
	for len(.nodeJSON) <= int() {
		.nodeJSON = append(.nodeJSON, nil)
	}
	.nodeJSON[int()] = 
	 := .Node()
	.Identifier, .IdentifierPresent = .ID.String(), true
	importShape(&.Shape, .X, .Y, .Width, .Height)
	.importProperties(&.Properties, .LayoutOptions, .LayoutOptionKeys())
	.importIndividualSpacings(&.Properties, .IndividualSpacings, .IndividualSpacingKeys())
	for ,  := range .Ports {
		if  == nil {
			continue
		}
		 := .AddPort()
		if  := .importPort(, , );  != nil {
			return 
		}
	}
	for ,  := range .Labels {
		if  == nil {
			continue
		}
		.importLabel(, graph.NodeElementRef(), )
	}
	for ,  := range .Children {
		if  == nil {
			continue
		}
		 := .AddNode(&)
		if  := .(, , );  != nil {
			return 
		}
	}
	return nil
}

func ( *Codec) ( *graph.Model,  graph.PortID,  *graphjson.Port) error {
	if !.ID.IsValid() {
		return fmt.Errorf("every port must have an id")
	}
	if ,  := .portIDs[.ID];  {
		return fmt.Errorf("duplicate port id: %s", .ID.String())
	}
	.portIDs[.ID] = 
	for len(.portJSON) <= int() {
		.portJSON = append(.portJSON, nil)
	}
	.portJSON[int()] = 
	 := .Port()
	.Identifier, .IdentifierPresent = .ID.String(), true
	importShape(&.Shape, .X, .Y, .Width, .Height)
	.importProperties(&.Properties, .LayoutOptions, .LayoutOptionKeys())
	for ,  := range .Labels {
		if  != nil {
			.importLabel(, graph.PortElementRef(), )
		}
	}
	return nil
}

func ( *Codec) ( *graph.Model,  graph.ElementID,  *graphjson.Label) graph.LabelID {
	 := ""
	 := .Text != nil
	if .Text != nil {
		 = *.Text
	}
	 := .AddLabel(, )
	for len(.labelJSON) <= int() {
		.labelJSON = append(.labelJSON, nil)
	}
	.labelJSON[int()] = 
	 := .Label()
	.TextPresent = 
	if .ID != nil && .ID.IsValid() {
		.Identifier, .IdentifierPresent = .ID.String(), true
	}
	importShape(&.Shape, .X, .Y, .Width, .Height)
	.importProperties(&.Properties, .LayoutOptions, .LayoutOptionKeys())
	return 
}

func ( *Codec) ( *graph.Model,  graph.NodeID,  *graphjson.Node) error {
	for ,  := range .Edges {
		if  == nil {
			continue
		}
		if ,  := .importEdge(, , );  != nil {
			return 
		}
	}
	 := .Node().Children
	 := 0
	for ,  := range .Children {
		if  == nil {
			continue
		}
		if  >= len() {
			return fmt.Errorf("internal child order mismatch")
		}
		if  := .(, [], );  != nil {
			return 
		}
		++
	}
	return nil
}

func ( *Codec) ( *graph.Model,  graph.NodeID,  *graphjson.Edge) (graph.EdgeID, error) {
	if !.ID.IsValid() {
		return 0, fmt.Errorf("every edge must have an id")
	}
	 := .AddEdge(&)
	for len(.edgeJSON) <= int() {
		.edgeJSON = append(.edgeJSON, nil)
		.edgeParents = append(.edgeParents, 0)
	}
	.edgeJSON[int()] = 
	.edgeParents[int()] = 
	 := .Edge()
	.Identifier, .IdentifierPresent = .ID.String(), true
	.importProperties(&.Properties, .LayoutOptions, .LayoutOptionKeys())
	if .Sources != nil || .Targets != nil {
		for ,  := range .Sources {
			,  := .shapeByID()
			if  != nil {
				return 0, 
			}
			.AddSource(, )
		}
		for ,  := range .Targets {
			,  := .shapeByID()
			if  != nil {
				return 0, 
			}
			.AddTarget(, )
		}
		if len(.Sources) == 0 || len(.Targets) == 0 {
			return 0, fmt.Errorf("an edge must have at least one source and one target (edge id: %q)", .ID.String())
		}
		if  := .importSections(, , );  != nil {
			return 0, 
		}
	} else {
		if  := .importPrimitiveEdge(, , );  != nil {
			return 0, 
		}
	}
	for ,  := range .Labels {
		if  != nil {
			.importLabel(, graph.EdgeElementRef(), )
		}
	}
	.UpdateContainment()
	return , nil
}

func ( *Codec) ( *graph.Model,  graph.EdgeID,  *graphjson.Edge) error {
	if .Source == nil {
		return fmt.Errorf("an edge must have a source node (edge id: %q)", .ID.String())
	}
	,  := .nodeIDs[*.Source]
	if ! {
		return fmt.Errorf("an edge must have a source node (edge id: %q)", .ID.String())
	}
	 := graph.NodeRef()
	if .SourcePort != nil {
		,  := .portIDs[*.SourcePort]
		if ! || .Port().Parent !=  {
			return fmt.Errorf("source port must belong to the source node (edge id: %q)", .ID.String())
		}
		 = graph.PortRef()
	}
	if .Target == nil {
		return fmt.Errorf("an edge must have a target node (edge id: %q)", .ID.String())
	}
	,  := .nodeIDs[*.Target]
	if ! {
		return fmt.Errorf("an edge must have a target node (edge id: %q)", .ID.String())
	}
	 := graph.NodeRef()
	if .TargetPort != nil {
		,  := .portIDs[*.TargetPort]
		if ! || .Port().Parent !=  {
			return fmt.Errorf("target port must belong to the target node (edge id: %q)", .ID.String())
		}
		 = graph.PortRef()
	}
	.AddSource(, )
	.AddTarget(, )
	if .SourcePoint != nil || .TargetPoint != nil || .BendPoints != nil {
		 := .AddSection()
		 := .Section()
		if .SourcePoint != nil {
			.Start = fromJSONPoint(*.SourcePoint)
			.StartPresent = true
		}
		if .TargetPoint != nil {
			.End = fromJSONPoint(*.TargetPoint)
			.EndPresent = true
		}
		if .BendPoints != nil {
			.BendPointsPresent = true
			for ,  := range .BendPoints {
				.BendPoints = append(.BendPoints, fromJSONPoint())
			}
		}
	}
	return nil
}

func ( *Codec) ( *graph.Model,  graph.EdgeID,  *graphjson.Edge) error {
	 := make(map[graphjson.ID]graph.SectionID)
	type  struct {
		    graph.SectionID
		 graphjson.ID
	}
	var ,  []
	for ,  := range .Sections {
		if  == nil {
			continue
		}
		if !.ID.IsValid() {
			return fmt.Errorf("every edge section must have an id")
		}
		if ,  := [.ID];  {
			return fmt.Errorf("duplicate edge section id: %s", .ID.String())
		}
		if .StartPoint == nil {
			return fmt.Errorf("all edge sections need a start point")
		}
		if .EndPoint == nil {
			return fmt.Errorf("all edge sections need an end point")
		}
		 := .AddSection()
		[.ID] = 
		for len(.sectionJSON) <= int() {
			.sectionJSON = append(.sectionJSON, nil)
		}
		.sectionJSON[int()] = 
		 := .Section()
		.Identifier, .IdentifierPresent = .ID.String(), true
		.Start, .End = fromJSONPoint(*.StartPoint), fromJSONPoint(*.EndPoint)
		.StartPresent, .EndPresent = true, true
		.importProperties(&.Properties, .LayoutOptions, .LayoutOptionKeys())
		if .BendPoints != nil {
			.BendPointsPresent = true
		}
		for ,  := range .BendPoints {
			.BendPoints = append(.BendPoints, fromJSONPoint())
		}
		if .IncomingShape != nil {
			,  := .shapeByID(*.IncomingShape)
			if  != nil {
				return 
			}
			.IncomingShape = &
		}
		if .OutgoingShape != nil {
			,  := .shapeByID(*.OutgoingShape)
			if  != nil {
				return 
			}
			.OutgoingShape = &
		}
		for ,  := range .IncomingSections {
			 = append(, {, })
		}
		for ,  := range .OutgoingSections {
			 = append(, {, })
		}
	}
	 := func( [],  bool) error {
		for ,  := range  {
			,  := [.]
			if ! {
				return fmt.Errorf("referenced edge section does not exist: %s (edge id: %q)", ..String(), .ID.String())
			}
			if  {
				.Section(.).IncomingSections = append(.Section(.).IncomingSections, )
			} else {
				.Section(.).OutgoingSections = append(.Section(.).OutgoingSections, )
			}
		}
		return nil
	}
	if  := (, true);  != nil {
		return 
	}
	if  := (, false);  != nil {
		return 
	}
	 := .Edge()
	if len(.Sources) == 1 && len(.Targets) == 1 && len(.Sections) == 1 {
		 := .Section(.Sections[0])
		if .IncomingShape == nil && .OutgoingShape == nil {
			,  := .Sources[0], .Targets[0]
			.IncomingShape, .OutgoingShape = &, &
		}
	}
	return nil
}

func ( *Codec) ( graphjson.ID) (graph.ShapeID, error) {
	if ,  := .nodeIDs[];  {
		return graph.NodeRef(), nil
	}
	if ,  := .portIDs[];  {
		return graph.PortRef(), nil
	}
	return graph.ShapeID{}, fmt.Errorf("referenced shape does not exist: %s", .String())
}

func ( *Codec) (
	 *graph.PropertyMap,
	 graphjson.LayoutOptions,
	 []string,
) {
	for ,  := range .layoutOptionKeys(, ) {
		 := []
		 := .Options.BySuffix()
		if  == nil {
			continue
		}
		,  := .ParseValue(optionString())
		if  {
			.SetRaw(.ID, )
		}
	}
}

func ( *Codec) ( graphjson.LayoutOptions,  []string) []string {
	 := make([]string, 0, len())
	 := make(map[string]struct{}, len())
	for ,  := range  {
		if ,  := []; ! {
			continue
		}
		if ,  := [];  {
			continue
		}
		[] = struct{}{}
		 = append(, )
	}
	 := make([]string, 0, len()-len())
	for  := range  {
		if ,  := []; ! {
			 = append(, )
		}
	}
	if  == nil {
		sort.Slice(, func(,  int) bool {
			,  := [], []
			,  := .Options.BySuffix(), .Options.BySuffix()
			if  != nil &&  ==  {
				 := optionSpellingRank(, )
				 := optionSpellingRank(, )
				if  !=  {
					return  < 
				}
			}
			return  < 
		})
	} else {
		sort.Strings()
	}
	return append(, ...)
}

func optionSpellingRank( *OptionData,  string) int {
	if  == .ID {
		return 4
	}
	for ,  := range .LegacyIDs {
		if  ==  {
			return 1
		}
	}
	if dotSuffix(.ID, ) {
		return 3
	}
	for ,  := range .LegacyIDs {
		if dotSuffix(, ) {
			return 0
		}
	}
	return 0
}

func ( *Codec) (
	 *graph.PropertyMap,
	 graphjson.LayoutOptions,
	 []string,
) {
	if  == nil {
		return
	}
	 := &IndividualSpacings{}
	.importProperties(&.Properties, , )
	graph.Set(, SpacingIndividual, )
}

func optionString( any) string {
	switch typed := .(type) {
	case nil:
		return "null"
	case string:
		return 
	case bool:
		return strconv.FormatBool()
	case json.Number:
		return .String()
	case float64:
		return strconv.FormatFloat(, 'g', -1, 64)
	case float32:
		return strconv.FormatFloat(float64(), 'g', -1, 32)
	case int:
		return strconv.Itoa()
	case int64:
		return strconv.FormatInt(, 10)
	default:
		,  := json.Marshal()
		if  != nil {
			return fmt.Sprint()
		}
		return string()
	}
}

func importShape( *graph.Shape, , , ,  *float64) {
	if  != nil {
		.X, .Presence = finite(*), .Presence|graph.HasX
	}
	if  != nil {
		.Y, .Presence = finite(*), .Presence|graph.HasY
	}
	if  != nil {
		.Width, .Presence = finite(*), .Presence|graph.HasWidth
	}
	if  != nil {
		.Height, .Presence = finite(*), .Presence|graph.HasHeight
	}
}

func finite( float64) float64 {
	if math.IsNaN() || math.IsInf(, 0) {
		return 0
	}
	return 
}
func fromJSONPoint( graphjson.Point) geometry.Point {
	return geometry.Point{X: finite(.X), Y: finite(.Y)}
}
func toJSONPoint( geometry.Point) graphjson.Point {
	return graphjson.Point{X: .X, Y: .Y}
}

type coordinateContext struct {
	nodeGlobal     []geometry.Point
	portGlobal     []geometry.Point
	labelGlobal    []geometry.Point
	nodeShapeMode  []string
	portShapeMode  []string
	edgeShapeMode  []string
	labelShapeMode []string
	nodeEdgeMode   []string
	portEdgeMode   []string
	edgeEdgeMode   []string
	labelEdgeMode  []string
}

func resolveCoordinateMode(, ,  string) string {
	if  == "" ||  == "INHERIT" {
		if  != "" {
			return 
		}
		return 
	}
	return 
}

func ( *Codec) ( *graph.Model) (*coordinateContext, error) {
	if len(.edgeParents) != len(.Edges) {
		return nil, fmt.Errorf("edge parent bindings do not match imported model")
	}
	 := &coordinateContext{
		nodeGlobal:     make([]geometry.Point, len(.Nodes)),
		portGlobal:     make([]geometry.Point, len(.Ports)),
		labelGlobal:    make([]geometry.Point, len(.Labels)),
		nodeShapeMode:  make([]string, len(.Nodes)),
		portShapeMode:  make([]string, len(.Ports)),
		edgeShapeMode:  make([]string, len(.Edges)),
		labelShapeMode: make([]string, len(.Labels)),
		nodeEdgeMode:   make([]string, len(.Nodes)),
		portEdgeMode:   make([]string, len(.Ports)),
		edgeEdgeMode:   make([]string, len(.Edges)),
		labelEdgeMode:  make([]string, len(.Labels)),
	}

	// Arena creation order is parent-before-child. Record absolute coordinates
	// independently of the requested JSON output modes, matching JsonImporter.
	for  := range .Nodes {
		 := .Node(graph.NodeID())
		var  geometry.Point
		,  := "", ""
		if .Parent != nil {
			 := int(*.Parent)
			 = .nodeGlobal[]
			 = .nodeShapeMode[]
			 = .nodeEdgeMode[]
		}
		.nodeGlobal[] = .Shape.Position().Add()
		.nodeShapeMode[] = resolveCoordinateMode(
			graph.Get(&.Properties, JSONShapeCoords), , "PARENT")
		.nodeEdgeMode[] = resolveCoordinateMode(
			graph.Get(&.Properties, JSONEdgeCoords), , "CONTAINER")
	}

	for  := range .Ports {
		 := .Port(graph.PortID())
		 := int(.Parent)
		.portGlobal[] = .Shape.Position().Add(.nodeGlobal[])
		.portShapeMode[] = resolveCoordinateMode(
			graph.Get(&.Properties, JSONShapeCoords), .nodeShapeMode[], "PARENT")
		.portEdgeMode[] = resolveCoordinateMode(
			graph.Get(&.Properties, JSONEdgeCoords), .nodeEdgeMode[], "CONTAINER")
	}

	for  := range .Edges {
		 := .Edge(graph.EdgeID())
		 := int(.edgeParents[])
		.edgeShapeMode[] = resolveCoordinateMode(
			graph.Get(&.Properties, JSONShapeCoords), .nodeShapeMode[], "PARENT")
		.edgeEdgeMode[] = resolveCoordinateMode(
			graph.Get(&.Properties, JSONEdgeCoords), .nodeEdgeMode[], "CONTAINER")
	}

	for  := range .Labels {
		 := .Label(graph.LabelID())
		, , ,  := .labelParentCoordinates(, .Parent)
		if  != nil {
			return nil, 
		}
		.labelGlobal[] = .Shape.Position().Add()
		.labelShapeMode[] = resolveCoordinateMode(
			graph.Get(&.Properties, JSONShapeCoords), , "PARENT")
		.labelEdgeMode[] = resolveCoordinateMode(
			graph.Get(&.Properties, JSONEdgeCoords), , "CONTAINER")
	}
	return , nil
}

func ( *Codec) (
	 *coordinateContext,
	 graph.ElementID,
) (geometry.Point, string, string, error) {
	switch .Kind {
	case graph.NodeElement:
		 := int(.Node)
		return .nodeGlobal[], .nodeShapeMode[], .nodeEdgeMode[], nil
	case graph.PortElement:
		 := int(.Port)
		return .portGlobal[], .portShapeMode[], .portEdgeMode[], nil
	case graph.EdgeElement:
		 := int(.Edge)
		if  >= len(.edgeParents) {
			return geometry.Point{}, "", "", fmt.Errorf("edge parent binding %d is missing", )
		}
		 := int(.edgeParents[])
		return .nodeGlobal[], .edgeShapeMode[], .edgeEdgeMode[], nil
	case graph.LabelElement:
		 := int(.Label)
		return .labelGlobal[], .labelShapeMode[], .labelEdgeMode[], nil
	default:
		return geometry.Point{}, "", "", fmt.Errorf("unknown label parent kind: %d", .Kind)
	}
}

func ( *Codec) ( *graph.Model,  *coordinateContext,  graph.EdgeID) geometry.Point {
	 := int()
	 := int(.edgeParents[])
	 := .Edge().ContainingNode
	if  == nil {
		return geometry.Point{}
	}
	 := .nodeGlobal[int(*)]
	switch .nodeEdgeMode[] {
	case "ROOT":
		return 
	case "PARENT":
		return .Sub(.nodeGlobal[])
	default:
		return geometry.Point{}
	}
}

func ( *Codec) ( *graph.Model,  *coordinateContext,  *graph.Label) geometry.Point {
	switch .Parent.Kind {
	case graph.NodeElement:
		 := int(.Parent.Node)
		if .nodeShapeMode[] == "ROOT" {
			return .nodeGlobal[]
		}
	case graph.PortElement:
		 := int(.Parent.Port)
		if .portShapeMode[] == "ROOT" {
			return .portGlobal[]
		}
	case graph.EdgeElement:
		return .edgeOutputOffset(, , .Parent.Edge)
	case graph.LabelElement:
		 := int(.Parent.Label)
		if .labelShapeMode[] == "ROOT" {
			return .labelGlobal[]
		}
	}
	return geometry.Point{}
}

// TransferLayout copies all layout output into the public objects imported by
// the most recent Import call.
func ( *Codec) ( *graph.Model) error {
	if  == nil || len(.nodeJSON) != len(.Nodes) {
		return fmt.Errorf("model was not imported by this codec")
	}
	,  := .coordinates()
	if  != nil {
		return 
	}
	for  := range .Nodes {
		 := .nodeJSON[]
		if  == nil {
			return fmt.Errorf("node binding %d is missing", )
		}
		var  geometry.Point
		if  := .Nodes[].Parent;  != nil && .nodeShapeMode[int(*)] == "ROOT" {
			 = .nodeGlobal[int(*)]
		}
		transferShape(&.Nodes[].Shape, , &.X, &.Y, &.Width, &.Height)
	}
	for  := range .Ports {
		 := .portJSON[]
		if  == nil {
			return fmt.Errorf("port binding %d is missing", )
		}
		 := int(.Ports[].Parent)
		var  geometry.Point
		if .nodeShapeMode[] == "ROOT" {
			 = .nodeGlobal[]
		}
		transferShape(&.Ports[].Shape, , &.X, &.Y, &.Width, &.Height)
	}
	for  := range .Labels {
		 := .labelJSON[]
		if  == nil {
			return fmt.Errorf("label binding %d is missing", )
		}
		 := .labelOutputOffset(, , &.Labels[])
		transferShape(&.Labels[].Shape, , &.X, &.Y, &.Width, &.Height)
	}
	for  := range .Edges {
		 := graph.EdgeID()
		 := .Edge()
		 := .edgeOutputOffset(, , )
		 := .edgeJSON[]
		if  == nil {
			return fmt.Errorf("edge binding %d is missing", )
		}
		 := make([]*graphjson.EdgeSection, len(.Sections))
		 := make(map[graph.SectionID]graphjson.ID, len(.Sections))
		for ,  := range .Sections {
			var  *graphjson.EdgeSection
			if int() < len(.sectionJSON) {
				 = .sectionJSON[int()]
			}
			if  == nil {
				 = &graphjson.EdgeSection{}
			}
			if !.ID.IsValid() {
				 := .Section()
				if .IdentifierPresent {
					.ID = graphjson.StringID(.Identifier)
				} else {
					.ID = graphjson.StringID(.ID.String() + "_s" + strconv.Itoa())
				}
			}
			[] = 
			[] = .ID
		}
		for ,  := range .Sections {
			 := .Section()
			 := []
			,  := toJSONPoint(.Start.Add()), toJSONPoint(.End.Add())
			.StartPoint, .EndPoint = &, &
			.BendPoints = make([]graphjson.Point, len(.BendPoints))
			for ,  := range .BendPoints {
				.BendPoints[] = toJSONPoint(.Add())
			}
			if len(.BendPoints) == 0 {
				.BendPoints = nil
			}
			.IncomingShape = .publicShapeID(, .IncomingShape)
			.OutgoingShape = .publicShapeID(, .OutgoingShape)
			.IncomingSections = sectionReferenceIDs(.IncomingSections, )
			.OutgoingSections = sectionReferenceIDs(.OutgoingSections, )
		}
		.Sections = 
		if len() == 0 {
			.Sections = nil
		}
		if ,  := graph.TryGet(&.Properties, JunctionPoints);  {
			.JunctionPoints = make([]graphjson.Point, len())
			for ,  := range  {
				.JunctionPoints[] = toJSONPoint(.Add())
			}
		}
		 := int(.edgeParents[])
		if .nodeEdgeMode[] == "CONTAINER" {
			if .ContainingNode != nil {
				 := .nodeJSON[int(*.ContainingNode)].ID
				.Container = graphjson.IDPtr()
			} else {
				.Container = nil
			}
		}
	}
	return nil
}

func transferShape( *graph.Shape,  geometry.Point, , , ,  **float64) {
	* = graphjson.Float64(.X + .X)
	* = graphjson.Float64(.Y + .Y)
	* = graphjson.Float64(.Width)
	* = graphjson.Float64(.Height)
}

func ( *Codec) ( *graph.Model,  *graph.ShapeID) *graphjson.ID {
	if  == nil {
		return nil
	}
	if .Kind == graph.NodeShape {
		 := .nodeJSON[int(.Node)].ID
		return graphjson.IDPtr()
	}
	 := .portJSON[int(.Port)].ID
	return graphjson.IDPtr()
}

func sectionReferenceIDs( []graph.SectionID,  map[graph.SectionID]graphjson.ID) []graphjson.ID {
	if len() == 0 {
		return nil
	}
	 := make([]graphjson.ID, 0, len())
	for ,  := range  {
		if ,  := [];  {
			 = append(, )
		}
	}
	return 
}