<?php
namespace nur\sery\app;

use nur\sery\cl;
use nur\sery\file\SharedFile;
use nur\sery\output\msg;
use nur\sery\php\time\DateTime;

/**
 * Class LockFile: une classe qui permet à une application de verrouiller
 * certaines actions
 */
class LockFile {
  const NAME = null;

  const TITLE = null;

  function __construct($file, ?string $name=null, ?string $title=null) {
    $this->file = new SharedFile($file);
    $this->name = $name ?? static::NAME;
    $this->title = $title ?? static::TITLE;
  }

  /** @var SharedFile */
  protected $file;

  /** @var ?string */
  protected $name;

  /** @var ?string */
  protected $title;

  protected function initData(): array {
    return [
      "name" => $this->name,
      "title" => $this->title,
      "locked" => false,
      "date_lock" => null,
      "date_release" => null,
    ];
  }

  function read(bool $close=true): array {
    $data = $this->file->unserialize(null, $close);
    if (!is_array($data)) $data = $this->initData();
    return $data;
  }

  function isLocked(?array &$data=null): bool {
    $data = $this->read();
    return $data["locked"];
  }

  function warnIfLocked(?array $data=null): bool {
    if ($data === null) $data = $this->read();
    if ($data["locked"]) {
      msg::warning("$data[name]: possède le verrou depuis $data[date_lock] -- $data[title]");
      return true;
    }
    return false;
  }

  function lock(?array &$data=null): bool {
    $file = $this->file;
    $data = $this->read(false);
    if ($data["locked"]) {
      $file->close();
      return false;
    } else {
      $file->ftruncate();
      $file->serialize(cl::merge($data, [
        "locked" => true,
        "date_lock" => new DateTime(),
        "date_release" => null,
      ]));
      return true;
    }
  }

  function release(?array &$data=null): void {
    $file = $this->file;
    $data = $this->read(false);
    $file->ftruncate();
    $file->serialize(cl::merge($data, [
      "locked" => false,
      "date_release" => new DateTime(),
    ]));
  }
}
