// Based on https://en.wikipedia.org/wiki/Dependency_graph
//
// This example shows how to construct both sync and async DAG dependency graphs using Require and Auto.
//
// It can be used to e.g. resolve blocking code dependencies in order.

package main

import (
	

	

	amhelp 
	am 
)

func init() {
	// load .env
	_ = godotenv.Load()

	// am-dbg is required for debugging, go run it
	// go run github.com/pancsta/asyncmachine-go/tools/cmd/am-dbg@latest
	// amhelp.EnableDebugging(false)
	// amhelp.SetEnvLogLevel(am.LogOps)
}

func main() {
	depGraph()
	asyncDepGraph()
}

// SYNC
func depGraph() {
	// init the state machine
	 := am.New(nil, am.Schema{
		"A": {
			Auto:    true,
			Require: am.S{"B", "C"},
		},
		"B": {
			Auto:    true,
			Require: am.S{"D"},
		},
		"C":     {Auto: true},
		"D":     {Auto: true},
		"Start": {},
	}, &am.Opts{LogLevel: am.LogChanges, Id: "sync"})
	amhelp.MachDebugEnv()
	_ = .BindHandlers(&handlers{})
	.Add1("Start", nil)
}

type handlers struct{}

func ( *handlers) ( *am.Event) {
	println("A ok")
}

func ( *handlers) ( *am.Event) {
	println("B ok")
}

func ( *handlers) ( *am.Event) {
	println("C ok")
}

func ( *handlers) ( *am.Event) {
	println("D ok")
}

// ASYNC

func asyncDepGraph() {
	// init the state machine
	 := am.New(nil, am.Schema{
		"AInit": {
			Auto:    true,
			Require: am.S{"B", "C"},
		},
		"A": {
			Require: am.S{"B", "C"},
		},
		"BInit": {
			Auto:    true,
			Require: am.S{"D"},
		},
		"B": {
			Require: am.S{"D"},
		},
		"CInit": {Auto: true},
		"C":     {},
		"DInit": {Auto: true},
		"D":     {},

		"Start": {},
	}, &am.Opts{LogLevel: am.LogChanges, Id: "async"})
	amhelp.MachDebugEnv()
	_ = .BindHandlers(&asyncHandlers{})
	.Add1("Start", nil)
	<-.When1("A", nil)
}

type asyncHandlers struct{}

func ( *asyncHandlers) ( *am.Event) {
	// unblock
	go func() {
		// block
		time.Sleep(100 * time.Millisecond)
		// next
		.Machine().Add1("A", nil)
	}()
}

func ( *asyncHandlers) ( *am.Event) {
	// unblock
	go func() {
		// block
		time.Sleep(100 * time.Millisecond)
		// next
		.Machine().Add1("B", nil)
	}()
}

func ( *asyncHandlers) ( *am.Event) {
	// unblock
	go func() {
		// block
		time.Sleep(100 * time.Millisecond)
		// next
		.Machine().Add1("C", nil)
	}()
}

func ( *asyncHandlers) ( *am.Event) {
	// unblock
	go func() {
		// block
		time.Sleep(100 * time.Millisecond)
		// next
		.Machine().Add1("D", nil)
	}()
}

func ( *asyncHandlers) ( *am.Event) {
	println("A ok")
}

func ( *asyncHandlers) ( *am.Event) {
	println("B ok")
}

func ( *asyncHandlers) ( *am.Event) {
	println("C ok")
}

func ( *asyncHandlers) ( *am.Event) {
	println("D ok")
}