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.
//
// Guided mode runs "check", which reads the driver files and prints what is
// wrong with them. It writes nothing at all — not even the inventory file the
// "inventory" command produces — and it never touches the live Windows driver
// store or installs anything.
func runGuided() {
	in := bufio.NewScanner(os.Stdin)

	fmt.Println()
	fmt.Println("  DriverPilot")
	fmt.Println("  Check a folder of Windows drivers for problems before you use it.")
	fmt.Println()
	fmt.Println("  It opens every driver package in the folder and reports the ones")
	fmt.Println("  that will not read properly, the ones with no version or date, the")
	fmt.Println("  ones whose signature file is named but missing, and any two")
	fmt.Println("  packages that claim the same piece of hardware.")
	fmt.Println()
	fmt.Println("  It only reads. Nothing is installed, changed or deleted, and your")
	fmt.Println("  live Windows driver store is never touched.")
	fmt.Println()

	suggested := suggestedFolder()
	for {
		fmt.Println("  Which driver folder shall I check?")
		fmt.Println("  (the folder your drivers were downloaded or unpacked into)")
		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 check. 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
		}

		fmt.Println()
		fmt.Println("  Reading every driver package below that folder.")
		fmt.Println()
		runCheck([]string{answer})
		break
	}

	fmt.Println()
	fmt.Println("  Done. Nothing was installed or changed.")
	fmt.Println("  The command-line version can also record what is in this folder")
	fmt.Println("  and compare it against another day's list: driverpilot --help")
	pause(in)
}

// suggestedFolder offers somewhere worth checking that is certain to exist, so
// the reader can get a useful answer by pressing one key.
//
// There is no folder of driver packages every machine is guaranteed to have,
// so this returns nothing rather than something wrong. An empty suggestion is
// handled by the prompt: it simply asks for a path instead of offering a
// default.
func suggestedFolder() string {
	home, err := os.UserHomeDir()
	if err != nil {
		return ""
	}
	for _, rel := range []string{
		"Drivers",
		filepath.Join("Downloads", "Drivers"),
		filepath.Join("Documents", "Drivers"),
	} {
		candidate := filepath.Join(home, rel)
		if info, err := os.Stat(candidate); err == nil && info.IsDir() {
			return candidate
		}
	}
	return ""
}

// 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()
}
