<?php

namespace Axioma\Server;

use Axioma\Utils as utils;

trait AppConfig
{
    private $root;
    private $ini;
    private $default_log_path;
    private $app_config;

    private function initAppConfig()
    {
        $this->root = '..' . DIRECTORY_SEPARATOR . 'app';
        $this->ini = 'axioma-lm.ini';
        $this->default_log_path = 'log' . DIRECTORY_SEPARATOR . 'axioma-lm.log';
        $this->app_config = array();
    }

    private function loadAppConfig()
    {
        $inipath = $this->iniPath();
        if (file_exists($inipath) && is_file($inipath)) {
            $this->app_config = parse_ini_file($inipath, true);
        }
    }

    public function saveAppConfig(&$error = null)
    {
        $error = '';
        if (!$this->checkIni($error)) {
            return false;
        }
        if (empty($this->app_config)) {
            return true;
        }

        $new_content = '';
        foreach ($this->app_config as $section => $section_content) {
            $section_content = array_map(function ($value, $key) {
                return "$key=$value";
            }, array_values($section_content), array_keys($section_content));
            $section_content = implode("\n", $section_content);
            $new_content .= "[$section]\n$section_content\n";
        }
        if (!file_put_contents($this->iniPath(), $new_content)) {
            $error = _('Ошибка записи файла ') . '"' . $this->iniPath() . '"';
            return false;
        }
        return $this->checkIni($error);
    }

    private function getValue($key, $default = null)
    {
        $keys = explode('/', $key);
        if (isset($this->app_config[$keys[0]]) && isset($this->app_config[$keys[0]][$keys[1]])) {
            return $this->app_config[$keys[0]][$keys[1]];
        }
        return $default;
    }

    public function rootDir($absolute = true)
    {
        return $absolute ? utils::fixTailSeparator(utils::makeAbsolutePath($this->root)) : $this->root;
    }

    public function checkRoot(&$error = null)
    {
        $error = '';
        if (!file_exists($this->rootDir()) || !is_dir($this->rootDir())) {
            $error =
                !file_exists($this->rootDir()) ? sprintf(_("Каталог '%s' не существует"), $this->rootDir())
                : _('Необходимо указать путь к каталогу приложения');
            return false;
        }
        if (!is_writable($this->rootDir())) {
            $error = sprintf(
                _("Необходимо открыть доступ на запись к каталогу '%s' для пользователя '%s'"),
                $this->rootDir(),
                utils::getRunningUser()
            );
        }
        return true;
    }

    public function exePath($absolute = true)
    {
        $filename = 'axioma-lm' . (utils::isWindows() ? '.exe' : '');
        return $absolute ? $this->rootDir() . $filename : $filename;
    }

    public function checkExe(&$error = null)
    {
        if (!$this->checkRoot($error)) {
            return false;
        }
        $path = $this->exePath();
        if (!file_exists($path) || !is_file($path) || !is_executable($path)) {
            $error = !file_exists($path)
                ? _('Не найден файл приложения')
                : (!is_file($path)
                    ? sprintf(_("Объект '%s' не является файлом"), $this->exePath())
                    : _('Файл приложения не является исполняемым'));
            return false;
        }
        return true;
    }

    public function iniPath($absolute = true)
    {
        return utils::isAbsolutePath($this->ini) || !$absolute ?
            $this->ini : utils::makeAbsolutePath($this->ini, $this->rootDir());
    }

    public function checkIni(&$error = null)
    {
        if (!$this->checkRoot($error)) {
            return false;
        }
        $path = $this->iniPath();
        if (!file_exists($path)) {
            $error = _('Файл настроек приложения не существует, используются параметры по умолчанию');
            return true;
        }
        if (!is_file($path)) {
            $error = sprintf(_("Объект '%s' не является файлом"), $this->iniPath());
            return false;
        }
        if (!is_writable($path)) {
            $error = sprintf(
                _("Необходимо открыть доступ на запись к файлу '%s' для пользователя '%s'"),
                $this->iniPath(),
                utils::getRunningUser()
            );
            return false;
        }
        return true;
    }

