//
// Copyright (c) 2025, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//   12 May 2025  Brian Frank  Creation
//

using util

**
** Fantom CLI compiler command plugin.  To create:
**
**  1. Define subclass of FancCmd
**  2. Register type qname via indexed prop as "fanc.cmd" (if not in this pod)
**  3. Annotate options and args using `util::AbstractMain` design
**
abstract class FancCmd : AbstractMain
{
  ** Find a specific command or return null
  static FancCmd? find(Str name)
  {
    list.find |cmd| { cmd.name == name || cmd.aliases.contains(name) }
  }

  ** List installed commands
  static FancCmd[] list()
  {
    acc := FancCmd[,]

    // this pod
    FancCmd#.pod.types.each |t|
    {
      if (t.fits(FancCmd#) && !t.isAbstract) acc.add(t.make)
    }

    // other pods via index
    Env.cur.index("fanc.cmd").each |qname|
    {
      try
      {
        type := Type.find(qname)
        cmd := (FancCmd)type.make
        acc.add(cmd)
      }
      catch (Err e) echo("ERROR: invalid fanc.cmd $qname\n  $e")
    }

    acc.sort |a, b| { a.name <=> b.name }
    return acc
  }

  ** App name is "fanc {name}"
  override final Str appName() { "fanc $name" }

  ** Log name is "fanc"
  override Log log() { Log.get("fanc") }

  ** Command name
  abstract Str name()

  ** Command name alises/shortcuts
  virtual Str[] aliases() { Str[,] }

  ** Name and aliases
  Str[] names() { [name].addAll(aliases) }

  ** Run the command.  Return zero on success
  abstract override Int run()

  ** Single line summary of the command for help
  abstract Str summary()

//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////

  ** Print a line to stdout
  Void printLine(Str line := "") { echo(line) }

  ** Print info message
  Void info(Str msg) { printLine(msg) }

  ** Print error message and return 1
  Int err(Str msg) { printLine("ERROR: $msg"); return 1 }

  ** Prompt for a confirm yes/no
  Bool promptConfirm(Str msg)
  {
    res := Env.cur.prompt("$msg (y/n)> ")
    if (res.lower == "y") return true
    return false
  }
}