<?php

namespace Drupal\webform\Plugin\WebformElement;

use Drupal\Core\Form\FormStateInterface;
use Drupal\webform\WebformSubmissionInterface;

/**
 * Provides a 'select' element.
 *
 * @WebformElement(
 *   id = "select",
 *   api = "https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Render!Element!Select.php/class/Select",
 *   label = @Translation("Select"),
 *   description = @Translation("Provides a form element for a drop-down menu or scrolling selection box."),
 *   category = @Translation("Options elements"),
 * )
 */
class Select extends OptionsBase {

  /**
   * {@inheritdoc}
   */
  public function getDefaultProperties() {
    return [
      // Options settings.
      'multiple' => FALSE,
      'multiple_error' => '',
      'empty_option' => '',
      'empty_value' => '',
      'select2' => FALSE,
      'chosen' => FALSE,
      'placeholder' => '',
    ] + parent::getDefaultProperties();
  }

  /**
   * {@inheritdoc}
   */
  public function supportsMultipleValues() {
    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  public function prepare(array &$element, WebformSubmissionInterface $webform_submission = NULL) {
    $config = $this->configFactory->get('webform.settings');

    // Always include empty option.
    // Note: #multiple select menu does support empty options.
    // @see \Drupal\Core\Render\Element\Select::processSelect
    if (!isset($element['#empty_option']) && empty($element['#multiple'])) {
      $required = isset($element['#states']['required']) ? TRUE : !empty($element['#required']);
      $empty_option = $required
        ? ($config->get('element.default_empty_option_required') ?: $this->t('- Select -'))
        : ($config->get('element.default_empty_option_optional') ?: $this->t('- None -'));
      if ($config->get('element.default_empty_option')) {
        $element['#empty_option'] = $empty_option;
      }
      // Copied from: \Drupal\Core\Render\Element\Select::processSelect.
      elseif (($required && !isset($element['#default_value'])) || isset($element['#empty_value'])) {
        $element['#empty_option'] = $empty_option;
      }
    }

    if (!empty($element['#multiple'])) {
      $element['#element_validate'][] = [get_class($this), 'validateMultipleOptions'];
    }

    // If select2 or chosen is not available, see if we can use the alternative.
    if (isset($element['#select2'])
      && !$this->librariesManager->isIncluded('jquery.select2')
      && $this->librariesManager->isIncluded('jquery.chosen')) {
      $element['#chosen'] = TRUE;
    }
    elseif (isset($element['#chosen'])
      && !$this->librariesManager->isIncluded('jquery.chosen')
      && $this->librariesManager->isIncluded('jquery.select2')) {
      $element['#select2'] = TRUE;
    }

    // Enhance select element using select2 or chosen.
    if (isset($element['#select2']) && $this->librariesManager->isIncluded('jquery.select2')) {
      $element['#attached']['library'][] = 'webform/webform.element.select2';
      $element['#attributes']['class'][] = 'js-webform-select2';
      $element['#attributes']['class'][] = 'webform-select2';
    }
    elseif (isset($element['#chosen']) && $this->librariesManager->isIncluded('jquery.chosen')) {
      $element['#attached']['library'][] = 'webform/webform.element.chosen';
      $element['#attributes']['class'][] = 'js-webform-chosen';
      $element['#attributes']['class'][] = 'webform-chosen';
    }

    // Set placeholder as data attributes for select2 or chosen elements.
    if (!empty($element['#placeholder'])) {
      $element['#attributes']['data-placeholder'] = $element['#placeholder'];
    }

    parent::prepare($element, $webform_submission);
  }

  /**
   * {@inheritdoc}
   */
  public function form(array $form, FormStateInterface $form_state) {
    $form = parent::form($form, $form_state);

    // Select2 and/or Chosen enhancements.
    // @see \Drupal\webform\Plugin\WebformElement\WebformCompositeBase::form
    $form['options']['select2'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Select2'),
      '#description' => $this->t('Replace select element with jQuery <a href=":href">Select2</a> box.', [':href' => 'https://select2.github.io/']),
      '#return_value' => TRUE,
      '#states' => [
        'disabled' => [
          ':input[name="properties[chosen]"]' => ['checked' => TRUE],
        ],
      ],
    ];
    if ($this->librariesManager->isExcluded('jquery.select2')) {
      $form['options']['select2']['#access'] = FALSE;
    }
    $form['options']['chosen'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Chosen'),
      '#description' => $this->t('Replace select element with jQuery <a href=":href">Chosen</a> box.', [':href' => 'https://harvesthq.github.io/chosen/']),
      '#return_value' => TRUE,
      '#states' => [
        'disabled' => [
          ':input[name="properties[select2]"]' => ['checked' => TRUE],
        ],
      ],
    ];
    if ($this->librariesManager->isExcluded('jquery.chosen')) {
      $form['options']['chosen']['#access'] = FALSE;
    }
    if ($this->librariesManager->isIncluded('jquery.select2') && $this->librariesManager->isIncluded('jquery.chosen')) {
      $form['options']['select_message'] = [
        '#type' => 'webform_message',
        '#message_type' => 'warning',
        '#message_message' => $this->t('Select2 and Chosen provide very similar functionality, only one should be enabled.'),
        '#access' => TRUE,
      ];
    }

    // Add states to placeholder if custom library is supported and the
    // select menu supports multiple values.
    $placeholder_states = [];
    if (!$this->librariesManager->isExcluded('jquery.select2')) {
      $placeholder_states[] = [':input[name="properties[select2]"]' => ['checked' => TRUE]];
    }
    if (!$this->librariesManager->isExcluded('jquery.chosen')) {
      if (isset($form['form']['placeholder']['#states']['visible'])) {
        $placeholder_states[] = 'or';
      }
      $placeholder_states[] = [':input[name="properties[chosen]"]' => ['checked' => TRUE]];
    }
    if ($placeholder_states) {
      $form['form']['placeholder']['#states']['visible'] = [
        [
        ':input[name="properties[multiple][container][cardinality]"]' => ['value' => 'number'],
        ':input[name="properties[multiple][container][cardinality_number]"]' => ['!value' => 1],
        ],
        $placeholder_states,
      ];
    }
    else {
      $form['form']['placeholder']['#access'] = FALSE;
    }

    return $form;
  }

}
