// account-race.go provides an example of race conditions and data races if ran in a concurrent way
// If this program is ran sequentially then everythin is fine but once the program is ran in parallel
// is when problems could arise.
//
// Few terms to know:
//
// 1. A **race condition** is a situation, in which the result of an operation depends on the interleaving of certain individual operations.
//
// 2. A  **data race** is a situtation when at least two threads access a shared variable at the same time. One thread must try to modify the variable.
//
package main

import (
	"fmt"
	"sync"
	"sync/atomic"
	"time"
)

type Account struct {
	balance int32
}

func transfer(amount int32, from *Account, to *Account, group *sync.WaitGroup) {

	if from.balance >= amount {
		atomic.AddInt32(&(from.balance), -amount)
		time.Sleep(1 * time.Nanosecond)
		atomic.AddInt32(&(to.balance), amount)
	}
	group.Done()
}

func main() {

	account1 := Account{100}
	account2 := Account{100}

	var group sync.WaitGroup

	group.Add(2)

	go transfer(50, &account1, &account2, &group)
	go transfer(145, &account2, &account1, &group)

	group.Wait()
	fmt.Println("Account1 Balance = $", account1.balance)
	fmt.Println("Account2 Balance = $", account2.balance)

}
