<?php

/**
 * 
 * @author p6
 *
 */
class CriticalSection
{
  /**
   * full file path
   * @var string
   */
  protected $filename = null;
  /**
   * lock name
   * @var mixed
   */
  protected $name = null;
  /**
   * lock id
   * @var string
   */
  protected $id = null;
  /**
   * a file pointer resource on success, or false on error. 
   * @var resource
   */
  protected $handle = false;

  /**
   * creates a critical section object (using a file lock)
   * @param mixed $name name of the lock
   */
  public function __construct($name)
  {
    $this->name = $name;
    $this->id = md5($name);
    $this->filename = pathCombine(app()->runtimePath, "critical_section_".$this->id.".bin");
    $this->handle = false;
  }

  /**
   * lock the selected file
   * @return boolean true if the file has been opened and locked, false otherwise
   */
  public function lock()
  {
    if($this->isLocked())
      return true;
    $this->handle = fopen($this->filename, "w");
    if($this->handle === false)
    {
      $this->handle = false;
      return false;
    }
    if (flock($this->handle, LOCK_EX) !== true)
    {
      fclose($this->handle);
      $this->handle = false;
      return false;
    }
    return true;
  }

  /**
   * tell if the current object is locked
   * @return boolean true if the file has been opened and locked, false otherwise
   */
  public function isLocked()
  {
    return $this->handle !== false;
  }

  /**
   * unlock (if needed) the current object
   */
  public function unlock()
  {
    if(!$this->isLocked())
      return;
    flock($this->handle, LOCK_UN);
    fclose($this->handle);
    $this->handle = false;
  }

  function __destruct()
  {
    $this->unlock();
  }

  public function __toString()
  {
    return $this->name;
  }
}