<?php
namespace nur\v\base;

use nur\b\ValueException;
use nur\F;
use nur\str;

trait TActionSupport {
  /**
   * @return string nom du paramètre qui contient l'action à effectuer.
   * retourner null pour désactiver le support des actions
   */
  protected function ACTION_PARAM(): ?string {
    return static::ACTION_PARAM;
  }

  /** @return array liste des actions valides */
  protected function VALID_ACTIONS(): ?array {
    return static::VALID_ACTIONS;
  }

  /** @var string|false action à déclencher manuellement  */
  private $doAction;

  function doAction(string $action): void {
    $this->doAction = $action;
  }

  /** obtenir l'action demandée par l'utilisateur */
  protected function getAction(): ?string {
    $action = $this->doAction;
    if ($action === false) return null;
    if ($action === null) {
      $actionParam = $this->ACTION_PARAM();
      if ($actionParam === null) return null;
      $action = F::get($actionParam);
    }
    return $action;
  }

  /** vérifier si $action est une action valide */
  protected function isValidAction(string $action): bool {
    if ($action === $this->doAction) return true;
    $validActions = $this->VALID_ACTIONS();
    return $validActions !== null && in_array($action, $validActions);
  }

  /** retourner true si on va déclencher une action */
  protected function willDispatchAction(): bool {
    if ($this->doAction === false)  return false;
    $action = $this->getAction();
    return $action !== null && $this->isValidAction($action);
  }

  private $actionDispatched = false;
  private $actionCompleted = true;
  function dispatchAction(bool $dispatch=true): void {
    if ($this->actionDispatched) return;
    if ($dispatch) {
      $action = $this->getAction();
      if ($action !== null) {
        if (!$this->isValidAction($action)) {
          throw ValueException::invalid_value($action, "action");
        }
        $method = str_replace("-", "_", $action) . "_action";
        $method = str::us2camel($method);
        $retval = $this->$method();
        $this->actionCompleted = $retval !== false;
      }
    } else {
      $this->doAction = false;
    }
    $this->actionDispatched = true;
  }

  function haveContent(): bool {
    return parent::haveContent() && (
        !$this->actionCompleted || !$this->willDispatchAction()
      );
  }

  function afterSetup(): void {
    $this->dispatchAction();
    parent::afterSetup();
  }
}
