<?php
namespace nur;

use nur\b\date\Date as D;
use nur\b\date\Datetime as DT;
use nur\b\date\Elapsed;

/**
 * Class date: méthode pour gérer les dates au format français dd/mm/YYYY
 */
class date {
  static function is_datetime($date, ?array &$ms=null): bool {
    return is_string($date) && preg_match('/^(\d{1,2})[-\/]+(\d{1,2})[-\/]+(\d{2,4}) ([0-9]{1,2})[h:.,]([0-9]{1,2})(?:[:.,]([0-9]{1,2}))?$/', $date, $ms);
  }

  static function is_date($date, ?array &$ms=null): bool {
    return is_string($date) && preg_match('/^(\d{1,2})[-\/]+(\d{1,2})[-\/]+(\d{2,4})(?: 0{1,2}[h:.,]0{1,2}(?:[:.,]0{1,2})?)?$/', $date, $ms);
  }

  static function datetime(?int $timestamp=null): string {
    if ($timestamp === null) $timestamp = time();
    return strftime("%d/%m/%Y %H:%M:%S", $timestamp);
  }

  static function date(?int $timestamp=null): string {
    if ($timestamp === null) $timestamp = time();
    return strftime("%d/%m/%Y", $timestamp);
  }

  /**
   * corriger une année à deux chiffres qui est située dans le passé et
   * retourner l'année à 4 chiffres.
   *
   * par exemple, si l'année courante est 2019, alors:
   * - fix_past_year('18') === '2018'
   * - fix_past_year('19') === '1919'
   * - fix_past_year('20') === '1920'
   */
  static function fix_past_year(int $year): int {
    if ($year < 100) {
      $y = getdate(); $y = $y["year"];
      $r = $y % 100;
      $c = $y - $r;
      if ($year >= $r) $year += $c - 100;
      else $year += $c;
    }
    return $year;
  }

  /**
   * corriger une année à deux chiffres et retourner l'année à 4 chiffres.
   * l'année charnière entre année passée et année future est 70
   *
   * par exemple, si l'année courante est 2019, alors:
   * - fix_past_year('18') === '2018'
   * - fix_past_year('19') === '2019'
   * - fix_past_year('20') === '2020'
   * - fix_past_year('69') === '2069'
   * - fix_past_year('70') === '1970'
   * - fix_past_year('71') === '1971'
   */
  static function fix_any_year(int $year): int {
    if ($year < 100) {
      $y = getdate(); $y = $y["year"];
      $r = $y % 100;
      $c = $y - $r;
      if ($year >= 70) $year += $c - 100;
      else $year += $c;
    }
    return $year;
  }

  static function _ms2datetime(array $ms, ?string &$date, ?string &$time): void {
    $d = intval($ms[1]);
    $m = intval($ms[2]);
    $y = self::fix_any_year($ms[3]);
    $H = intval($ms[4]);
    $M = intval($ms[5]);
    $S = intval(isset($ms[6])? $ms[6]: 0);
    $date = sprintf("%02d/%02d/%04d", $d, $m, $y);
    $time = sprintf("%02d:%02d:%02d", $H, $M, $S);
  }

  static function _ms2date(array $ms, ?string &$date): void {
    $d = intval($ms[1]);
    $m = intval($ms[2]);
    $y = self::fix_any_year($ms[3]);
    $date = sprintf("%02d/%02d/%04d", $d, $m, $y);
  }

  /**
   * Analyser $datetime qui peut être de la forme 'dd/mm/YYYY HH:MM:SS' ou
   * 'dd/mm/YYYY' et initialiser les variables $date et $time
   *
   * s'il n'y a pas de composante 'heure' dans $datetime, $time reçoit la
   * valeur null.
   *
   * retourner true si $datetime était au format attendu, false sinon
   */
  static function _split_datetime(?string $datetime, ?string &$date, ?string &$time): bool {
    $ms = null;
    if (self::is_datetime($datetime, $ms)) {
      self::_ms2datetime($ms, $date, $time);
      return true;
    } elseif (self::is_date($datetime, $ms)) {
      self::_ms2date($ms, $date);
      $time = null;
      return true;
    } else {
      return false;
    }
  }

  static function split_datetime($datetime, ?string &$date, ?string &$time): bool {
    if ($datetime === null || $datetime === false) return false;
    else return self::_split_datetime($datetime, $date, $time);
  }

  static function new($date, bool $null_is_now=false): ?DT {
    if ($null_is_now && $date === null) return new DT();
    elseif ($date === null) return null;
    elseif (is_int($date)) return new DT($date);
    return self::is_datetime($date)? new DT($date): new D($date);
  }

  static function before($date, $other): bool {
    if ($other === null) return true;
    if ($date === null) return false;
    return self::new($date)->before(self::new($other));
  }

  static function after($date, $other): bool {
    if ($other === null) return true;
    if ($date === null) return false;
    return self::new($date)->after(self::new($other));
  }

  static function get_elapsed($date, $now=null): Elapsed {
    return self::new($date, true)->getElapsed(self::new($now));
  }
}
