package d2lib

import (
	
	
	
	
	

	
	
	
	
	
	
	
	
	
	
	
	
	
)

type CompileOptions struct {
	UTF16Pos       bool
	FS             fs.FS
	MeasuredTexts  []*d2target.MText
	Ruler          *textmeasure.Ruler
	RouterResolver func(engine string) (d2graph.RouteEdges, error)
	LayoutResolver func(engine string) (d2graph.LayoutGraph, error)

	Layout *string

	// FontFamily controls the font family used for all texts that are not the following:
	// - code
	// - latex
	// - pre-measured (web setting)
	// TODO maybe some will want to configure code font too, but that's much lower priority
	FontFamily *d2fonts.FontFamily

	InputPath string
}

func ( context.Context,  string,  *CompileOptions) (*d2ast.Map, error) {
	if  == nil {
		 = &CompileOptions{}
	}

	,  := d2parser.Parse(.InputPath, strings.NewReader(), &d2parser.ParseOptions{
		UTF16Pos: .UTF16Pos,
	})
	return , 
}

func ( context.Context,  string,  *CompileOptions,  *d2svg.RenderOpts) (*d2target.Diagram, *d2graph.Graph, error) {
	if  == nil {
		 = &CompileOptions{}
	}
	if  == nil {
		 = &d2svg.RenderOpts{}
	}

	, ,  := d2compiler.Compile(.InputPath, strings.NewReader(), &d2compiler.CompileOptions{
		UTF16Pos: .UTF16Pos,
		FS:       .FS,
	})
	if  != nil {
		return nil, nil, 
	}

	applyConfigs(, , )
	applyDefaults(, )
	if  != nil {
		.Data = .Data
	}

	,  := compile(, , , )
	if  != nil {
		if  == nil {
			 = &d2target.Config{}
		}
		// These are fields that affect a diagram's appearance, so feed them back
		// into diagram.Config to ensure the hash computed for CSS styling purposes
		// is unique to its appearance
		.ThemeID = .ThemeID
		.DarkThemeID = .DarkThemeID
		.Sketch = .Sketch
		.Config = 
	}
	return , , 
}

func compile( context.Context,  *d2graph.Graph,  *CompileOptions,  *d2svg.RenderOpts) (*d2target.Diagram, error) {
	 := .ApplyTheme(*.ThemeID)
	if  != nil {
		return nil, 
	}

	if len(.Objects) > 0 {
		 := .SetDimensions(.MeasuredTexts, .Ruler, .FontFamily)
		if  != nil {
			return nil, 
		}

		,  := getLayout()
		if  != nil {
			return nil, 
		}
		,  := getEdgeRouter()
		if  != nil {
			return nil, 
		}

		 := d2layouts.NestedGraphInfo(.Root)
		 = d2layouts.LayoutNested(, , , , )
		if  != nil {
			return nil, 
		}
	}

	,  := d2exporter.Export(, , .FontFamily)
	if  != nil {
		return nil, 
	}

	for ,  := range .Layers {
		,  := (, , , )
		if  != nil {
			return nil, 
		}
		.Layers = append(.Layers, )
	}
	for ,  := range .Scenarios {
		,  := (, , , )
		if  != nil {
			return nil, 
		}
		.Scenarios = append(.Scenarios, )
	}
	for ,  := range .Steps {
		,  := (, , , )
		if  != nil {
			return nil, 
		}
		.Steps = append(.Steps, )
	}
	return , nil
}

func getLayout( *CompileOptions) (d2graph.LayoutGraph, error) {
	if .Layout != nil {
		return .LayoutResolver(*.Layout)
	} else if os.Getenv("D2_LAYOUT") == "dagre" {
		 := func( context.Context,  *d2graph.Graph) error {
			return d2dagrelayout.Layout(, , nil)
		}
		return , nil
	} else {
		return nil, errors.New("no available layout")
	}
}

func getEdgeRouter( *CompileOptions) (d2graph.RouteEdges, error) {
	if .Layout != nil && .RouterResolver != nil {
		,  := .RouterResolver(*.Layout)
		if  != nil {
			return nil, 
		}
		if  != nil {
			return , nil
		}
	}
	return d2layouts.DefaultRouter, nil
}

// applyConfigs applies the configs read from D2 and applies it to passed in opts
// It will only write to opt fields that are nil, as passed-in opts have precedence
func applyConfigs( *d2target.Config,  *CompileOptions,  *d2svg.RenderOpts) {
	if  == nil {
		return
	}

	if .Layout == nil {
		.Layout = .LayoutEngine
	}

	if .ThemeID == nil {
		.ThemeID = .ThemeID
	}
	if .DarkThemeID == nil {
		.DarkThemeID = .DarkThemeID
	}
	if .Sketch == nil {
		.Sketch = .Sketch
	}
	if .Pad == nil {
		.Pad = .Pad
	}
	if .Center == nil {
		.Center = .Center
	}
	.ThemeOverrides = .ThemeOverrides
	.DarkThemeOverrides = .DarkThemeOverrides
}

func applyDefaults( *CompileOptions,  *d2svg.RenderOpts) {
	if .Layout == nil {
		.Layout = go2.Pointer("dagre")
	}

	if .ThemeID == nil {
		.ThemeID = &d2themescatalog.NeutralDefault.ID
	}
	if .Sketch == nil {
		.Sketch = go2.Pointer(false)
	}
	if *.Sketch {
		.FontFamily = go2.Pointer(d2fonts.HandDrawn)
	}
	if .Pad == nil {
		.Pad = go2.Pointer(int64(d2svg.DEFAULT_PADDING))
	}
	if .Center == nil {
		.Center = go2.Pointer(false)
	}
}