// Copyright (c) 2026 The elk-go Authors.
//
// 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 graphjson

import (
	
	
	
	
)

// javascriptNumber preserves JSON.stringify's numeric boundary semantics.
// JavaScript serializes NaN and infinities as null instead of rejecting the
// containing object, which matters when reproducing an upstream ELK failure
// mode byte-for-byte.
type javascriptNumber float64

func ( javascriptNumber) () ([]byte, error) {
	 := float64()
	if math.IsNaN() || math.IsInf(, 0) {
		return []byte("null"), nil
	}
	return json.Marshal()
}

func decodeObject( []byte,  any,  ...string) (
	map[string]json.RawMessage,
	map[string]json.RawMessage,
	error,
) {
	var  map[string]json.RawMessage
	if  := json.Unmarshal(, &);  != nil {
		return nil, nil, 
	}
	if  := json.Unmarshal(, );  != nil {
		return nil, nil, 
	}
	 := make(map[string]json.RawMessage, len())
	for ,  := range  {
		[] = 
	}
	for ,  := range  {
		delete(, )
	}
	if len() == 0 {
		 = nil
	}
	return , , nil
}

func orderedObjectKeys( json.RawMessage) ([]string, error) {
	if len() == 0 || bytes.Equal(bytes.TrimSpace(), []byte("null")) {
		return nil, nil
	}
	 := json.NewDecoder(bytes.NewReader())
	,  := .Token()
	if  != nil {
		return nil, 
	}
	,  := .(json.Delim)
	if ! ||  != '{' {
		return nil, fmt.Errorf("layout options must be an object")
	}
	 := make([]string, 0)
	 := make(map[string]struct{})
	for .More() {
		,  := .Token()
		if  != nil {
			return nil, 
		}
		,  := .(string)
		if ! {
			return nil, fmt.Errorf("layout option key must be a string")
		}
		var  json.RawMessage
		if  := .Decode(&);  != nil {
			return nil, 
		}
		if ,  := []; ! {
			[] = struct{}{}
			 = append(, )
		}
	}
	if ,  := .Token();  != nil {
		return nil, 
	}
	return , nil
}

func encodeObject( map[string]json.RawMessage,  map[string]any) ([]byte, error) {
	 := make(map[string]any, len()+len())
	for ,  := range  {
		[] = 
	}
	for ,  := range  {
		[] = 
	}
	return json.Marshal()
}

func addID( map[string]any,  string,  ID) {
	if .IsValid() {
		[] = 
	}
}

func addSlice[ any]( map[string]any,  string,  []) {
	if  != nil {
		[] = 
	}
}

func addMap( map[string]any,  string,  LayoutOptions) {
	if  != nil {
		[] = 
	}
}

func addPointer[ any]( map[string]any,  string,  *) {
	if  != nil {
		[] = 
	}
}

func addNumberPointer( map[string]any,  string,  *float64) {
	if  != nil {
		[] = javascriptNumber(*)
	}
}

func ( Point) () ([]byte, error) {
	return json.Marshal(struct {
		 javascriptNumber `json:"x"`
		 javascriptNumber `json:"y"`
	}{: javascriptNumber(.X), : javascriptNumber(.Y)})
}

func ( *Node) ( []byte) error {
	type  Node
	var  
	, ,  := decodeObject(, &,
		"id", "labels", "layoutOptions", "properties", "individualSpacings",
		"x", "y", "width", "height", "children", "ports", "edges")
	if  != nil {
		return 
	}
	* = Node()
	 := "layoutOptions"
	if .LayoutOptions == nil {
		var  struct {
			 LayoutOptions `json:"properties"`
		}
		if  := json.Unmarshal(, &);  != nil {
			return 
		}
		.LayoutOptions = .
		 = "properties"
	}
	.layoutOptionOrder,  = orderedObjectKeys([])
	if  != nil {
		return 
	}
	.individualOrder,  = orderedObjectKeys(["individualSpacings"])
	if  != nil {
		return 
	}
	.AdditionalFields = 
	return nil
}

func ( Node) () ([]byte, error) {
	 := make(map[string]any, 11)
	addID(, "id", .ID)
	addSlice(, "labels", .Labels)
	addMap(, "layoutOptions", .LayoutOptions)
	addMap(, "individualSpacings", .IndividualSpacings)
	addNumberPointer(, "x", .X)
	addNumberPointer(, "y", .Y)
	addNumberPointer(, "width", .Width)
	addNumberPointer(, "height", .Height)
	addSlice(, "children", .Children)
	addSlice(, "ports", .Ports)
	addSlice(, "edges", .Edges)
	return encodeObject(.AdditionalFields, )
}

func ( *Port) ( []byte) error {
	type  Port
	var  
	, ,  := decodeObject(, &,
		"id", "labels", "layoutOptions", "properties", "x", "y", "width", "height")
	if  != nil {
		return 
	}
	* = Port()
	 := "layoutOptions"
	if .LayoutOptions == nil {
		var  struct {
			 LayoutOptions `json:"properties"`
		}
		if  := json.Unmarshal(, &);  != nil {
			return 
		}
		.LayoutOptions = .
		 = "properties"
	}
	.layoutOptionOrder,  = orderedObjectKeys([])
	if  != nil {
		return 
	}
	.AdditionalFields = 
	return nil
}

