<?php
namespace nur\sery\output\std;

use Exception;
use nur\sery\A;
use nur\sery\cl;
use nur\sery\ExceptionShadow;
use nur\sery\output\IMessenger;
use nur\sery\UserException;
use Throwable;

class StdMessenger implements _IMessenger {
  const INDENT = "  ";
  const DATE_FORMAT = 'Y-m-d\TH:i:s.u';

  const VALID_LEVELS = [self::DEBUG, self::MINOR, self::NORMAL, self::MAJOR, self::NONE];
  const LEVEL_MAP = [
    "debug" => self::DEBUG,
    "minor" => self::MINOR, "verbose" => self::MINOR,
    "normal" => self::NORMAL,
    "major" => self::MAJOR, "quiet" => self::MAJOR,
    "none" => self::NONE, "silent" => self::NONE,
  ];

  protected static function verifix_level($level, int $max_level=self::MAX_LEVEL): int {
    if (!in_array($level, self::VALID_LEVELS, true)) {
      $level = cl::get(self::LEVEL_MAP, $level, $level);
    }
    if (!in_array($level, self::VALID_LEVELS, true)) {
      throw new Exception("$level: invalid level");
    }
    if ($level > $max_level) {
      throw new Exception("$level: level not allowed here");
    }
    return $level;
  }

  const GENERIC_PREFIXES = [
    self::MAJOR => [
      "section" => [true, "SECTION!", "===", "<color @b>=", "=</color>", "==="],
      "title" => [false, "TITLE!", null, "<color @b>T", "</color>", "==="],
      "desc" => ["DESC!", "<color @b>></color>", ""],
      "error" => ["CRIT.ERROR!", "<color @r>E!", "</color>"],
      "warning" => ["CRIT.WARNING!", "<color @y>W!", "</color>"],
      "note" => ["ATTENTION!", "<color @g>N!", "</color>"],
      "info" => ["IMPORTANT!", "<color @b>N!", "</color>"],
      "step" => ["*", "<color @w>.</color>", ""],
      "print" => [null, null, null],
    ],
    self::NORMAL => [
      "section" => [true, "SECTION:", "---", "<color @b>-", "-</color>", "---"],
      "title" => [false, "TITLE:", null, "<color @b>T</color><color b>", "</color>", "---"],
      "desc" => ["DESC:", "<color @b>></color>", ""],
      "error" => ["ERROR:", "<color @r>E</color><color r>", "</color>"],
      "warning" => ["WARNING:", "<color @y>W</color><color y>", "</color>"],
      "note" => ["NOTE:", "<color @g>N</color>", ""],
      "info" => ["INFO:", "<color @b>I</color>", ""],
      "step" => ["*", "<color @w>.</color>", ""],
      "print" => [null, null, null],
    ],
    self::MINOR => [
      "section" => [true, "section", null, "<color @w>>>", "<<</color>", null],
      "title" => [false, "title", null, "<color b>t", "</color>", null],
      "desc" => ["desc", "<color b>></color>", ""],
      "error" => ["error", "<color r>E</color><color -r>", "</color>"],
      "warning" => ["warning", "<color y>W</color><color -y>", "</color>"],
      "note" => ["note", "<color g>N</color>", ""],
      "info" => ["info", "<color b>I</color><color w>", "</color>"],
      "step" => ["*", "<color w>.</color>", ""],
      "print" => [null, null, null],
    ],
    self::DEBUG => [
      "section" => [true, "section", null, "<color @w>>>", "<<</color>", null],
      "title" => [false, "title", null, "<color b>t", "</color>", null],
      "desc" => ["desc", "<color b>></color>", ""],
      "error" => ["debugE", "<color r>e</color><color -r>", "</color>"],
      "warning" => ["debugW", "<color y>w</color><color -y>", "</color>"],
      "note" => ["debugN", "<color b>i</color>", ""],
      "info" => ["debug", "<color @w>D</color><color w>", "</color>"],
      "step" => ["*", "<color w>.</color>", ""],
      "print" => [null, null, null],
    ],
  ];

  const RESULT_PREFIXES = [
    "failure" => ["(FAILURE)", "<color r>✘</color>"],
    "success" => ["(SUCCESS)", "<color @g>✔</color>"],
    "done" => [null, null],
  ];

