<?php

namespace Drupal\locale\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\locale\StringStorageInterface;
use Drupal\Core\State\StateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Defines the locale user interface translation form base.
 *
 * Provides methods for searching and filtering strings.
 */
abstract class TranslateFormBase extends FormBase {

  /**
   * The locale storage.
   *
   * @var \Drupal\locale\StringStorageInterface
   */
  protected $localeStorage;

  /**
   * The state store.
   *
   * @var \Drupal\Core\State\StateInterface
   */
  protected $state;

  /**
   * The language manager.
   *
   * @var \Drupal\Core\Language\LanguageManagerInterface
   */
  protected $languageManager;

  /*
   * Filter values. Shared between objects that inherit this class.
   *
   * @var array|null
   */
  protected static $filterValues;

  /**
   * Constructs a new TranslationFormBase object.
   *
   * @param \Drupal\locale\StringStorageInterface $locale_storage
   *   The locale storage.
   * @param \Drupal\Core\State\StateInterface $state
   *   The state service.
   * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
   *   The language manager.
   */
  public function __construct(StringStorageInterface $locale_storage, StateInterface $state, LanguageManagerInterface $language_manager) {
    $this->localeStorage = $locale_storage;
    $this->state = $state;
    $this->languageManager = $language_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('locale.storage'),
      $container->get('state'),
      $container->get('language_manager')
    );
  }

  /**
   * Builds a string search query and returns an array of string objects.
   *
   * @return \Drupal\locale\TranslationString[]
   *   Array of \Drupal\locale\TranslationString objects.
   */
  protected function translateFilterLoadStrings() {
    $filter_values = $this->translateFilterValues();

    // Language is sanitized to be one of the possible options in
    // translateFilterValues().
    $conditions = ['language' => $filter_values['langcode']];
    $options = ['pager limit' => 30, 'translated' => TRUE, 'untranslated' => TRUE];

    // Add translation status conditions and options.
    switch ($filter_values['translation']) {
      case 'translated':
        $conditions['translated'] = TRUE;
        if ($filter_values['customized'] != 'all') {
          $conditions['customized'] = $filter_values['customized'];
        }
        break;

      case 'untranslated':
        $conditions['translated'] = FALSE;
        break;

    }

    if (!empty($filter_values['string'])) {
      $options['filters']['source'] = $filter_values['string'];
      if ($options['translated']) {
        $options['filters']['translation'] = $filter_values['string'];
      }
    }

    return $this->localeStorage->getTranslations($conditions, $options);
  }

  /**
   * Builds an array out of search criteria specified in request variables.
   *
   * @param bool $reset
   *   If the list of values should be reset.
   *
   * @return array
   *   The filter values.
   */
  protected function translateFilterValues($reset = FALSE) {
    if (!$reset && static::$filterValues) {
      return static::$filterValues;
    }

    $filter_values = [];
    $filters = $this->translateFilters();
    foreach ($filters as $key => $filter) {
      $filter_values[$key] = $filter['default'];
      // Let the filter defaults be overwritten by parameters in the URL.
      if ($this->getRequest()->query->has($key)) {
        // Only allow this value if it was among the options, or
        // if there were no fixed options to filter for.
        $value = $this->getRequest()->query->get($key);
        if (!isset($filter['options']) || isset($filter['options'][$value])) {
          $filter_values[$key] = $value;
        }
      }
      elseif (isset($_SESSION['locale_translate_filter'][$key])) {
        // Only allow this value if it was among the options, or
        // if there were no fixed options to filter for.
        if (!isset($filter['options']) || isset($filter['options'][$_SESSION['locale_translate_filter'][$key]])) {
          $filter_values[$key] = $_SESSION['locale_translate_filter'][$key];
        }
      }
    }

    return static::$filterValues = $filter_values;
  }

  /**
   * Lists locale translation filters that can be applied.
   */
  protected function translateFilters() {
    $filters = [];

    // Get all languages, except English.
    $this->languageManager->reset();
    $languages = $this->languageManager->getLanguages();
    $language_options = [];
    foreach ($languages as $langcode => $language) {
      if (locale_is_translatable($langcode)) {
        $language_options[$langcode] = $language->getName();
      }
    }

    // Pick the current interface language code for the filter.
    $default_langcode = $this->languageManager->getCurrentLanguage()->getId();
    if (!isset($language_options[$default_langcode])) {
      $available_langcodes = array_keys($language_options);
      $default_langcode = array_shift($available_langcodes);
    }

    $filters['string'] = [
      'title' => $this->t('String contains'),
      'description' => $this->t('Leave blank to show all strings. The search is case sensitive.'),
      'default' => '',
    ];

    $filters['langcode'] = [
      'title' => $this->t('Translation language'),
      'options' => $language_options,
      'default' => $default_langcode,
    ];

    $filters['translation'] = [
      'title' => $this->t('Search in'),
      'options' => [
        'all' => $this->t('Both translated and untranslated strings'),
        'translated' => $this->t('Only translated strings'),
        'untranslated' => $this->t('Only untranslated strings'),
      ],
      'default' => 'all',
    ];

    $filters['customized'] = [
      'title' => $this->t('Translation type'),
      'options' => [
        'all' => $this->t('All'),
        LOCALE_NOT_CUSTOMIZED => $this->t('Non-customized translation'),
        LOCALE_CUSTOMIZED => $this->t('Customized translation'),
      ],
      'states' => [
        'visible' => [
          ':input[name=translation]' => ['value' => 'translated'],
        ],
      ],
      'default' => 'all',
    ];

    return $filters;
  }

}