    public function logPath($absolute = true)
    {
        $log_path = $this->default_log_path;
        if (isset($this->app_config['log']) && isset($this->app_config['log']['logfile'])) {
            $log_path = $this->app_config['log']['logfile'];
            if (empty($log_path)) {
                return null;
            }
        }
        return utils::isAbsolutePath($log_path) || !$absolute ?
            $log_path : utils::makeAbsolutePath($log_path, $this->rootDir());
    }

    public function appPort()
    {
        return $this->getValue('server/port', 13000);
    }

    private function appLocale()
    {
        $lang = $this->getValue('core/language', \Axioma\Lang::serverLanguage());
        return $lang . '.utf-8';
    }

    private function setLogPath($path)
    {
        if (!empty($path)) {
            $this->app_config['log']['logfile'] = $path;
        }
    }

    private function setAppPort($port)
    {
        $this->app_config['server']['port'] = $port;
    }

    public function licensePath($absolute = true)
    {
        $path = $this->getValue('license/keyfile', 'axioma-lm.lic');
        return utils::isAbsolutePath($path) || !$absolute ? $path : utils::makeAbsolutePath($path, $this->rootDir());
    }

    private function setLicensePath($path)
    {
        $this->app_config['license']['keyfile'] = $path;
    }

    public function checkLicense(&$error = null)
    {
        if (!$this->checkRoot($error)) {
            return false;
        }
        $path = $this->licensePath();
        if (!file_exists($path)) {
            $error = _('Файл лицензии не найден');
            return false;
        }
        if (!is_file($path)) {
            $error = sprintf(_("Объект '%s' не является файлом"), $this->licensePath());
            return false;
        }
        return true;
    }

    public function checkLicenseCreateAccess(&$error = null)
    {
        if (!$this->checkRoot($error)) {
            return false;
        }
        $path = $this->licensePath();
        if (!file_exists($path)) {
            return true;
        }
        if (!is_file($path)) {
            $error = _('Указанный объект существует и не является файлом');
            return false;
        }
        if (!is_writable($path)) {
            $error = _('Файл уже существует и не может быть перезаписан');
            return false;
        }
        $error = _('Файл уже существует');
        return true;
    }

    public function serialNumber()
    {
        return $this->getValue('license/serial', '');
    }

    public function setSerialNumber($serial)
    {
        $this->app_config['license']['serial'] = $serial;
    }

    public function checkSerialNumber(&$error = null)
    {
        $serial = $this->serialNumber();
        if (empty($serial)) {
            $error = _('Серийный номер не может быть пустым');
            return false;
        }
        $pattern = '/^AL' . substr(self::version(), 0, 1) . '\w{2}(?:-\w{5}){3}$/';
        $result = preg_match($pattern, $serial);
        if ($result !== 1) {
            $error = _('Неправильный формат серийного номера');
            return false;
        }
        return true;
    }

    public function company()
    {
        return $this->getValue('license/company_name', '');
    }

    public function setCompany($name)
    {
        $this->app_config['license']['company_name'] = $name;
    }

    public function checkCompanyName(&$error = null)
    {
        $name = $this->company();
        if (empty($name)) {
            $error = _('Название компании не может быть пустым');
            return false;
        }
        return true;
    }

    public function databasePath($absolute = true)
    {
        $path = $this->getValue('core/dbfile', 'axioma-lm.sqlite');
        return utils::isAbsolutePath($path) || !$absolute ? $path : utils::makeAbsolutePath($path, $this->rootDir());
    }

    public function checkDatabasePath(&$error = null)
    {
        $path = $this->databasePath(true);
        if (empty($path)) {
            $error = _('Не указан путь к базе данных');
            return false;
        }
        if (!file_exists($path)) {
            $error = _('Файл базы данных не существует');
            return false;
        }
        if (!is_file($path)) {
            $error = sprintf(_("Указанный путь ('%s') существует и не является файлом"), $path);
            return false;
        }
        return true;
    }
}