func ( Port) () ([]byte, error) {
	 := make(map[string]any, 8)
	addID(, "id", .ID)
	addSlice(, "labels", .Labels)
	addMap(, "layoutOptions", .LayoutOptions)
	addNumberPointer(, "x", .X)
	addNumberPointer(, "y", .Y)
	addNumberPointer(, "width", .Width)
	addNumberPointer(, "height", .Height)
	return encodeObject(.AdditionalFields, )
}

func ( *Label) ( []byte) error {
	type  Label
	var  
	, ,  := decodeObject(, &,
		"id", "text", "labels", "layoutOptions", "properties", "x", "y", "width", "height")
	if  != nil {
		return 
	}
	* = Label()
	 := "layoutOptions"
	if .LayoutOptions == nil {
		var  struct {
			 LayoutOptions `json:"properties"`
		}
		if  := json.Unmarshal(, &);  != nil {
			return 
		}
		.LayoutOptions = .
		 = "properties"
	}
	.layoutOptionOrder,  = orderedObjectKeys([])
	if  != nil {
		return 
	}
	.AdditionalFields = 
	return nil
}

func ( Label) () ([]byte, error) {
	 := make(map[string]any, 9)
	addPointer(, "id", .ID)
	addPointer(, "text", .Text)
	addSlice(, "labels", .Labels)
	addMap(, "layoutOptions", .LayoutOptions)
	addNumberPointer(, "x", .X)
	addNumberPointer(, "y", .Y)
	addNumberPointer(, "width", .Width)
	addNumberPointer(, "height", .Height)
	return encodeObject(.AdditionalFields, )
}

func ( *Edge) ( []byte) error {
	type  Edge
	var  
	, ,  := decodeObject(, &,
		"id", "labels", "layoutOptions", "properties", "sources", "targets", "sections",
		"junctionPoints", "source", "sourcePort", "target", "targetPort", "sourcePoint",
		"targetPoint", "bendPoints", "container")
	if  != nil {
		return 
	}
	* = Edge()
	 := "layoutOptions"
	if .LayoutOptions == nil {
		var  struct {
			 LayoutOptions `json:"properties"`
		}
		if  := json.Unmarshal(, &);  != nil {
			return 
		}
		.LayoutOptions = .
		 = "properties"
	}
	.layoutOptionOrder,  = orderedObjectKeys([])
	if  != nil {
		return 
	}
	.AdditionalFields = 
	return nil
}

func ( Edge) () ([]byte, error) {
	 := make(map[string]any, 18)
	addID(, "id", .ID)
	addSlice(, "labels", .Labels)
	addMap(, "layoutOptions", .LayoutOptions)
	addSlice(, "sources", .Sources)
	addSlice(, "targets", .Targets)
	addSlice(, "sections", .Sections)
	addSlice(, "junctionPoints", .JunctionPoints)
	addPointer(, "source", .Source)
	addPointer(, "sourcePort", .SourcePort)
	addPointer(, "target", .Target)
	addPointer(, "targetPort", .TargetPort)
	addPointer(, "sourcePoint", .SourcePoint)
	addPointer(, "targetPoint", .TargetPoint)
	addSlice(, "bendPoints", .BendPoints)
	addPointer(, "container", .Container)
	return encodeObject(.AdditionalFields, )
}

func ( *EdgeSection) ( []byte) error {
	type  EdgeSection
	var  
	, ,  := decodeObject(, &,
		"id", "layoutOptions", "properties", "startPoint", "endPoint", "bendPoints",
		"incomingShape", "outgoingShape", "incomingSections", "outgoingSections")
	if  != nil {
		return 
	}
	* = EdgeSection()
	 := "layoutOptions"
	if .LayoutOptions == nil {
		var  struct {
			 LayoutOptions `json:"properties"`
		}
		if  := json.Unmarshal(, &);  != nil {
			return 
		}
		.LayoutOptions = .
		 = "properties"
	}
	.layoutOptionOrder,  = orderedObjectKeys([])
	if  != nil {
		return 
	}
	.AdditionalFields = 
	return nil
}

func ( EdgeSection) () ([]byte, error) {
	 := make(map[string]any, 10)
	addID(, "id", .ID)
	addMap(, "layoutOptions", .LayoutOptions)
	addPointer(, "startPoint", .StartPoint)
	addPointer(, "endPoint", .EndPoint)
	addSlice(, "bendPoints", .BendPoints)
	addPointer(, "incomingShape", .IncomingShape)
	addPointer(, "outgoingShape", .OutgoingShape)
	addSlice(, "incomingSections", .IncomingSections)
	addSlice(, "outgoingSections", .OutgoingSections)
	return encodeObject(.AdditionalFields, )
}