package main

import (
	"bufio"
	"fmt"
	"os"
	"runtime"
	"strings"
	"time"
)

// defaultPhaseDuration is what the reader gets by pressing Enter: long enough
// for the numbers to settle, short enough that nobody wonders whether the
// program has hung. It matches the command line's own default.
const defaultPhaseDuration = 500 * time.Millisecond

// runGuided is what happens when somebody double-clicks CorePilot instead of
// typing its name at a prompt.
//
// Explorer opens a console, runs the program with no arguments, and destroys
// the window the instant the process exits — so printing usage and quitting
// looks exactly like a crash. When we know we were double-clicked we ask the
// one thing CorePilot needs and stay on screen until the reader is done.
//
// CorePilot only measures: it does arithmetic in memory and reports how fast
// it went. It reads no files and writes none, so there is nothing here that
// could change anything on the machine.
func runGuided() {
	in := bufio.NewScanner(os.Stdin)

	fmt.Println()
	fmt.Println("  CorePilot")
	fmt.Println("  Find out how much work your processor really gets through.")
	fmt.Println()
	fmt.Printf("  This machine reports %d processor cores. I will give it a hard sum to\n", runtime.NumCPU())
	fmt.Println("  do twice: once using a single core, then again using all of them, and")
	fmt.Println("  show you how much faster the second run was. That is the number that")
	fmt.Println("  tells you whether all those cores are actually pulling their weight.")
	fmt.Println()
	fmt.Println("  Nothing is opened, saved or changed — this is a measurement only.")
	fmt.Println()

	duration := defaultPhaseDuration
	for {
		fmt.Println("  How long should each of the two runs last?")
		fmt.Printf("  (press Enter for %s, or type something like 2s or 10s)\n", defaultPhaseDuration)
		fmt.Print("  > ")

		if !in.Scan() {
			// stdin closed on us; there is nothing sensible left to ask.
			return
		}
		answer := strings.TrimSpace(in.Text())
		if answer == "" {
			break
		}
		// A bare number is what most people type. Read it as seconds rather
		// than rejecting it over a missing unit.
		if !strings.ContainsAny(answer, "smhSMH") {
			answer += "s"
		}
		d, err := time.ParseDuration(strings.ToLower(answer))
		switch {
		case err != nil:
			fmt.Println()
			fmt.Printf("  I could not read %q as a length of time.\n", strings.TrimSpace(in.Text()))
			fmt.Println("  Try 2s for two seconds, or 500ms for half a second.")
			fmt.Println()
			continue
		case d <= 0:
			fmt.Println()
			fmt.Println("  That has to be longer than nothing. Try 2s.")
			fmt.Println()
			continue
		case d > time.Minute:
			fmt.Println()
			fmt.Println("  That is longer than a minute per run, which will pin your")
			fmt.Println("  processor for a very long time. Try 10s or less.")
			fmt.Println()
			continue
		}
		duration = d
		break
	}

	fmt.Println()
	fmt.Printf("  Working. This takes about %s in total, and the fans may spin up.\n", 2*duration)
	fmt.Println()
	runBench([]string{"--duration", duration.String()})

	fmt.Println()
	fmt.Println("  Done. The scaling figure is the honest one to look at: it is how many")
	fmt.Println("  times more work all your cores did than one core alone.")
	fmt.Println("  There is a command-line version too, which can report the same run as")
	fmt.Println("  machine-readable data: corepilot --help")
	pause(in)
}

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