package main

import "fmt"

type DB struct {
	Name string
}

// double pointer
// a pointer which points to another pointer
func wrapperFunc(config **DB) func() error {
	return func() error {
		cfg := &DB{}
		(*cfg).Name = "hello"
		*config = cfg
		return nil
	}
}

// config = cfg assigns the address which cfg has to config
// hence dd1 in main() doesn't get impacted
func wrapperFunc1(config *DB) func() error {
	return func() error {
		cfg := &DB{}
		fmt.Println("address of config: ", &config)
		fmt.Printf("  wrapperFunc1 A: config is %p, cfg is %p\n", config, cfg)
		cfg.Name = "hello"
		config = cfg
		fmt.Printf("  wrapperFunc1 B: config is %p, cfg is %p\n", config, cfg)
		return nil
	}
}

// *config = *cfg value at address cfg has will be copied to value at the address that config has
// hence dd2 in main() does gets updated
func wrapperFunc2(config *DB) func() error {
	return func() error {
		cfg := &DB{}
		fmt.Printf("  wrapperFunc2 A: config is %p, cfg is %p\n", config, cfg)
		cfg.Name = "hello"
		fmt.Println("value at ", *cfg)
		*config = *cfg
		fmt.Printf("  wrapperFunc2 B: config is %p, cfg is %p\n", config, cfg)
		return nil
	}
}

func wrapperFunc3(config *DB) func() error {
	return func() error {
		config.Name = "hello"
		return nil
	}
}

func wrapperFunc4(config DB) func() error {
	return func() error {
		config.Name = "hello"
		return nil
	}
}

func main() {
	{
		var d *DB
		fn := wrapperFunc(&d)
		fn()
		fmt.Printf("d.Name: %q\n", d.Name)
	}

	{
		dd1 := &DB{}
		fmt.Println("address of dd1: ", &dd1)
		fmt.Printf("main A: dd1 is %p\n", dd1)
		fn1 := wrapperFunc1(dd1)
		fn1()
		fmt.Printf("main B: dd1 is %p\n", dd1)
		fmt.Printf("dd1.Name: %q\n", dd1.Name)
	}

	{
		dd2 := &DB{}
		fmt.Printf("main C: dd2 is %p\n", dd2)
		fn2 := wrapperFunc2(dd2)
		fn2()
		fmt.Printf("main D: dd2 is %p\n", dd2)
		fmt.Printf("dd2.Name: %q\n", dd2.Name)
	}

	{
		dd3 := &DB{}
		fn3 := wrapperFunc3(dd3)
		fn3()
		fmt.Printf("dd3.Name: %q\n", dd3.Name)
	}

	{
		dd4 := DB{}
		fn4 := wrapperFunc4(dd4)
		fn4()
		fmt.Printf("dd4.Name: %q\n", dd4.Name)
	}
}