  function __construct(?array $params=null) {
    $output = cl::get($params, "output");
    $color = cl::get($params, "color");
    $indent = cl::get($params, "indent", static::INDENT);

    $defaultLevel = cl::get($params, "default_level");
    if ($defaultLevel === null) $defaultLevel = self::NORMAL;
    $defaultLevel = self::verifix_level($defaultLevel);

    $debug = boolval(cl::get($params, "debug"));
    $minLevel = cl::get($params, "min_level");
    if ($minLevel === null && $debug) $minLevel = self::DEBUG;
    if ($minLevel === null) $minLevel = cl::get($params, "verbosity"); # alias
    if ($minLevel === null) $minLevel = self::NORMAL;
    $minLevel = self::verifix_level($minLevel, self::NONE);

    $addDate = boolval(cl::get($params, "add_date"));
    $dateFormat = cl::get($params, "date_format", static::DATE_FORMAT);
    $id = cl::get($params, "id");

    $params = [
      "color" => $color,
      "indent" => $indent,
    ];
    if ($output !== null) {
      $this->err = $this->out = new StdOutput($output, $params);
    } else {
      $this->out = new StdOutput(STDOUT, $params);
      $this->err = new StdOutput(STDERR, $params);
    }
    $this->defaultLevel = $defaultLevel;
    $this->minLevel = $minLevel;
    $this->addDate = $addDate;
    $this->dateFormat = $dateFormat;
    $this->id = $id;
    $this->inSection = false;
    $this->titles = [];
    $this->actions = [];
  }

  function resetParams(?array $params=null): void {
    $output = cl::get($params, "output");
    $color = cl::get($params, "color");
    $indent = cl::get($params, "indent");

    $defaultLevel = cl::get($params, "default_level");
    if ($defaultLevel !== null) $defaultLevel = self::verifix_level($defaultLevel);

    $debug = cl::get($params, "debug");
    $minLevel = cl::get($params, "min_level");
    if ($minLevel === null && $debug !== null) $minLevel = $debug? self::DEBUG: self::NORMAL;
    if ($minLevel === null) $minLevel = cl::get($params, "verbosity"); # alias
    if ($minLevel !== null) $minLevel = self::verifix_level($minLevel, self::NONE);

    $addDate = cl::get($params, "add_date");
    $dateFormat = cl::get($params, "date_format");
    $id = cl::get($params, "id");

    $params = [
      "output" => $output,
      "color" => $color,
      "indent" => $indent,
    ];
    if ($this->out === $this->err) {
      $this->out->resetParams($params);
    } else {
      # NB: si initialement [output] était null, et qu'on spécifie une valeur
      # [output], alors les deux instances $out et $err sont mis à jour
      # séparément avec la même valeur de output
      # de plus, on ne peut plus revenir à la situation initiale avec une
      # destination différente pour $out et $err
      $this->out->resetParams($params);
      $this->err->resetParams($params);
    }
    if ($defaultLevel !== null) $this->defaultLevel = $defaultLevel;
    if ($minLevel !== null) $this->minLevel = $minLevel;
    if ($addDate !== null) $this->addDate = boolval($addDate);
    if ($dateFormat !== null) $this->dateFormat = $dateFormat;
    if ($id !== null) $this->id = $id;
  }

  function clone(?array $params=null): IMessenger {
    $clone = clone $this;
    if ($params !== null) $clone->resetParams($params);
    #XXX faut-il marquer la section et les titres du clone à "print" => false?
    # ou en faire des références au parent?
    # dans tous les cas, on considère qu'il n'y a pas d'actions en cours, et on
    # ne doit pas dépiler avec end() plus que l'état que l'on a eu lors du clone
    return $clone;
  }

  /** @var StdOutput la sortie standard */
  protected $out;

  /** @var StdOutput la sortie d'erreur */
  protected $err;

  /** @var int level par défaut dans lequel les messages sont affichés */
  protected $defaultLevel;

  /** @var int level minimum que doivent avoir les messages pour être affichés */
  protected $minLevel;

  /** @var bool faut-il ajouter la date à chaque ligne? */
  protected $addDate;

  /** @var string format de la date */
  protected $dateFormat;

  /** @var ?string identifiant de ce messenger, à ajouter à chaque ligne */
  protected $id;

