<?php
namespace nur\sery\wip\cli;

use Exception;
use nur\sery\ExitException;
use nur\sery\output\msg;
use nur\sery\output\std\StdMessenger;

/**
 * Class Application: une application en ligne de commande
 */
abstract class Application {
  protected static function _app_init(): void {
    msg::set_messenger_class(StdMessenger::class);
  }

  protected static function _app_configure(Application $app): void {
    $app->parseArgs();
  }

  protected static function _app_main(Application $app): void {
    $retcode = $app->main();
    if (is_int($retcode)) exit($retcode);
    elseif (is_bool($retcode)) exit($retcode? 0: 1);
    elseif ($retcode !== null) exit(strval($retcode));
  }

  static function run(?Application $app=null): void {
    try {
      static::_app_init();
      if ($app === null) $app = new static();
      static::_app_configure($app);
      static::_app_main($app);
    } catch (ExitException $e) {
      msg::error($e->getUserMessage());
      exit($e->getCode());
    } catch (Exception $e) {
      msg::error($e);
      exit(1);
    }
  }

  /**
   * sortir de l'application avec un code d'erreur, qui est 0 par défaut (i.e
   * pas d'erreur)
   *
   * équivalent à lancer l'exception {@link ExitException}
   */
  protected static final function exit(int $exitcode=0, $message=null) {
    throw new ExitException($exitcode, $message);
  }

  /**
   * sortir de l'application avec un code d'erreur, qui vaut 1 par défaut (i.e
   * une erreur s'est produite)
   *
   * équivalent à lancer l'exception {@link ExitException}
   */
  protected static final function die($message=null, int $exitcode=1) {
    throw new ExitException($exitcode, $message);
  }

  const ARGS = [];

  /** @throws ArgsException */
  function parseArgs(array $args=null): void {
    $parser = new ArgsParser(static::ARGS);
    $parser->parse($this, $args);
  }

  abstract function main();
}
