<?php
require_once("PEAR.php");
require_once("Var_Dump.php");
require_once('Log.php');
/** name of the table for error logging */
define('WGRAPHE_LOG_TABLENAME', 'log');
/**
 * @file
 * PEAR Log error levels: 
 * 
 * Level         The constant to pass when using the <code>$Logger->  ('message', CONSTANT);</code> function.
 * Shortcut      You can use the shortcut like this: <code>$Logger->info('Message to   ');</code> 
 * Description
 * 
 * 
 * PEAR_LOG_EMERG
 * emerg()
 * System is unusable
 * 
 * PEAR_LOG_ALERT
 * alert()
 * Immediate action required
 * 
 * PEAR_LOG_CRIT
 * crit()
 * Critical conditions
 * 
 * PEAR_LOG_ERR
 * err()
 * Error conditions
 * 
 * PEAR_LOG_WARNING
 * warning()
 * Warning conditions
 * 
 * PEAR_LOG_NOTICE
 * notice()
 * Normal but significant
 * 
 * PEAR_LOG_INFO
 * info()
 * Informational
 * 
 * PEAR_LOG_DEBUG
 * debug()
 * Debug-level messages
 * @author Alexandre Quessy
 */
 define('WGRAPHE_ERROR_DIE', PEAR_LOG_ALERT); /* dies & show */
 define('WGRAPHE_ERROR_DEBUG', PEAR_LOG_DEBUG); /* debug */
 define('WGRAPHE_ERROR_NOTICE', PEAR_LOG_NOTICE); /* debug & show */
 define('WGRAPHE_ERROR_INFO', PEAR_LOG_INFO);   /* shows */

/**
 * Gestionnaires d'erreurs PEAR et PHP. Ces fonctions seront appelees en cas d'erreurs.
 *
 * Pour tester ces error handlers:
 * <code> PEAR::raiseError('This is an information    message.', PEAR_LOG_INFO);</code>
 * <code>PEAR::raiseError('Test object error.', PEAR_LOG_INFO); </code>
 * @package wikigraphe_core
 */

class ErrorHandler {
  /** @var array Error message to be shown */
  var $messages = array();
    /** @var array String of variable dump */
  var $list_of_debugs = array();
  /** @array boolean */
  var $logging_enabled = FALSE;
  /** @var object  PEAR/Log */
  var $logger;
  /** @var boolean Debug mode */
  var $debug_mode = FALSE;
  