  protected function getLinePrefix(): ?string {
    $linePrefix = null;
    if ($this->addDate) {
      $date = date_create()->format($this->dateFormat);
      $linePrefix .= "$date ";
    }
    if ($this->id !== null) {
      $linePrefix .= "$this->id ";
    }
    return $linePrefix;
  }

  protected function decrLevel(int $level, int $amount=-1): int {
    $level += $amount;
    if ($level < self::MIN_LEVEL) $level = self::MIN_LEVEL;
    return $level;
  }

  protected function checkLevel(?int &$level): bool {
    if ($level === null) $level = $this->defaultLevel;
    elseif ($level < 0) $level = $this->decrLevel($this->defaultLevel, $level);
    return $level >= $this->minLevel;
  }

  protected function getIndentLevel(bool $withActions=true): int {
    $indentLevel = count($this->titles) - 1;
    if ($indentLevel < 0) $indentLevel = 0;
    if ($withActions) {
      foreach ($this->actions as $action) {
        if ($action["level"] < $this->minLevel) continue;
        $indentLevel++;
      }
    }
    return $indentLevel;
  }

  protected function _printTitle(?string $linePrefix, int $level,
                                 string $type, $content,
                                 int $indentLevel, StdOutput $out): void {
    $prefixes = self::GENERIC_PREFIXES[$level][$type];
    if ($prefixes[0]) $out->print();
    $content = cl::with($content);
    if ($out->isColor()) {
      $before = $prefixes[2];
      $prefix = $prefixes[3];
      $prefix2 = $prefix !== null? "$prefix ": null;
      $suffix = $prefixes[4];
      $suffix2 = $suffix !== null? " $suffix": null;
      $after = $prefixes[5];

      $lines = $out->getLines(false, ...$content);
      $maxlen = 0;
      foreach ($lines as &$content) {
        $line = $out->filterColors($content);
        $len = mb_strlen($line);
        if ($len > $maxlen) $maxlen = $len;
        $content = [$content, $len];
      }; unset($content);
      if ($before !== null) {
        if ($linePrefix !== null) $out->write($linePrefix);
        $out->iprint($indentLevel, $prefix, substr($before, 1), str_repeat($before[0], $maxlen), $suffix);
      }
      foreach ($lines as [$content, $len]) {
        if ($linePrefix !== null) $out->write($linePrefix);
        $padding = $len < $maxlen? str_repeat(" ", $maxlen - $len): null;
        $out->iprint($indentLevel, $prefix2, $content, $padding, $suffix2);
      }
      if ($after !== null) {
        if ($linePrefix !== null) $out->write($linePrefix);
        $out->iprint($indentLevel, $prefix, substr($after, 1), str_repeat($after[0], $maxlen), $suffix);
      }
    } else {
      $prefix = $prefixes[1];
      if ($prefix !== null) $prefix .= " ";
      $prefix2 = str_repeat(" ", mb_strlen($prefix));
      $lines = $out->getLines(false, ...$content);
      foreach ($lines as $content) {
        if ($linePrefix !== null) $out->write($linePrefix);
        $out->iprint($indentLevel, $prefix, $content);
        $prefix = $prefix2;
      }
    }
  }

