<?php

/**
 *       @file  qtrLogger.php
 *      @brief  plugin logger implementation
 *
 *
 *     @author  Quttera (qtr), contactus@quttera.com
 *
 *   @internal
 *     Created  01/14/2016
 *    Compiler  gcc/g++
 *     Company  Quttera
 *   Copyright  Copyright (c) 2016, Quttera
 *
 * This source code is released for free distribution under the terms of the
 * GNU General Public License as published by the Free Software Foundation.
 * =====================================================================================
 */

/**
 * FILE LOGGING CONFIGURATION
 * 
 * To enable writing logs to file, define the QTR_DEBUG_LOG constant as true in wp-config.php:
 * 
 *     define('QTR_DEBUG_LOG', true);
 * 
 * When enabled:
 *     - All log messages (Debug, Info, Warning, Error) are written to runtime.log
 *     - Log file location: {plugin_root}/runtime.log
 *     - Each log entry includes timestamp, severity level, and message
 *     - File is flushed after each write for real-time updates
 *     - Use Clean() method to clear both database and file logs
 * 
 * Note: File logging only occurs if QTR_DEBUG_LOG is defined and true.
 *       Without this constant, _log_file remains null and no file operations occur.
 */

require_once('qtrConfig.php');
require_once('qtrOptions.php');

define( 'QTR_LOGGER','quttera_wp_logger');

class CQtrLogger
{
    protected $_log_cache;
    protected $_severity;    
    protected $_config;
    protected $_max_lines;
    protected $_is_cli;
    protected $_log_file;
    protected $_log_file_name;

    public function __construct()
    {
        $this->_config      = new CQtrConfig();
        $this->_severity    = $this->_config->LogSeverity();
        
        if( defined("QTR_DEBUG") && QTR_DEBUG ){
            $this->_max_lines   = 200;
        }else{
            $this->_max_lines   = 50;
        }

        $this->_log_file    = null;

        if (php_sapi_name() == "cli") { 
            $this->_is_cli = TRUE;
        } else {
            $this->_is_cli = FALSE;
        }

        $this->_log_file_name =  dirname(__FILE__) . DIRECTORY_SEPARATOR . 'runtime.log';
        $this->_LoadLog();
        $this->_OpenLogFile();
    }

    public function Severity(){
        return $this->_severity;
    }

    public function SeverityStr(){
        return $this->_config->LogSeverityStr( $this->_severity);
    }


    public function Clean(){
        /*
         * reset log lines stored in database
         */
        $this->_log_cache = array();
        $this->_StoreLog();
        /*
         * reset log file
         */
        $this->_ResetLog();
    }


    public function Debug( $msg ){
        if( $this->_severity >= CQtrConfig::$LOG_SEVERITY["DEBUG"] ){
            if( defined("QTR_DEBUG") && QTR_DEBUG ){
                $this->_Trim();
                $this->_Log("DEBUG",$msg);
            }
        }
    }


    public function Info( $msg ){
        if( $this->_severity >= CQtrConfig::$LOG_SEVERITY["INFO"] ){
            if( defined("QTR_DEBUG") && QTR_DEBUG ){
                $this->_Trim();
                $this->_Log("INFO",$msg);
            } 
        }
    }

    public function Warning( $msg ){
        if( $this->_severity >= CQtrConfig::$LOG_SEVERITY["WARNING"] ){
            $this->_Trim();
            $this->_Log("WARNING",$msg);
        }
    }

    public function Error( $msg ){
        if( $this->_severity >= CQtrConfig::$LOG_SEVERITY["ERROR"] ){
            $this->_Trim();
            $this->_Log("ERROR",$msg);
        }
    }

    public function GetFromLine( $line = 0 ){
        $size   = count( $this->_log_cache );
        $index  = 0;
        for(;$index < $size;$index++){
            if( $this->_log_cache[$index][0] >= $line ){
                break;
            }
        }

        if( $index < $size ){
            $output = array();
            for(;$index < $size;$index++){
                array_push($output,$this->_log_cache[$index]);
            }
            return $output;
        }else{
            return NULL;
        }
    }

    public function GetAllLines(){
        return $this->_log_cache;
    }

    /***************************************************************
     *                  PROTECTED METHODS
     **************************************************************/
    protected function _Trim(){
        if( count( $this->_log_cache ) > $this->_max_lines ){
            while( count( $this->_log_cache ) > $this->_max_lines ){
                array_shift ( $this->_log_cache );
            }
        }
    }

    protected function _Log( $severity, $msg ){
        
        if ( $this->_is_cli ) {
            printf("[%s] %s %s\n",date("h:i:s"),$severity,$msg);
            $this->_WriteLog($severity, $msg);
            return;
        }

        $message = sprintf("[%s] %s",date("h:i:s"),$msg);
        /*
         * Write to log file if log file in use
         */
        $this->_WriteLog($severity, $msg);

        $this->_LoadLog();

        if( count($this->_log_cache ) == 0 ){
            /*
             * log cache empty, adding first line
             */
            array_push( $this->_log_cache, array(0,$severity,$message));
        } else {
            $last = end($this->_log_cache);
            if( !$last ){
                /* 
                 * adding this log line as a first one 
                 */
                array_push( $this->_log_cache, array(0,$severity,$message));
            } else {
                /*
                 * append new log line
                 */
                $index = $last[0] + 1;
                array_push( $this->_log_cache,array($index,$severity,$message));
            }
        }

        $this->_StoreLog();
    }

    protected function _StoreLog()
    {
        $body = CQtrOptions::Serialize( $this->_log_cache );

        if ( CQtrOptions::GetOption( QTR_LOGGER ) !== false ) 
        {
            $rc = CQtrOptions::UpdateOption( QTR_LOGGER, $body );
        }
        else 
        {
            $deprecated = null;
            $autoload = 'no';
            return CQtrOptions::AddOption( QTR_LOGGER, $body ,$deprecated, $autoload );
        }
    }


    protected function _LoadLog()
    {
        $body   = CQtrOptions::GetOption( QTR_LOGGER );
        if( $body )
        {
            $this->_log_cache = CQtrOptions::Unserialize( $body );

            if( !is_array( $this->_log_cache ) ){
                /* 
                 * something gone wrong, reset log 
                 */
                $this->_log_cache = array();
            }

        }
        else
        {
            /*
             * nothing found
             */
            $this->_log_cache = array();
        }

        $this->_Trim();
        return TRUE;
    }

    protected function _OpenLogFile()
    {
        /*
         * open file and move pointer to the end of file
         */
        if(defined("QTR_DEBUG_LOG") && QTR_DEBUG_LOG ){
            $this->_log_file = fopen( $this->_log_file_name, "a+");
            
            // Error handling: check if file opening failed
            /*if( $this->_log_file === false ){
                error_log("QTR Logger: Failed to open log file at " . $this->_log_file_name);
                error_log("QTR Logger: Check directory permissions and disk space");
            }*/
        }else{
            $this->_log_file = null;
        }
        return $this->_log_file;
    }


    protected function _WriteLog( $severity, $msg )
    {
        if( $this->_log_file )
        {
            $rc = fwrite(   $this->_log_file,
                            sprintf("[%s] %s\t%s\n",
                                date("h:i:s"),
                                $severity,
                                $msg));

            fflush($this->_log_file);
            return $rc;
        }
        return 0;
    }

    protected function _ResetLog()
    {
        if( $this->_log_file ){
            fclose($this->_log_file);
            $this->_log_file = NULL;
        }
        /*
         * open file and erase all its content
         */
        @unlink($this->_log_file_name);
        $this->_OpenLogFile();
    }
}

?>