  /**
   * Etabli les gestionnaires d'erreurs PEAR et PHP.
   * 
   * Ne peut pas ere appele de facon statique! 
   * @see ErrorHandler::addMessage()
   * @todo Enable the error logger when we can get a DB using DB_DataObject::getDatabaseConnection()
   */
  function ErrorHandler() {
    /* Configure les error handlers pour PHP et PEAR */
    set_error_handler(array($this, 'php'));
    PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array($this, 'pear'));
    //$this->logger =& $this->loggerFactory();
    //$this->logging_enabled = TRUE;
  }
  
  /**
   * Handler for PHP errors : will send convert it to a PEAR error that will be handled by the PEAR errors handler
   * If you want to test it: 
   * <code>trigger_error('This is an information    message.', E_USER_NOTICE);</code>
   * 
   */
  function php($code, $message, $file, $line) {
    /* Map the PHP error to a Log priority. */
    switch ($code) {
      /* Fatal PHP errors cannot be handled. */
      case E_WARNING:
      case E_USER_WARNING:
        $priority = PEAR_LOG_WARNING;
        break;
      case E_NOTICE:
      case E_USER_NOTICE:
        $priority = PEAR_LOG_NOTICE;
        break;
      case E_ERROR:
      case E_USER_ERROR:
        $priority = PEAR_LOG_ERR;
        break;
      default:
        $priority = PEAR_LOG_INFO;
      }
      
    /* Logs the error in the    with the $Logger object (instance of PEAR/Log) */
    //$logger->  ('PHP: ' . $message . ' in ' . $file . ' at line ' . $line, $priority);
    $pear_message = 'PHP: ' . $message . ' in ' . $file . ' at line ' . $line;
    // Then calls the function pear() below
    PEAR::raiseError($pear_message, $priority);
    //debug(array('Erreur PHP'=>array($code, $message, $file, $line)));
  }
  
  /**
   * This is the PEAR error handler. This function is called when there is a PEAR error. 
   *
   * @param object $Error   Objet d'erreur PEAR
   */
  function pear($Error) {
    $message = $Error->getMessage();
    /*
     * I add this, but it might give some risky debug infos. It is just for the log file 
     */
    $backtrace = $Error->getBacktrace();
    $message .= print_r($backtrace, TRUE);
    /*
    if (@empty($backtrace['userinfo'])) {
      $message .= "";
    } else {
      $message .= " " . $backtrace['userinfo'];
    }
    */
    /**
     * Ajoute les infos pour le deboggage pour le log file
     */
    if (substr($message, 0, 4) != 'PHP:') { /* ligne importante: sinon on verrait le mauvais num�o de ligne quand c'est une erreur PHP */
      if (!empty($Error->backtrace[1]['file'])) {
        $message .= ' (' . $Error->backtrace[1]['file'];
        if (!empty($Error->backtrace[1]['line'])) {
          $message .= ' at line ' . $Error->backtrace[1]['line'];
        }
        $message .= ')';
      }
    } 
    $code = $Error->code;

    switch ($code) {
      /* Erreurs importantes. */
      case PEAR_LOG_EMERG:
      case PEAR_LOG_ALERT:
      case PEAR_LOG_CRIT:
      case PEAR_LOG_WARNING:
        $show = TRUE;
        $log =  TRUE; 
        $die =  TRUE;
        break;

      /* Erreurs ? */
      case PEAR_LOG_ERR:
        $show = TRUE;
        $log =  TRUE; 
        $die =  FALSE;
        break;

      /* Not�s dans le fichier de log pour d�ogage. */ 
      case PEAR_LOG_DEBUG:
        $show = FALSE;
        $log =  TRUE; 
        $die =  FALSE;
        break;

      /* Not�s dans le log, elles sont aussi montr�s �l'usager */
      case PEAR_LOG_NOTICE:
        $show = TRUE;
        $log =  TRUE; 
        $die =  FALSE;
        break;

      /* Je montre ces erreurs �l'usager. */ 
      case PEAR_LOG_INFO:
      default:
        $show = TRUE;
        $log =  FALSE; 
        $die =  FALSE;
        break;
    }

    /* Outputs the error message or die, according to the error level. */
    if ($log) {
      if ($this->logging_enabled) {
        $this->logger->log($message, $code); 
      } 
      $this->dump(array('Error'=>array('code'=>$code, 'message'=>$message)));
    }
    if ($die && !$show) {
      die();
    } elseif ($die && $show) {
      die($Error->getMessage());
    } elseif ($show) {
      $this->addMessage($Error->getMessage());
    }
    if ($this->isDebugMode()) {
      $this->dump($Error->userinfo); 
    }
  }
  /**
   * Met le mode verbose a on ou off
   * @param bool $val 
   */
  function setDebugMode($val) {
    $this->debug_mode = $val;
  } 
  /** @return bool Are we in debug mode ? */
  function isDebugMode() {
    return $this->debug_mode;
  }
  /**
   * Ajoute quelque chose dans la liste des variables a debugger
   */
  function dump($var) {
    if ($this->isDebugMode()) {
      ob_start();
      Var_Dump::display($var);
      $result = ob_get_clean();
      $this->list_of_debugs[] = $result;
    }
  }
  /** Error logging 
   * @see Log::log()
  */
  function log($message ) {
    $this->logger->log($message);
  }
  
  /**
   * Affiche un message �l'usager. 
   * @param string|null $mess Message
   */
  function addMessage($mess) {
    $i;
    if (!isset($i)) {
      $i = 0;
    } else {
      $i++;
    }
    if (!is_null($mess)) {
      /* Le 'k' de la cl�est pour �iter des name clashes quand on fait un array_merge par la suite. */
      $this->messages["k$i"] = $mess;
    }
  }
  /** 
   * @return All the error messages as an array
   */
  function getMessages() {
    if (@is_object(@$this)) {
      //return array_merge($this->user_messages, $this->messages);
      return $this->messages;
    }
  }

/**
 * PEAR/Log factory that returns a PEAR/Log object with a configuration for a sql logging.
 * 
 * Then, you just need to do this to    an error:
 * <code>$GLOBALS['Logger']->  ('Message', PEAR_LOG_NOTICE);</code>
 * To test it, do something like this :
 * <code>for ($i = 0; $i < 10; $i++) {
 *   $error->log("Log entry $i");
 * }</code>
 * @param string $file_path The error    file. Has to be chmod 600, chown nobody, or 
 *                          chmod 666.
 * @static
 * @return object $Logger a PEAR/Log instance meant to be global. 
 * @link http://www.indelible.org/pear/Log/guide.php The PEAR/Log online documentation. 
 * @todo Change log method to db 
     * <code>mode = 0600</code>            UNIX rights on the file
     * <code>append = TRUE</code>          Should the strings be added at the end of the file ?
     * <code>eol = '\n'</code>             UNIX line endings.
     * <code>timeFormat = '%a %Y-%m-%d %H:%M'</code> ISO format for strftime() PHP function
     */
  function &loggerFactory(&$pear_db) {
    $configuration = array('db' => &$pear_db);
    //$file_path = $dir_path . date('Y-m') . '_fliki.error  .txt';
    return Log::factory('sql', WGRAPHE_LOG_TABLENAME, 'ident', $configuration);
  }
}
?>