<?php
/**
 * @link https://craftcms.com/
 * @copyright Copyright (c) Pixel & Tonic, Inc.
 * @license https://craftcms.github.io/license/
 */

namespace craft\base;

use craft\events\DefineValueEvent;
use craft\helpers\DateTimeHelper;

/**
 * Component is the base class for classes representing Craft components that are configurable.
 *
 * @author Pixel & Tonic, Inc. <support@pixelandtonic.com>
 * @since 3.5.0
 */
abstract class ConfigurableComponent extends Component implements ConfigurableComponentInterface
{
    /**
     * @event DefineValueEvent The event that is triggered when defining the component’s settings attributes, as returned by [[settingsAttributes()]].
     * @since 3.7.0
     */
    const EVENT_DEFINE_SETTINGS_ATTRIBUTES = 'defineSettingsAttributes';

    /**
     * @inheritdoc
     */
    public function settingsAttributes(): array
    {
        // By default, include all public, non-static properties that were not defined in an abstract class
        $class = new \ReflectionClass($this);
        $names = [];

        foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC) as $property) {
            if (!$property->isStatic() && !$property->getDeclaringClass()->isAbstract()) {
                $names[] = $property->getName();
            }
        }

        if ($this->hasEventHandlers(self::EVENT_DEFINE_SETTINGS_ATTRIBUTES)) {
            $event = new DefineValueEvent([
                'value' => $names,
            ]);
            $this->trigger(self::EVENT_DEFINE_SETTINGS_ATTRIBUTES, $event);
            $names = $event->value;
        }

        return $names;
    }

    /**
     * @inheritdoc
     */
    public function getSettings(): array
    {
        $settings = [];
        $datetimeAttributes = array_flip($this->datetimeAttributes());

        foreach ($this->settingsAttributes() as $attribute) {
            if (isset($datetimeAttributes[$attribute])) {
                $settings[$attribute] = DateTimeHelper::toIso8601($this->$attribute) ?: null;
            } else {
                $settings[$attribute] = $this->$attribute;
            }
        }

        return $settings;
    }

    /**
     * @inheritdoc
     */
    public function getSettingsHtml()
    {
        return null;
    }
}
