<?php
namespace nur\cli;

use nur\A;
use nur\func;

/**
 * Class DynamicCommand: implémentation par défaut de {@link IDynamicCommand}
 *
 */
class DynamicCommand implements IDynamicCommand {
  /**
   * retourner la liste des commandes sous la forme d'un tableau associatif avec
   * des éléments { $command => $cdef }
   */
  protected function COMMANDS(): array {
    return static::COMMANDS;
  } const COMMANDS = null;

  private $commands;
  private $dcommands;
  private $aliases;

  protected function buildCommands(): void {
    if ($this->commands !== null) return;
    $commands = [];
    $dcommands = [];
    $aliases = [];
    $index = 0;
    foreach ($this->COMMANDS() as $key => $cdef) {
      if ($key === $index) {
        $index++;
        [$cnames, $assoc] = A::split_assoc($cdef);
        $cname = $cnames[0];
        if ($cname === null) {
          # commande complètement dynamique
          $dcommands[] = $cnames[2];
          if ($cnames[1] === null) continue;
          $cdef = [null, $cnames[1]];
          $cname = $cnames[1][0];
          $cnames = [];
        }
      } else {
        $cname = $key;
        $cnames = [$cname];
        [$seq, $assoc] = A::split_assoc($cdef);
        A::merge($cnames, $seq);
        A::merge_assoc($cdef, $cnames, $assoc, true);
      }
      $commands[$cname] = $cdef;
      foreach ($cnames as $key) {
        $aliases[$key] = $cname;
      }
    }
    $this->commands = $commands;
    $this->dcommands = $dcommands;
    $this->aliases = $aliases;
  }

  function getCommands(): ?array {
    $this->buildCommands();
    return array_keys($this->commands);
  }

  function getCommandDefs(string $command, bool $virtual): ?array {
    $this->buildCommands();
    $command = A::get($this->aliases, $command, $command);
    $cdef = A::get($this->commands, $command);
    if ($cdef !== null) {
      if ($cdef[0] === null) {
        if ($virtual) $cdef = $cdef[1];
        else return null;
      }
      return $cdef !== null? [$cdef]: null;
    }
    # tester les commandes complètement dynamiques
    foreach ($this->dcommands as $func) {
      $cdef = func::call($func, $command);
      if ($cdef !== null) return [$cdef];
    }
    return null;
  }
}