<?php
/**
 * Handle standard OSInet date code strings, uppercase
 * format: [y]ymdd
 * 4-characters until 2009-12-31, 5 afterwards
 *
 * @copyright  (c) 2007 OSI
 * @author     Frédéric G. MARAND
 * @license    Licensed under the CeCILL 2.0
 * @version    CVS: $Id: u_date_code.php,v 1.5 2007-06-10 19:39:54 marand Exp $
 * @link
 * @since      Not applicable yet
 * @package    default
 */

/**
 * needed to sign-compare ints
 */
require_once('boxed_scalars.php');

/**
 * OSInet-format date codes like 07F09 to 2007-06-09
 *
 * @package default
 *
 */
class osinet_date_code implements Comparable_Interface
  {
  private $f_value;

  /**
   * Implements Comparable_Interface restrictively, only comparing to other osinet_date_code objects, not to any other class implementing Comparable_Interface
   * @return int
   */
  public function cmp(Comparable_Interface $other)
    {
    if (!($other instanceof osinet_date_code))
      throw new Exception('osinet_date_code only compares to other osinet_date_code objects');

    $ar_d1 = $this->to_mkdate();
    $d1 = new boxed_int($ar_d1['mday']);
    $m1 = new boxed_int($ar_d1['mon']) ;
    $y1 = new boxed_int($ar_d1['year']);

    $ar_d2 = $other->to_mkdate();
    $d2 = new boxed_int($ar_d2['mday']);
    $m2 = new boxed_int($ar_d2['mon']) ;
    $y2 = new boxed_int($ar_d2['year']);

    $ret = $y1->cmp($y2);
    if ($ret)
      return $ret;
    else // same year
      {
      $ret = $m1->cmp($m2);
      if ($ret)
        return $ret;
      else // same year and month
        {
        $ret = $d1->cmp($d2);
        return $ret;
        }
      }
    }

  /**
   * Generate an mkdate()-like array for a date code
   *
   * @param string $date_code
   * @return array ['mday', 'mon', 'year']
   */
  public function to_mkdate()
    {
    $date_code = strtoupper($this->f_value);
    $matches = array();
    preg_match('/^([0-9]*)([A-Z])([0-9]?.*$)/', $date_code, $matches);
    if (count($matches) <> 4)
      {
      throw new Exception("Incorrect date code $date_code");
      }
    $ret = array(
      'mday' => $matches[3],
      'mon'  => ord($matches[2]) - ord('@'),
      'year' => 2000 + $matches[1],
      );
    return $ret;
    }

  /**
   * @param int $time
   */
  public function __construct($time = null)
    {
    date_default_timezone_set('Europe/Paris');
    if (!$time)
      $time = time();
    $date = getdate();
    $day   = $date['mday'];
    $month = $date['mon'];
    $year  = $date['year'] % 100;

    $month = chr(ord('@') + $month);

    $this->f_value = sprintf('%d%s%02d', $year, $month, $day);
    }

  /**
   * @param string $date_code
   */
  private function set_value($date_code)
    {
    $date_code = strtoupper($date_code);
    $matches = array();
    preg_match('/^([0-9]*)([A-Z])([0-9]?.*$)/', $date_code, $matches);
    if (count($matches) <> 4)
      {
      throw new Exception("Incorrect date code $date_code");
      }
    else
      $this->f_value = $date_code;
    }

  /**
   * @param string $nm
   * @return mixed
   */
  protected function __get($nm)
    {
    // echo "osinet_date_code::__get($nm)\n";
    if ($nm <> 'value')
      throw new Exception("$nm: undefined property for " . get_class($this));

    return $this->f_value;
    }

  /**
   * @param string $nm
   * @param mixed $val
   * @return void
   */
 protected function __set($nm, $val)
    {
    if ($nm <> 'value')
      throw new Exception("$nm: undefined property for " . get_class($this));

    $this->set_value($val);
    }
  }