  protected function _printAction(?string $linePrefix, int $level,
                                  bool $printContent, $content,
                                  bool $printResult, ?bool $rsuccess, $rcontent,
                                  int $indentLevel, StdOutput $out): void {
    $color = $out->isColor();
    if ($rsuccess === true) $type = "success";
    elseif ($rsuccess === false) $type = "failure";
    else $type = "done";
    $rprefixes = self::RESULT_PREFIXES[$type];
    if ($color) {
      $rprefix = $rprefixes[1];
      $rprefix2 = null;
      if ($rprefix !== null) {
        $rprefix .= " ";
        $rprefix2 = $out->filterColors($out->filterContent($rprefix));
        $rprefix2 = str_repeat(" ", mb_strlen($rprefix2));
      }
    } else {
      $rprefix = $rprefixes[0];
      if ($rprefix !== null) $rprefix .= " ";
      $rprefix2 = str_repeat(" ", mb_strlen($rprefix));
    }
    if ($printContent && $printResult) {
      A::ensure_array($content);
      if ($rcontent) {
        $content[] = ": ";
        $content[] = $rcontent;
      }
      $lines = $out->getLines(false, ...$content);
      foreach ($lines as $content) {
        if ($linePrefix !== null) $out->write($linePrefix);
        $out->iprint($indentLevel, $rprefix, $content);
        $rprefix = $rprefix2;
      }
    } elseif ($printContent) {
      $prefixes = self::GENERIC_PREFIXES[$level]["step"];
      if ($color) {
        $prefix = $prefixes[1];
        if ($prefix !== null) $prefix .= " ";
        $prefix2 = $out->filterColors($out->filterContent($prefix));
        $prefix2 = str_repeat(" ", mb_strlen($prefix2));
        $suffix = $prefixes[2];
      } else {
        $prefix = $prefixes[0];
        if ($prefix !== null) $prefix .= " ";
        $prefix2 = str_repeat(" ", mb_strlen($prefix));
        $suffix = null;
      }
      A::ensure_array($content);
      $content[] = ":";
      $lines = $out->getLines(false, ...$content);
      foreach ($lines as $content) {
        if ($linePrefix !== null) $out->write($linePrefix);
        $out->iprint($indentLevel, $prefix, $content, $suffix);
        $prefix = $prefix2;
      }
    } elseif ($printResult) {
      if (!$rcontent) {
        if ($type === "success") $rcontent = $color? "succès": "";
        elseif ($type === "failure") $rcontent = $color? "échec": "";
        elseif ($type === "done") $rcontent = "fait";
      }
      $rprefix = " $rprefix";
      $rprefix2 = " $rprefix2";
      $lines = $out->getLines(false, $rcontent);
      foreach ($lines as $rcontent) {
        if ($linePrefix !== null) $out->write($linePrefix);
        $out->iprint($indentLevel, $rprefix, $rcontent);
        $rprefix = $rprefix2;
      }
    }
  }

  protected function _printGeneric(?string $linePrefix, int $level,
                                   string $type, $content,
                                   int $indentLevel, StdOutput $out): void {
    $prefixes = self::GENERIC_PREFIXES[$level][$type];
    $content = cl::with($content);
    if ($out->isColor()) {
      $prefix = $prefixes[1];
      $prefix2 = null;
      if ($prefix !== null) {
        $prefix .= " ";
        $prefix2 = $out->filterColors($out->filterContent($prefix));
        $prefix2 = str_repeat(" ", mb_strlen($prefix2));
      }
      $suffix = $prefixes[2];
      $lines = $out->getLines(false, ...$content);
      foreach ($lines as $content) {
        if ($linePrefix !== null) $out->write($linePrefix);
        $out->iprint($indentLevel, $prefix, $content, $suffix);
        $prefix = $prefix2;
      }
    } else {
      $prefix = $prefixes[0];
      if ($prefix !== null) $prefix .= " ";
      $prefix2 = str_repeat(" ", mb_strlen($prefix));
      $lines = $out->getLines(false, ...$content);
      foreach ($lines as $content) {
        if ($linePrefix !== null) $out->write($linePrefix);
        $out->iprint($indentLevel, $prefix, $content);
        $prefix = $prefix2;
      }
    }
  }

  protected function _printGenericOrException(?int $level, string $type, $content, int $indentLevel, StdOutput $out): void {
    $linePrefix = $this->getLinePrefix();
    # si $content contient des exceptions, les afficher avec un level moindre
    $exceptions = null;
    if (is_array($content)) {
      $valueContent = null;
      foreach ($content as $value) {
        if ($value instanceof Throwable || $value instanceof ExceptionShadow) {
          $exceptions[] = $value;
        } else {
          $valueContent[] = $value;
        }
      }
      if ($valueContent === null) $content = null;
      elseif (count($valueContent) == 1) $content = $valueContent[0];
      else $content = $valueContent;
    } elseif ($content instanceof Throwable || $content instanceof ExceptionShadow) {
      $exceptions[] = $content;
      $content = null;
    }

    $printActions = true;
    $showContent = $this->checkLevel($level);
    if ($content !== null && $showContent) {
      $this->printActions(); $printActions = false;
      $this->_printGeneric($linePrefix, $level, $type, $content, $indentLevel, $out);
    }
    if ($exceptions !== null) {
      $level1 = $this->decrLevel($level);
      $showTraceback = $this->checkLevel($level1);
      foreach ($exceptions as $exception) {
        # tout d'abord userMessage
        if ($exception instanceof UserException) {
          $userMessage = UserException::get_user_message($exception);
          $showSummary = true;
        } else {
          $userMessage = UserException::get_summary($exception);
          $showSummary = false;
        }
        if ($userMessage !== null && $showContent) {
          if ($printActions) { $this->printActions(); $printActions = false; }
          $this->_printGeneric($linePrefix, $level, $type, $userMessage, $indentLevel, $out);
        }
        # puis summary et traceback
        if ($showTraceback) {
          if ($printActions) { $this->printActions(); $printActions = false; }
          if ($showSummary) {
            $summary = UserException::get_summary($exception);
            $this->_printGeneric($linePrefix, $level1, $type, $summary, $indentLevel, $out);
          }
          $traceback = UserException::get_traceback($exception);
          $this->_printGeneric($linePrefix, $level1, $type, $traceback, $indentLevel, $out);
        }
      }
    }
  }

