package main

import (
"fmt"
"os"
"path/filepath"
"sync"
)

// go-fakedu - toy approximation of the du (disk usage)
// toy program to learn go concurrency structures

type FileInfo struct {
path string
info os.FileInfo
}

type SafeArraySlice struct {
m sync.Mutex
data []int64
}

func NewSafeIntArraySlice() *SafeArraySlice {
return &SafeArraySlice{
m: sync.Mutex{},
data: make([]int64, 100),
}
}

func (a *SafeArraySlice) AppendIntArraySlice(i int64) {
a.m.Lock()
defer a.m.Unlock()
a.data = append(a.data, i)
}

func enumFiles(dir string) {
fileCh := make(chan FileInfo)
errCh := make(chan error, 1) // Buffered channel to prevent blocking
var wg sync.WaitGroup

file_size_storage := NewSafeIntArraySlice()

// Start a goroutine for walking the file tree
go func() {
// Send any errors to the errCh channel
errCh <- filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
fileCh <- FileInfo{path, info}
}
return nil
})
close(fileCh) // Close the fileCh channel after walking is done
}()

// Start a goroutine to process files
go func() {
for path := range fileCh {
wg.Add(1)
go func(fInfo FileInfo) {
defer wg.Done()
// Process file (e.g., read, hash, etc.)
fmt.Println(fInfo.path, fInfo.info.Size())
file_size_storage.AppendIntArraySlice(fInfo.info.Size())

}(path)
}
wg.Wait()
close(errCh) // Close the errCh channel after all processing is done
}()

// Check for errors from filepath.Walk
if err := <-errCh; err != nil {
fmt.Println("Error walking the file tree:", err)
return
}

// Not getting a lock here as by now we know
// that nothing is currently accessing this slice
var size int64 = 0
for _, value := range file_size_storage.data {
size = size + value
}

fmt.Println("Total size: ", float32(size)/(1<<20), "MBs")
}

func main() {
args := os.Args
if len(args) < 2 {
fmt.Println("Must provide path to directory")
os.Exit(1)
}

enumFiles(args[1])
}