package main

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
	"strings"
)

// runGuided is what happens when somebody double-clicks the program instead of
// typing its name at a prompt.
//
// Without this, Explorer opens a console, main() finds no arguments, prints
// the usage text to stderr and exits — and Windows destroys the window in the
// same instant. From the other side of the screen that is indistinguishable
// from a crash. So when we know we were double-clicked, we ask the one
// question the program actually needs and stay on screen until the reader is
// done.
//
// This path is entered ONLY when there are no arguments and both ends of the
// program are a real console. Any scripted or piped use takes exactly the same
// code path it always did.
//
// DiskWatch's headline answer — "when do I run out of room?" — needs a history
// of samples taken over days, and a forecast cannot be conjured from a single
// visit. So the guided run does the honest half: it measures the folder now,
// with the same walk "sample" uses, and prints the reading. It does NOT create
// or append to a history file. Where that log lives is a decision the reader
// should make, and it is one line on the command line.
func runGuided() {
	in := bufio.NewScanner(os.Stdin)

	fmt.Println()
	fmt.Println("  DiskWatch")
	fmt.Println("  Watch a folder fill up, and work out when it runs out of room.")
	fmt.Println()
	fmt.Println("  DiskWatch answers that by comparing readings taken days apart, so")
	fmt.Println("  the prediction needs a few of them. Right now I can take the first")
	fmt.Println("  reading for you: how much a folder holds today, and how many files")
	fmt.Println("  and sub-folders are in it.")
	fmt.Println()
	fmt.Println("  It only counts. Nothing is moved, changed or deleted, and no file")
	fmt.Println("  is written — not even a log.")
	fmt.Println()

	suggested := suggestedFolder()
	for {
		fmt.Println("  Which folder shall I measure?")
		if suggested != "" {
			fmt.Printf("  (press Enter for %s)\n", suggested)
		}
		fmt.Print("  > ")

		if !in.Scan() {
			// stdin closed on us; there is nothing sensible left to ask.
			return
		}
		answer := strings.TrimSpace(in.Text())
		answer = strings.Trim(answer, `"`)
		if answer == "" {
			answer = suggested
		}
		if answer == "" {
			fmt.Println()
			fmt.Println("  I need a folder to measure. Try again, or close this window.")
			fmt.Println()
			continue
		}

		info, err := os.Stat(answer)
		switch {
		case err != nil:
			fmt.Println()
			fmt.Printf("  I cannot find %q.\n", answer)
			fmt.Println("  Tip: you can drag a folder from Explorer onto this window to")
			fmt.Println("  paste its location, then press Enter.")
			fmt.Println()
			continue
		case !info.IsDir():
			fmt.Println()
			fmt.Printf("  %q is a file, not a folder. Give me the folder it sits in.\n", answer)
			fmt.Println()
			continue
		}

		abs, err := filepath.Abs(answer)
		if err != nil {
			abs = answer
		}

		fmt.Println()
		fmt.Println("  Counting. On a large folder this can take a minute.")
		fmt.Println()
		reportReading(scanTree(abs))
		break
	}

	fmt.Println()
	fmt.Println("  Done. That is today's reading.")
	fmt.Println("  Take one every week or so and DiskWatch will fit the trend and")
	fmt.Println("  tell you the date the folder runs out of room:")
	fmt.Printf("  %s help\n", appName)
	pause(in)
}

// reportReading prints one measurement in the same shape "sample" prints it,
// minus everything that only makes sense once a history file exists.
func reportReading(e Entry) {
	fmt.Printf("  %s\n", e.Path)
	fmt.Printf("    usage : %s (%d bytes)\n", humanBytes(e.Bytes), e.Bytes)
	fmt.Printf("    files : %d in %d sub-folders\n", e.Files, e.Dirs)
	if e.Errors > 0 {
		fmt.Printf("    note  : %d entries could not be read and were skipped\n", e.Errors)
	}
}

// suggestedFolder offers somewhere worth measuring that is certain to exist,
// so the reader can get a useful answer by pressing one key.
func suggestedFolder() string {
	home, err := os.UserHomeDir()
	if err != nil {
		return ""
	}
	return home
}

// pause keeps the console window open. Explorer closes it the moment the
// process exits, so without this the reader never sees the output.
func pause(in *bufio.Scanner) {
	fmt.Println()
	fmt.Print("  Press Enter to close this window. ")
	in.Scan()
}
