<?php
namespace nur\v\base;

use nur\A;
use nur\authz;
use nur\md;
use nur\v\model\IMenuManager;

class MenuManager implements IMenuManager {
  function __construct($menu=null, ?string $selectedId=null) {
    $this->init($menu, $selectedId);
  }

  /** @var array */
  private $menu;

  /** @var string */
  private $selectedId;

  /** @var bool */
  private $built;

  /** @var string */
  private $brand;

  /** @var array */
  private $navbarItems;

  function init($menu, ?string $selectedId): void {
    $this->menu = null;
    $this->selectedId = null;
    $this->built = false;
    $this->brand = null;
    $this->navbarItems = null;
    if ($menu !== null) {
      md::ensure_schema($menu, self::MENU_SCHEMA, null, false);
      $this->menu = $menu;
      $this->selectedId = $selectedId;
    }
  }

  private function build($id, array $item, string $menuType="menu"): ?array {
    md::ensure_schema($item, self::ITEM_SCHEMA);
    A::replace_n($item, "id", $id);
    A::replace_n_indirect($item, "id", "url");

    $perms = $item["perm"];
    $roles = $item["role"];
    if ($perms !== null || $roles !== null) {
      $user = authz::get();
      if ($perms !== null && !$user->isPerm($perms)) return null;
      if ($roles !== null && !$user->isRole($roles)) return null;
    }

    $id = $item["id"];
    $text = $item["text"];
    $accesskey = $item["accesskey"];
    $target = $item["target"];
    $active = $id === $this->selectedId;

    $startOfMenu = false;
    $setNavbarItems = false;
    $subItems = $item["items"];
    $navbarItems = null;
    if ($subItems) {
      $index = 0;
      foreach ($subItems as $subId => $subItem) {
        if ($subId === $index) {
          $subId = null;
          $index++;
        }
        $navbarItem = $this->build($subId, $subItem, "link");
        if ($navbarItem === null) continue;
        if (!$active && $navbarItem["active"]) {
          $active = true;
          $startOfMenu = true;
        }
        if ($navbarItem["som"]) $setNavbarItems = true;
        A::append($navbarItems, $navbarItem);
      }
    }
    $itemType = $navbarItems ? $menuType : "link";
    if ($setNavbarItems) $this->navbarItems = $navbarItems;

    $url = $item["url"];
    if ($itemType == "link" && $url === null) {
      $class = is_array($text) && count($text) == 1? $text[0]: $text;
      if (class_exists($class)) {
        $url = $class;
        $text = $class::TITLE;
      } else if ($navbarItems) {
        $url = $navbarItems[0]["url"];
      }
    }
    A::merge($tmpText, $item["prefix"], $text, $item["suffix"]);
    $text = $tmpText;
    $params = $item["params"];

    return [
      "item" => $itemType,
      "text" => $text,
      "url" => $url,
      "params" => $params,
      "active" => $active,
      "show_active" => $item["show_active"],
      "links" => $navbarItems,
      "accesskey" => $accesskey,
      "target" => $target,
      "som" => $startOfMenu,
    ];
  }

  function get(): array {
    if (!$this->built) {
      $this->brand = $this->menu["brand"];
      $this->navbarItems = $navbarItems = null;
      $index = 0;
      $items = $this->menu["items"];
      if ($items !== null) {
        foreach ($items as $id => $item) {
          if ($id === $index) {
            $id = null;
            $index++;
          }
          $navbarItem = $this->build($id, $item);
          if ($navbarItem !== null) $navbarItems[] = $navbarItem;
        }
      }
      if ($this->navbarItems === null) $this->navbarItems = $navbarItems;
      $this->built = true;
    }
    return [
      "brand" => $this->brand,
      "navbar_items" => $this->navbarItems,
    ];
  }
}