<?php

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

namespace Icinga\Module\Businessprocess\Forms;

use Icinga\Authentication\Auth;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Module\Businessprocess\Web\Form\BpConfigBaseForm;

class BpConfigForm extends BpConfigBaseForm
{
    protected $deleteButtonName;

    public function setup()
    {
        $this->addElement('text', 'name', array(
            'label' => $this->translate('ID'),
            'required'    => true,
            'validators' => array(
                array(
                    'validator' => 'StringLength',
                    'options' => array(
                        'min' => 2,
                        'max' => 40
                    )
                ),
                [
                    'validator' => 'Regex',
                    'options'   => [
                        'pattern' => '/^[a-zA-Z0-9](?:[\w\h._-]*)?\w$/',
                        'messages'  => [
                            'regexNotMatch' => $this->translate(
                                'Id must only consist of alphanumeric characters.'
                                . ' Underscore at the beginning and space, dot and hyphen at the beginning'
                                . ' and end are not allowed.'
                            )
                        ]
                    ]
                ]
            ),
            'description' => $this->translate(
                'This is the unique identifier of this process'
            ),
        ));

        $this->addElement('text', 'Title', array(
            'label'       => $this->translate('Display Name'),
            'description' => $this->translate(
                'Usually this name will be shown for this process. Equals ID'
                . ' if not given'
            ),
        ));

        $this->addElement('textarea', 'Description', array(
            'label'       => $this->translate('Description'),
            'description' => $this->translate(
                'A slightly more detailed description for this process, about 100-150 characters long'
            ),
            'rows' => 4,
        ));

        if (! empty($this->listAvailableBackends())) {
            $this->addElement('select', 'Backend', array(
                'label'       => $this->translate('Backend'),
                'description' => $this->translate(
                    'Icinga Web Monitoring Backend where current object states for'
                    . ' this process should be retrieved from'
                ),
                'multiOptions' => array(
                        '' => $this->translate('Use the configured default backend'),
                    ) + $this->listAvailableBackends()
            ));
        }

        $this->addElement('select', 'Statetype', array(
            'label'       => $this->translate('State Type'),
            'required'    => true,
            'description' => $this->translate(
                'Whether this process should be based on Icinga hard or soft states'
            ),
            'multiOptions' => array(
                'soft' => $this->translate('Use SOFT states'),
                'hard' => $this->translate('Use HARD states'),
            )
        ));

        $this->addElement('select', 'AddToMenu', array(
            'label'       => $this->translate('Add to menu'),
            'required'    => true,
            'description' => $this->translate(
                'Whether this process should be linked in the main Icinga Web 2 menu'
            ),
            'multiOptions' => array(
                'yes' => $this->translate('Yes'),
                'no'  => $this->translate('No'),
            )
        ));

        $this->addElement('text', 'AllowedUsers', array(
            'label'       => $this->translate('Allowed Users'),
            'description' => $this->translate(
                'Allowed Users (comma-separated)'
            ),
        ));

        $this->addElement('text', 'AllowedGroups', array(
            'label'       => $this->translate('Allowed Groups'),
            'description' => $this->translate(
                'Allowed Groups (comma-separated)'
            ),
        ));

        $this->addElement('text', 'AllowedRoles', array(
            'label'       => $this->translate('Allowed Roles'),
            'description' => $this->translate(
                'Allowed Roles (comma-separated)'
            ),
        ));

        if ($this->bp === null) {
            $this->setSubmitLabel(
                $this->translate('Add')
            );
        } else {
            $config = $this->bp;

            $meta = $config->getMetadata();
            foreach ($meta->getProperties() as $k => $v) {
                if ($el = $this->getElement($k)) {
                    $el->setValue($v);
                }
            }
            $this->getElement('name')
                 ->setValue($config->getName())
                 ->setAttrib('readonly', true);

            $this->setSubmitLabel(
                $this->translate('Store')
            );

            $label = $this->translate('Delete');
            $el = $this->createElement('submit', $label, array(
                'data-base-target' => '_main'
            ))->setLabel($label)->setDecorators(array('ViewHelper'));
            $this->deleteButtonName = $el->getName();
            $this->addElement($el);
        }
    }

    protected function onSetup()
    {
        $this->getElement($this->getSubmitLabel())->setAttrib('data-base-target', '_main');
    }

    protected function onRequest()
    {
        $name = $this->getValue('name');

        if ($this->shouldBeDeleted()) {
            if ($this->bp->isReferenced()) {
                $this->addError(sprintf(
                    $this->translate('Process "%s" cannot be deleted as it has been referenced in other processes'),
                    $name
                ));
            } else {
                $this->bp->clearAppliedChanges();
                $this->storage->deleteProcess($name);
                $this->setSuccessUrl('businessprocess');
                $this->redirectOnSuccess(sprintf($this->translate('Process %s has been deleted'), $name));
            }
        }
    }

    public function onSuccess()
    {
        $name = $this->getValue('name');

        if ($this->bp === null) {
            if ($this->storage->hasProcess($name)) {
                $this->addError(sprintf(
                    $this->translate('A process named "%s" already exists'),
                    $name
                ));

                return;
            }

            // New config
            $config = new BpConfig();
            $config->setName($name);

            if (! $this->prepareMetadata($config)) {
                return;
            }

            $this->setSuccessUrl(
                $this->getSuccessUrl()->setParams(
                    array('config' => $name, 'unlocked' => true)
                )
            );
            $this->setSuccessMessage(sprintf($this->translate('Process %s has been created'), $name));
        } else {
            $config = $this->bp;
            $this->setSuccessMessage(sprintf($this->translate('Process %s has been stored'), $name));
        }
        $meta = $config->getMetadata();
        foreach ($this->getValues() as $key => $value) {
            if (
                ! in_array($key, ['Title', 'Description', 'Backend'], true)
                && ($value === null || $value === '')
            ) {
                continue;
            }

            if ($meta->hasKey($key)) {
                $meta->set($key, $value);
            }
        }

        $this->storage->storeProcess($config);
        $config->clearAppliedChanges();
        parent::onSuccess();
    }

    public function hasDeleteButton()
    {
        return $this->deleteButtonName !== null;
    }

    public function shouldBeDeleted()
    {
        if (! $this->hasDeleteButton()) {
            return false;
        }

        $name = $this->deleteButtonName;
        return $this->getSentValue($name) === $this->getElement($name)->getLabel();
    }
}