  /** @var bool est-on dans une section? */
  protected $inSection;

  /** @var array section qui est en attente d'affichage */
  protected $section;

  function section($content, ?callable $func=null, ?int $level=null): void {
    $this->_endSection();
    $this->inSection = true;
    if (!$this->checkLevel($level)) return;
    $this->section = [
      "line_prefix" => $this->getLinePrefix(),
      "level" => $level,
      "content" => $content,
      "print_content" => true,
    ];
    if ($func !== null) {
      try {
        $func($this);
      } finally {
        $this->_endSection();
      }
    }
  }

  protected function printSection() {
    $section =& $this->section;
    if ($section !== null && $section["print_content"]) {
      $this->_printTitle(
        $section["line_prefix"], $section["level"],
        "section", $section["content"],
        0, $this->err);
      $section["print_content"] = false;
    }
  }

  function _endSection(): void {
    $this->inSection = false;
    $this->section = null;
  }

  /** @var array */
  protected $titles;

  /** @var array */
  protected $title;

  function _getTitleMark(): int {
    return count($this->titles);
  }

  function title($content, ?callable $func=null, ?int $level=null): void {
    if (!$this->checkLevel($level)) return;
    $until = $this->_getTitleMark();
    $this->titles[] = [
      "line_prefix" => $this->getLinePrefix(),
      "level" => $level,
      "content" => $content,
      "print_content" => true,
      "descs" => [],
      "print_descs" => false,
    ];
    $this->title =& $this->titles[$until];
    if ($func !== null) {
      try {
        $func($this);
      } finally {
        $this->_endTitle($until);
      }
    }
  }

  function desc($content, ?int $level=null): void {
    if (!$this->checkLevel($level)) return;
    $title =& $this->title;
    $title["descs"][] = [
      "line_prefix" => $this->getLinePrefix(),
      "level" => $level,
      "content" => $content,
    ];
    $title["print_descs"] = true;
  }

  protected function printTitles(): void {
    $this->printSection();
    $err = $this->err;
    $indentLevel = 0;
    foreach ($this->titles as &$title) {
      if ($title["print_content"]) {
        $this->_printTitle(
          $title["line_prefix"], $title["level"],
          "title", $title["content"],
          $indentLevel, $err);
        $title["print_content"] = false;
      }
      if ($title["print_descs"]) {
        foreach ($title["descs"] as $desc) {
          $this->_printGeneric(
            $desc["line_prefix"], $desc["level"],
            "desc", $desc["content"],
            $indentLevel, $err);
        }
        $title["descs"] = [];
        $title["print_descs"] = false;
      }
      $indentLevel++;
    }; unset($title);
  }

  function _endTitle(?int $until=null): void {
    if ($until === null) $until = $this->_getTitleMark() - 1;
    while (count($this->titles) > $until) {
      array_pop($this->titles);
    }
    if ($this->titles) {
      $this->title =& $this->titles[count($this->titles) - 1];
    } else {
      $this->titles = [];
      unset($this->title);
    }
  }

  /** @var array */
  protected $actions;
  
  /** @var array */
  protected $action;

  function _getActionMark(): int {
    return count($this->actions);
  }

