<?php

/**
 * @file
 * Provides a filtering mechanism to various admin pages.
 */

use Drupal\Core\Render\Element;
use Drupal\Core\Form\FormStateInterface;

/**
 * Implements hook_form_FORM_ID_alter().
 */
function module_filter_form_system_modules_alter(&$form, FormStateInterface $form_state, $form_id) {
  $config = \Drupal::config('module_filter.settings');

  $key = array_search('system/drupal.system.modules', $form['#attached']['library']);
  if ($key !== FALSE) {
    unset($form['#attached']['library'][$key]);
  }
  $form['#attached']['library'][] = $config->get('tabs') ? 'module_filter/modules.tabs' : 'module_filter/modules.bare';
  unset($form['filters']['text']['#description']);
  $form['filters']['text']['#placeholder'] = t('Filter by name');
  if (!empty($_GET['filter'])) {
    $form['filters']['text']['#default_value'] = $_GET['filter'];
  }

  $status_defaults = [
    ((isset($_GET['enabled'])) ? $_GET['enabled'] : 1) ? 'enabled' : '',
    ((isset($_GET['disabled'])) ? $_GET['disabled'] : 1) ? 'disabled' : '',
    ((isset($_GET['unavailable'])) ? $_GET['unavailable'] : 1) ? 'unavailable' : '',
  ];
  $form['filters']['status'] = [
    '#type' => 'container',
    '#attributes' => [
      'class' => [
        'module-filter-status',
      ],
    ],
    'checkboxes' => [
      '#type' => 'checkboxes',
      '#default_value' => array_filter($status_defaults),
      '#options' => [
        'enabled' => t('Enabled'),
        'disabled' => t('Disabled'),
        'unavailable' => t('Unavailable'),
      ],
    ],
  ];

  $state = \Drupal::state();
  $recent = $state->get('module_filter.recent') ?: [];

  // Remove recent items older than a week.
  $recent = array_filter($recent, function ($val) {
    return !($val < REQUEST_TIME - 60 * 60 * 24 * 7);
  });
  $state->set('module_filter.recent', $recent);

  if (!empty($recent)) {
    foreach ($recent as $module => $time) {
      foreach (Element::children($form['modules']) as $package) {
        if (isset($form['modules'][$package][$module])) {
          $form['modules'][$package][$module]['#attributes']['class'][] = 'recent';
          break;
        }
      }
    }
  }

  $modules = system_rebuild_module_data();

  foreach ($modules as $name => $module) {
    if ($name == 'module_filter') {
      $ctime = filectime($module->getPathname());
      if (($ctime - strtotime('-1 week')) > 0) {
        foreach (Element::children($form['modules']) as $package) {
          if (isset($form['modules'][$package][$name])) {
            $form['modules'][$package][$name]['#attributes']['class'][] = 'new';
            break;
          }
        }
      }
    }
  }

  $form['#submit'][] = 'module_filter_system_modules_recent_enabled_submit';
  $form['#submit'][] = 'module_filter_system_modules_redirect_submit';
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function module_filter_form_system_modules_confirm_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['filters']['text'] = [
    '#type' => 'value',
    '#value' => isset($_GET['filter']) ? $_GET['filter'] : '',
  ];
  $form['#submit'][] = 'module_filter_system_modules_redirect_submit';
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function module_filter_form_system_modules_uninstall_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  $key = array_search('system/drupal.system.modules', $form['#attached']['library']);
  if ($key !== FALSE) {
    unset($form['#attached']['library'][$key]);
  }
  $form['#attached']['library'][] = 'module_filter/modules.uninstall';
  unset($form['filters']['text']['#description']);
  $form['filters']['text']['#placeholder'] = t('Filter by name');
  if (!empty($_GET['filter'])) {
    $form['filters']['text']['#default_value'] = $_GET['filter'];
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function module_filter_form_user_admin_permissions_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  $form['filters'] = [
    '#type' => 'container',
    '#attributes' => [
      'class' => ['table-filter', 'js-show'],
    ],
  ];
  $form['filters']['text'] = [
    '#type' => 'search',
    '#title' => t('Filter modules'),
    '#title_display' => 'invisible',
    '#size' => 30,
    '#placeholder' => t('Filter by name'),
    '#attributes' => [
      'class' => ['table-filter-text'],
      'data-table' => '#permissions',
      'autocomplete' => 'off',
    ],
    '#weight' => -1000,
  ];
  if (!empty($_GET['filter'])) {
    $form['filters']['text']['#default_value'] = $_GET['filter'];
  }
  $form['#attached']['library'][] = 'module_filter/permissions';
}

/**
 * Implements hook_theme_registry_alter().
 */
function module_filter_theme_registry_alter(&$theme_registry) {
  // We need to alter the system-modules-details template so we can add
  // applicable requires and required-by classes.
  $theme_registry['system_modules_details']['path'] = drupal_get_path('module', 'module_filter') . '/templates';
}

/**
 * Implements hook_preprocess_HOOK().
 */
function module_filter_preprocess_system_modules_details(&$variables) {
}

/**
 * Form submit callback to track recently enabled modules.
 */
function module_filter_system_modules_recent_enabled_submit($form, FormStateInterface $form_state) {
  $state = \Drupal::state();
  $recent = $state->get('module_filter.recent') ?: [];

  // Drupal 8.3.0 simplified the module form structure which requires checking
  // the version of Drupal and building the $modules array accordingly.
  // @see https://www.drupal.org/node/2851653
  $modules = [];
  if (version_compare(\DRUPAL::VERSION, '8.3.0', '<')) {
    foreach ($form_state->getValue('modules') as $package) {
      $modules += $package;
    }
  }
  else {
    $modules = $form_state->getValue('modules');
  }

  foreach (Element::children($form['modules']) as $package) {
    foreach ($modules as $module => $details) {
      if (isset($form['modules'][$package][$module]) && $form['modules'][$package][$module]['enable']['#default_value'] != $details['enable']) {
        $recent[$module] = REQUEST_TIME;
      }
    }
  }

  $state->set('module_filter.recent', $recent);
}

/**
 * Form submit callback for remembering the filter value.
 */
function module_filter_system_modules_redirect_submit($form, FormStateInterface $form_state) {
  if ($text = $form_state->getValue('text')) {
    /** @var \Drupal\Core\Url $redirect */
    $route_name = ($redirect = $form_state->getRedirect()) ? $redirect->getRouteName() : 'system.modules_list';
    $form_state->setRedirect($route_name, ['filter' => $text]);
  }
}
