<?php

// SPDX-FileCopyrightText: 2018 Icinga GmbH <https://icinga.com>
// SPDX-License-Identifier: GPL-3.0-or-later

namespace Icinga\Module\Businessprocess\Storage;

use DirectoryIterator;
use Icinga\Application\Hook\AuditHook;
use Icinga\Application\Icinga;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Exception\SystemPermissionException;

class LegacyStorage extends Storage
{
    /**
     * All parsed configurations
     *
     * @var BpConfig[]
     */
    protected $configs = [];

    /** @var string */
    protected $configDir;

    public function getConfigDir()
    {
        if ($this->configDir === null) {
            $this->prepareDefaultConfigDir();
        }

        return $this->configDir;
    }

    protected function prepareDefaultConfigDir()
    {
        $dir = Icinga::app()
            ->getModuleManager()
            ->getModule('businessprocess')
            ->getConfigDir();

        // TODO: This is silly. We need Config::requireDirectory().
        if (! is_dir($dir)) {
            if (! is_dir(dirname($dir))) {
                if (! @mkdir(dirname($dir))) {
                    throw new SystemPermissionException('Could not create config directory "%s"', dirname($dir));
                }
            }
            if (! mkdir($dir)) {
                throw new SystemPermissionException('Could not create config directory "%s"', $dir);
            }
        }
        $dir = $dir . '/processes';
        if (! is_dir($dir)) {
            if (! mkdir($dir)) {
                throw new SystemPermissionException('Could not create config directory "%s"', $dir);
            }
        }

        $this->configDir = $dir;
    }

    /**
     * @inheritdoc
     */
    public function listProcesses()
    {
        $files = array();

        foreach ($this->listAllProcessNames() as $name) {
            $meta = $this->loadMetadata($name);
            if (! $meta->canRead()) {
                continue;
            }

            $files[$name] = $meta->getExtendedTitle();
        }

        return $files;
    }

    /**
     * @inheritdoc
     */
    public function listProcessNames()
    {
        $files = array();

        foreach ($this->listAllProcessNames() as $name) {
            $meta = $this->loadMetadata($name);
            if (! $meta->canRead()) {
                continue;
            }

            $files[$name] = $name;
        }

        return $files;
    }

    /**
     * @inheritdoc
     */
    public function listAllProcessNames()
    {
        $files = array();

        foreach (new DirectoryIterator($this->getConfigDir()) as $file) {
            if ($file->isDot()) {
                continue;
            }

            $filename = $file->getFilename();
            if (substr($filename, -5) === '.conf') {
                $files[] = substr($filename, 0, -5);
            }
        }

        natcasesort($files);
        return $files;
    }

    /**
     * @inheritdoc
     */
    public function loadProcess($name)
    {
        if (! isset($this->configs[$name])) {
            $this->configs[$name] = LegacyConfigParser::parseFile(
                $name,
                $this->getFilename($name)
            );
        }

        return $this->configs[$name];
    }

    /**
     * @inheritdoc
     */
    public function storeProcess(BpConfig $process)
    {
        AuditHook::logActivity('businessprocess/store', "Business Process \"{$process->getName()}\" stored");
        file_put_contents(
            $this->getFilename($process->getName()),
            LegacyConfigRenderer::renderConfig($process)
        );
    }

    /**
     * @inheritdoc
     */
    public function deleteProcess($name)
    {
        AuditHook::logActivity('businessprocess/delete', "Business Process \"{$name}\" deleted");
        return @unlink($this->getFilename($name));
    }

    /**
     * @inheritdoc
     */
    public function loadMetadata($name)
    {
        if (isset($this->configs[$name])) {
            return $this->configs[$name]->getMetadata();
        }

        return LegacyConfigParser::readMetadataFromFileHeader(
            $name,
            $this->getFilename($name)
        );
    }

    public function getSource($name)
    {
        return file_get_contents($this->getFilename($name));
    }

    public function getFilename($name)
    {
        return $this->getConfigDir() . '/' . $name . '.conf';
    }

    /**
     * @param $name
     * @param $string
     *
     * @return BpConfig
     */
    public function loadFromString($name, $string)
    {
        return LegacyConfigParser::parseString($name, $string);
    }

    /**
     * @param $name
     * @return bool
     */
    public function hasProcess($name)
    {
        $file = $this->getFilename($name);
        if (! is_file($file)) {
            return false;
        }

        return $this->loadMetadata($name)->canRead();
    }
}
