<?php
/**
 * @package Dotclear
 * @subpackage Core
 *
 * @copyright Olivier Meunier & Association Dotclear
 * @copyright GPL-2.0-only
 */
if (!defined('DC_RC_PATH')) {
    return;
}

class dcLog
{
    protected $core;
    protected $con;
    protected $log_table;
    protected $user_table;

    /**
     * Constructs a new instance.
     *
     * @param      dcCore  $core   The core
     */
    public function __construct(dcCore $core)
    {
        $this->core       = &$core;
        $this->con        = &$core->con;
        $this->log_table  = $core->prefix . 'log';
        $this->user_table = $core->prefix . 'user';
    }

    /**
     * Retrieves logs. <b>$params</b> is an array taking the following
     * optionnal parameters:
     *
     * - blog_id: Get logs belonging to given blog ID
     * - user_id: Get logs belonging to given user ID
     * - log_ip: Get logs belonging to given IP address
     * - log_table: Get logs belonging to given log table
     * - order: Order of results (default "ORDER BY log_dt DESC")
     * - limit: Limit parameter
     *
     * @param      array   $params      The parameters
     * @param      bool    $count_only  Count only resultats
     *
     * @return     record  The logs.
     */
    public function getLogs($params = [], $count_only = false)
    {
        $sql = new dcSelectStatement($this->core, 'dcLogGetLogs');

        if ($count_only) {
            $sql->column($sql->count('log_id'));
        } else {
            $sql->columns([
                'L.log_id',
                'L.user_id',
                'L.log_table',
                'L.log_dt',
                'L.log_ip',
                'L.log_msg',
                'L.blog_id',
                'U.user_name',
                'U.user_firstname',
                'U.user_displayname',
                'U.user_url',
            ]);
        }

        $sql->from($this->log_table . ' L');

        if (!$count_only) {
            $sql->join(
                (new dcJoinStatement($this->core, 'dcLogGetLogs'))
                ->type('LEFT')
                ->from($this->user_table . ' U')
                ->on('U.user_id = L.user_id')
                ->statement()
            );
        }

        if (!empty($params['blog_id'])) {
            if ($params['blog_id'] === '*') {
            } else {
                $sql->where('L.blog_id = ' . $sql->quote($params['blog_id']));
            }
        } else {
            $sql->where('L.blog_id = ' . $sql->quote($this->core->blog->id));
        }

        if (!empty($params['user_id'])) {
            $sql->and('L.user_id' . $sql->in($params['user_id']));
        }
        if (!empty($params['log_ip'])) {
            $sql->and('log_ip' . $sql->in($params['log_ip']));
        }
        if (!empty($params['log_table'])) {
            $sql->and('log_table' . $sql->in($params['log_table']));
        }

        if (!$count_only) {
            if (!empty($params['order'])) {
                $sql->order($sql->escape($params['order']));
            } else {
                $sql->order('log_dt DESC');
            }
        }

        if (!empty($params['limit'])) {
            $sql->limit($params['limit']);
        }

        $rs = $sql->select();
        $rs->extend('rsExtLog');

        return $rs;
    }

    /**
     * Creates a new log. Takes a cursor as input and returns the new log ID.
     *
     * @param      cursor  $cur    The current
     *
     * @return     integer
     */
    public function addLog($cur)
    {
        $this->con->writeLock($this->log_table);

        try {
            # Get ID
            $sql = new dcSelectStatement($this->core, 'dcLogAddLog');
            $sql
                ->column($sql->max('log_id'))
                ->from($this->log_table);

            $rs = $sql->select();

            $cur->log_id  = (int) $rs->f(0) + 1;
            $cur->blog_id = (string) $this->core->blog->id;
            $cur->log_dt  = date('Y-m-d H:i:s');

            $this->getLogCursor($cur, $cur->log_id);

            # --BEHAVIOR-- coreBeforeLogCreate
            $this->core->callBehavior('coreBeforeLogCreate', $this, $cur);

            $cur->insert();
            $this->con->unlock();
        } catch (Exception $e) {
            $this->con->unlock();

            throw $e;
        }

        # --BEHAVIOR-- coreAfterLogCreate
        $this->core->callBehavior('coreAfterLogCreate', $this, $cur);

        return $cur->log_id;
    }

    /**
     * Deletes a log.
     *
     * @param      mixed    $id     The identifier
     * @param      bool     $all    Remove all logs
     */
    public function delLogs($id, $all = false)
    {
        if ($all) {
            $sql = new dcTruncateStatement($this->core, 'dcLogDelLogs');
            $sql
                ->from($this->log_table);
        } else {
            $sql = new dcDeleteStatement($this->core, 'dcLogDelLogs');
            $sql
                ->from($this->log_table)
                ->where('log_id ' . $sql->in($id));
        }

        $sql->run();
    }

    /**
     * Gets the log cursor.
     *
     * @param      cursor     $cur     The current
     * @param      mixed      $log_id  The log identifier
     *
     * @throws     Exception
     */
    private function getLogCursor($cur, $log_id = null)
    {
        if ($cur->log_msg === '') {
            throw new Exception(__('No log message'));
        }

        if ($cur->log_table === null) {
            $cur->log_table = 'none';
        }

        if ($cur->user_id === null) {
            $cur->user_id = 'unknown';
        }

        if ($cur->log_dt === '' || $cur->log_dt === null) {
            $cur->log_dt = date('Y-m-d H:i:s');
        }

        if ($cur->log_ip === null) {
            $cur->log_ip = http::realIP();
        }

        $log_id = is_int($log_id) ? $log_id : $cur->log_id;
    }
}

/**
 * Extent log record class.
 */
class rsExtLog
{
    /**
     * Gets the user cn.
     *
     * @param      record  $rs     Invisible parameter
     *
     * @return     string  The user cn.
     */
    public static function getUserCN($rs)
    {
        $user = dcUtils::getUserCN(
            $rs->user_id,
            $rs->user_name,
            $rs->user_firstname,
            $rs->user_displayname
        );

        if ($user === 'unknown') {
            $user = __('unknown');
        }

        return $user;
    }
}
