<?php

  /**
   * Logger class
   *
   * @package angie.library.logger
   */
  final class Logger {
    
    /**
     * Log levels
     */
    const INFO = 0;
    const NOTICE = 1;
    const WARNING = 2;
    const ERROR = 3;
  
    /**
     * Logger messages
     * 
     * @var array
     */
    static private $messages = array();
    
    /**
     * Grouped messages
     * 
     * @var array
     */
    static private $grouped_messages = array();
    
    /**
     * Set max number of messages that will be logged
     *
     * @var integer
     */
    static private $max_messages = 5000;
    
    /**
     * Add message to log
     *
     * @param string $message
     * @param integer $level
     * @param sting $group
     * @return null
     */
    static function log($message, $level = Logger::INFO, $group = null) {
      $log_entry = array($message, $level);
      
      $max_messages_reached = self::$max_messages && count(self::$messages) >= self::$max_messages;
      
      if($max_messages_reached) {
        array_pop(self::$messages);
      } // if
      
      self::$messages[] = $log_entry;
      
      if($group) {
        if(!isset(self::$grouped_messages[$group])) {
          self::$grouped_messages[$group] = array();
        } // if
        
        if($max_messages_reached) {
          array_pop(self::$grouped_messages[$group]);
        } // if
        
        self::$grouped_messages[$group][] = $log_entry;
      } // if
    } // log
    
    /**
     * Return max messages value
     * 
     * @return integer
     */
    static function getMaxMessages() {
      return self::$max_messages;
    } // getMaxMessages
    
    /**
     * Set max messages value
     * 
     * @param integer $max_messages
     */
    static function setMaxMessages($max_messages) {
      self::$max_messages = $max_messages;
    } // setMaxMessages
    
    /**
     * Log entries to file
     *
     * @param string $file_path
     */
    static function logToFile($path) {
      $result = "Logged on: " . date(DATE_COOKIE) . "\nMemory usage: " . format_file_size(memory_get_usage()) . "\nAvailable groups: " . implode(', ', array_merge(array('all'), array_keys(self::$grouped_messages))) . "\n\nall:\n\n";
      
      $counter = 1;
      foreach(self::$messages as $entry) {
        list($message, $level) = $entry;
        $result .= self::prepareMessageForFile($message, $level, $counter);
        $counter++;
      } // foreach
      
      foreach(self::$grouped_messages as $group => $messages) {
        $result .= "\n$group\n\n";
        
        $counter = 1;
        foreach($messages as $entry) {
          list($message, $level) = $entry;
          $result .= self::prepareMessageForFile($message, $level, $counter);
          $counter++;
        } // foreach
      } // foreach
      
      $result .= "\n======================================================\n\n";
      
//      old approach, uses more memory, but may be faster (not confirmed)
//      $result .= file_exists($path) ? file_get_contents($path) : '';
//      return file_put_contents($path, $result);

      
      // new approach - split file if necessary
      $log_file_size_limit = 5 * 1048576; // 5 mb
      
      if (is_file($path) && filesize($path) > $log_file_size_limit) {
        $path_info = pathinfo($path);
        $directory = $path_info['dirname'];
        $extension = $path_info['extension'];
        $filename = $path_info['filename'];
        
        $counter = 0;
        do {
          $counter++;
          $old_file = $directory.'/'.$filename.'-part'.$counter.'.'.$extension;
        } while (is_file($old_file));        
        rename($path, $old_file);      
      } // if
      
      return file_prepend_contents($path, $result);
    } // logToFile
    
    /**
     * Format single message to be saved into file
     *
     * @param string $message
     * @param integer $level
     * @param string $group
     * @return string
     */
    private static function prepareMessageForFile($message, $level, $counter) {
      $level_string = '<unknown>';
      switch($level) {
        case Logger::INFO:
          $level_string = 'info';
          break;
        case Logger::NOTICE:
          $level_string = 'notice';
          break;
        case Logger::WARNING:
          $level_string = 'warning';
          break;
        case Logger::ERROR:
          $level_string = 'error';
          break;
      } // switch
      
      return "#$counter - $level_string - $message\n";
    } // prepareMessageForFile
  
  }