  function action($content, ?callable $func=null, ?int $level=null): void {
    $this->checkLevel($level);
    $until = $this->_getActionMark();
    $this->actions[] = [
      "line_prefix" => $this->getLinePrefix(),
      "level" => $level,
      "content" => $content,
      "print_content" => true,
      "result_success" => null,
      "result_content" => null,
    ];
    $this->action =& $this->actions[$until];
    if ($func !== null) {
      try {
        $result = $func($this);
        if ($this->_getActionMark() > $until) {
          $this->aresult($result);
        }
      } catch (Exception $e) {
        $this->afailure($e);
        throw $e;
      } finally {
        $this->_endAction($until);
      }
    }
  }
  
  function printActions(bool $endAction=false, ?int $overrideLevel=null): void {
    $this->printTitles();
    $err = $this->err;
    $indentLevel = $this->getIndentLevel(false);
    $lastIndex = count($this->actions) - 1;
    $index = 0;
    foreach ($this->actions as &$action) {
      $mergeResult = $index++ == $lastIndex && $endAction;
      $linePrefix = $action["line_prefix"];
      $level = $overrideLevel?? $action["level"];
      $content = $action["content"];
      $printContent = $action["print_content"];
      $rsuccess = $action["result_success"];
      $rcontent = $action["result_content"];
      if ($level < $this->minLevel) continue;
      if ($mergeResult) {
        $this->_printAction(
          $linePrefix, $level,
          $printContent, $content,
          true, $rsuccess, $rcontent,
          $indentLevel, $err);
      } elseif ($printContent) {
        $this->_printAction(
          $linePrefix, $level,
          $printContent, $content,
          false, $rsuccess, $rcontent,
          $indentLevel, $err);
        $action["print_content"] = false;
      }
      $indentLevel++;
    }; unset($action);
    if ($endAction) $this->_endAction();
  }

  function step($content, ?int $level=null): void {
    $this->_printGenericOrException($level, "step", $content, $this->getIndentLevel(), $this->err);
  }

  function asuccess($content=null, ?int $overrideLevel=null): void {
    if (!$this->actions) $this->action(null);
    $this->action["result_success"] = true;
    $this->action["result_content"] = $content;
    $this->printActions(true, $overrideLevel);
  }

  function afailure($content=null, ?int $overrideLevel=null): void {
    if (!$this->actions) $this->action(null);
    $this->action["result_success"] = false;
    $this->action["result_content"] = $content;
    $this->printActions(true, $overrideLevel);
  }

  function adone($content=null, ?int $overrideLevel=null): void {
    if (!$this->actions) $this->action(null);
    $this->action["result_success"] = null;
    $this->action["result_content"] = $content;
    $this->printActions(true, $overrideLevel);
  }

  function aresult($result=null, ?int $overrideLevel=null): void {
    if (!$this->actions) $this->action(null);
    if ($result === true) $this->asuccess(null, $overrideLevel);
    elseif ($result === false) $this->afailure(null, $overrideLevel);
    elseif ($result instanceof Exception) $this->afailure($result, $overrideLevel);
    else $this->adone($result, $overrideLevel);
  }

  function _endAction(?int $until=null): void {
    if ($until === null) $until = $this->_getActionMark() - 1;
    while (count($this->actions) > $until) {
      array_pop($this->actions);
    }
    if ($this->actions) {
      $this->action =& $this->actions[count($this->actions) - 1];
    } else {
      $this->actions = [];
      unset($this->action);
    }
  }

  function print($content, ?int $level=null): void {
    $this->_printGenericOrException($level, "print", $content, $this->getIndentLevel(), $this->out);
  }

  function info($content, ?int $level=null): void {
    $this->_printGenericOrException($level, "info", $content, $this->getIndentLevel(), $this->err);
  }

  function note($content, ?int $level=null): void {
    $this->_printGenericOrException($level, "note", $content, $this->getIndentLevel(), $this->err);
  }

  function warning($content, ?int $level=null): void {
    $this->_printGenericOrException($level, "warning", $content, $this->getIndentLevel(), $this->err);
  }

  function error($content, ?int $level=null): void {
    $this->_printGenericOrException($level, "error", $content, $this->getIndentLevel(), $this->err);
  }

  function end(bool $all=false): void {
    if ($all) {
      while ($this->actions) $this->adone();
      while ($this->titles) $this->_endTitle();
      $this->_endSection();
    } elseif ($this->actions) {
      $this->_endAction();
    } elseif ($this->titles) {
      $this->_endTitle();
    } else {
      $this->_endSection();
    }
  }
}
