<?php
/**
 * Created by PhpStorm.
 * User: crose
 * Date: 2/18/16
 * Time: 5:30 PM
 */

namespace IMATHUZH\Qfq\Core\Helper;


/**
 * Class Logger
 * @package qfq
 */
class Logger {

    /**
     * Append $msg to $filename. Create the file it it not exist.
     *
     * @param $msg
     * @param string $pathFileNameAbsoluteOrRelToApp Log file path (either absolute path or relative to app directory)
     * @param string $mode
     * @param int $currentLevel Log only messages with $currentLevel>=$minLevel
     * @param int $minLevel
     * @param bool $recursion
     * @throws \CodeException
     * @throws \UserFormException
     */
    public static function logMessage($msg, $pathFileNameAbsoluteOrRelToApp, $mode = FILE_MODE_APPEND, int $currentLevel = 0, int $minLevel = 0, $recursion = false) {

        $handle = false;

        if ($pathFileNameAbsoluteOrRelToApp == '' || $currentLevel < $minLevel) {
            return;
        }

        $absolutePathFileName = Path::joinIfNotAbsolute(Path::absoluteApp(), $pathFileNameAbsoluteOrRelToApp);

        try {
            $handle = fopen($absolutePathFileName, $mode);
        } catch (\Exception $e) {
            $dummy = 1;
        }

        $cwd1 = getcwd();

        if ($handle === false) {

            if ($recursion) {
                throw new \UserFormException(
                    json_encode([ERROR_MESSAGE_TO_USER => 'Error: cannot open file',
                        ERROR_MESSAGE_TO_DEVELOPER => "Error - cannot open. File: " . $absolutePathFileName .
                            " ( CWD: " . getcwd() . ") - " . HelperFile::errorGetLastAsString()]),
                    ERROR_IO_OPEN);
            }

            // If open fails, maybe the directory does not exist. Create it:
            HelperFile::mkDirParent($absolutePathFileName);
            self::logMessage($msg, $absolutePathFileName, $mode, $currentLevel, $minLevel, true);
            return;
        }

        if (fwrite($handle, $msg . PHP_EOL) === false) {
            throw new \UserFormException(
                json_encode([ERROR_MESSAGE_TO_USER => 'Error: cannot write file',
                    ERROR_MESSAGE_TO_DEVELOPER => "Error - cannot open. File: " . $absolutePathFileName .
                        " ( CWD: " . getcwd() . ") - " . HelperFile::errorGetLastAsString()]),
                ERROR_IO_WRITE);
        }

        fclose($handle);
    }

    /**
     * Prefix every message with linePre().
     *
     * @param $msg
     * @param $filename
     * @param string $mode
     * @throws \CodeException
     * @throws \UserFormException
     */
    public static function logMessageWithPrefix($msg, $filename, $mode = FILE_MODE_APPEND) {
        self::logMessage(self::linePre() . $msg, $filename, $mode);
    }

    /**
     * Returns a timestamp prefix '[Y.m.d H:i:s O] ' - same format as the sql.log timestamp.
     * For logs written from CLI/daemon context (e.g. imap.log) where IP/cookie of linePre()
     * are meaningless.
     *
     * @return string
     */
    public static function linePreTimestamp(): string {
        return '[' . date('Y.m.d H:i:s O') . '] ';
    }

    /**
     * Returns a timestamp, IP, cookie.
     *
     * @return string
     */
    public static function linePre() {

        $cookie = isset($_COOKIE[SESSION_NAME]) ? $_COOKIE[SESSION_NAME] : '<no session cookie>';

        $str = '[' . date('Y-m-d H:i:s');
        $str .= ' / ' . htmlentities(empty($_SERVER['REMOTE_ADDR']) ? '<no ip>' : $_SERVER['REMOTE_ADDR']);
//        $str .= ' / ' . htmlentities(empty($_SERVER['HTTP_USER_AGENT']) ? '<no user agent>' : $_SERVER['HTTP_USER_AGENT']);
        $str .= ' / ' . htmlentities($cookie);


        $str .= '] ';

        return $str;
    }

    /**
     * Format details of a FormElement.
     *
     * @param array $fe
     * @return string
     */
    public static function formatFormElementName(array $fe) {

        return ($fe['id'] ?? '') . ' / ' . ($fe[FE_NAME] ?? '') . ' / ' . ($fe[FE_LABEL] ?? '');
    }

    /**
     * Logs a line to all of the given logfiles.
     * If $data is an array, it will be json encoded.
     *
     * @param array $form
     * @param $pre
     * @param $data
     * @param bool $flagNewLineFirst
     * @throws \CodeException
     * @throws \UserFormException
     */
    public static function logFormLine(array $form, $pre, $data, $flagNewLineFirst = false) {

        $line = (is_array($data)) ? json_encode($data) : $data;
        $line = '[' . $pre . '] ' . $line;

        if ($flagNewLineFirst) {
            $line = PHP_EOL . $line;
        }

        foreach ([FORM_LOG_FILE_ALL, FORM_LOG_FILE_SESSION] as $filename) {
            if (!empty($form[$filename])) {
                Logger::logMessage($line, Path::absoluteApp($form[$filename]));
            }
        }
    }

    public static function nameToLevel(string $logLevelName) {
        switch ($logLevelName) {
            case 'none':
                return LOG_LEVEL_NONE;
                break;
            case 'debug':
                return LOG_LEVEL_DEBUG;
                break;
            case 'all':
                return LOG_LEVEL_ALL;
                break;
            case 'modify':
                return LOG_LEVEL_MODIFY;
                break;
            case 'error':
                return LOG_LEVEL_ERROR;
                break;
            default:  throw new \UserFormException(
                json_encode([ERROR_MESSAGE_TO_USER => 'Error: undefined loglevel "' . $logLevelName . '"',
                    ERROR_MESSAGE_TO_DEVELOPER => ""]),
                ERROR_UNEXPECTED_TYPE);
        }
    }
}