<?php

/**
 * @file
 * Textimage - Provides text to image manipulations.
 */

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\StreamWrapper\StreamWrapperInterface;
use Drupal\Core\Template\Attribute;
use Drupal\Core\Url;
use Drupal\image\ImageStyleInterface;

/**
 * Implements hook_help().
 */
function textimage_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    case 'textimage.settings':
      $output = '<p>';
      $output .= t('Textimage provides integration with the <a href="@image_effects_url">Image effects</a> module to generate images with overlaid text.', ['@image_effects_url' => 'https://www.drupal.org/project/image_effects']);
      $output .= ' ' . t('Use <a href="@image">Image styles</a> features to create Image styles. The \'Text overlay\' image effect must be used to specifiy the text appearance on the generated image.', ['@image' => Url::fromRoute('entity.image_style.collection')->toString()]);
      $output .= ' ' . t('On the edit image style form, a "Textimage options" section allows selecting Textimage-specific options for the style.');
      $output .= '</p>';
      return $output;

  }
}

/**
 * Implements hook_theme().
 */
function textimage_theme() {
  $theme = [
    // Format a textimage.
    'textimage_formatter' => [
      'variables' => [
        'item' => NULL,
        'uri' => NULL,
        'width' => NULL,
        'height' => NULL,
        'alt' => '',
        'title' => '',
        'attributes' => [],
        'image_container_attributes' => [],
        'anchor_url' => NULL,
      ],
    ],
  ];
  return $theme;
}

/**
 * Implements hook_file_download().
 *
 * Control the access to files underneath the textimage directories.
 */
function textimage_file_download($uri) {
  $path = \Drupal::service('stream_wrapper_manager')->getTarget($uri);
  // Private file access for image style derivatives.
  if (strpos($path, 'textimage') === 0) {
    // Check that the file exists and is an image.
    $image = \Drupal::service('image.factory')->get($uri);
    if ($image->isValid()) {
      return [
        // Send headers describing the image's size, and MIME-type...
        'Content-Type' => $image->getMimeType(),
        'Content-Length' => $image->getFileSize(),
        // By not explicitly setting them here, this uses normal Drupal
        // Expires, Cache-Control and ETag headers to prevent proxy or
        // browser caching of private images.
      ];
    }
    return -1;
  }
  return NULL;
}

/**
 * Implements hook_cache_flush().
 */
function textimage_cache_flush() {
  return ['textimage'];
}

/**
 * Implements hook_cron().
 */
function textimage_cron() {
  // Remove temporary, uncached, image files in all available schemes.
  $wrappers = \Drupal::service('stream_wrapper_manager')->getWrappers(StreamWrapperInterface::WRITE_VISIBLE);
  foreach ($wrappers as $wrapper => $wrapper_data) {
    if (file_exists($directory = \Drupal::service('textimage.factory')->getStoreUri('/temp', $wrapper))) {
      if (\Drupal::service('file_system')->deleteRecursive($directory)) {
        \Drupal::service('textimage.logger')->notice('Textimage temporary image files removed.');
      }
      else {
        \Drupal::service('textimage.logger')->error('Textimage could not remove temporary image files.');
      }
    }
  }
}

/**
 * Implements hook_token_info().
 */
function textimage_token_info() {
  $type = [
    'name' => t('Textimage'),
    'description' => t('Deprecated - Tokens related to Textimage'),
    'needs-data' => 'node',
  ];
  $tokens = [
    'uri' => [
      'name' => t("URI"),
      'description' => t("Deprecated. Use [node:textimage-uri:field{:display}{:sequence}] instead."),
      'dynamic' => TRUE,
    ],
    'url' => [
      'name' => t("URL"),
      'description' => t("Deprecated. Use [node:textimage-url:field{:display}{:sequence}] instead."),
      'dynamic' => TRUE,
    ],
  ];
  $node_tokens = [
    'textimage-uri' => [
      'name' => t("Textimage URI"),
      'description' => t("The URI(s) of a Textimage generated for a node's field. Use like <strong>[node:textimage-uri:field{:display}{:sequence}]</strong>, where:<br/><strong>field</strong> is the machine name of the field for which the Textimage is generated (e.g. body or field_xxxx);<br/><strong>display</strong> is an optional indication of the display view mode (e.g. default, full, teaser, etc.); 'default' is used if not specified; <br/><strong>sequence</strong> is an optional indication of the URI to return if Textimage produces more images for the same field (like e.g. in a multi-value Image field); if not specified, a comma-delimited string of all the URIs generated will be returned."),
      'dynamic' => TRUE,
    ],
    'textimage-url' => [
      'name' => t("Textimage URL"),
      'description' => t("The URL(s) of a Textimage generated for a node's field. Use like <strong>[node:textimage-url:field{:display}{:sequence}]</strong>, where:<br/><strong>field</strong> is the machine name of the field for which the Textimage is generated (e.g. body or field_xxxx);<br/><strong>display</strong> is an optional indication of the display view mode (e.g. default, full, teaser, etc.); 'default' is used if not specified; <br/><strong>sequence</strong> is an optional indication of the URL to return if Textimage produces more images for the same field (like e.g. in a multi-value Image field); if not specified, a comma-delimited string of all the URLs generated will be returned."),
      'dynamic' => TRUE,
    ],
  ];
  return [
    'types'  => ['textimage' => $type],
    'tokens' => ['textimage' => $tokens, 'node' => $node_tokens],
  ];
}

/**
 * Implements hook_tokens().
 */
function textimage_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
  if ($type === 'textimage') {
    @trigger_error(implode(', ', $tokens) . ' tokens are deprecated in textimage:8.x-4.2 and are removed from textimage:5.0.0. Use alternative tokens instead. See https://www.drupal.org/project/textimage/issues/3241405', E_USER_DEPRECATED);
    \Drupal::service('textimage.logger')->error(implode(', ', $tokens) . ' tokens are deprecated. Use [node:textimage-url:?] or [node:textimage-uri:?]. In Textimage 5, deprecated tokens will no longer be replaced with the corresponding values.');
    // Process tokens.
    $replacements = \Drupal::service('textimage.factory')->processTokens('url', $tokens, $data, $bubbleable_metadata);
    $replacements += \Drupal::service('textimage.factory')->processTokens('uri', $tokens, $data, $bubbleable_metadata);
    return $replacements;
  }

  if ($type === 'node') {
    // Process tokens.
    $replacements = \Drupal::service('textimage.factory')->processTokens('textimage-url', $tokens, $data, $bubbleable_metadata);
    $replacements += \Drupal::service('textimage.factory')->processTokens('textimage-uri', $tokens, $data, $bubbleable_metadata);
    return $replacements;
  }

  return [];
}

/**
 * Implements hook_image_style_flush().
 */
function textimage_image_style_flush($style) {
  // Manage the textimage part of image style flushing.
  \Drupal::service('textimage.factory')->flushStyle($style);
}

/**
 * Implements hook_image_style_presave().
 *
 * Deals with Textimage third party settings.
 */
function textimage_image_style_presave(ImageStyleInterface $style) {
  // If Textimage TPSs are not yet set, set defaults.
  if (!in_array('textimage', $style->getThirdPartyProviders())) {
    $style->setThirdPartySetting('textimage', 'uri_scheme', \Drupal::service('config.factory')->get('system.file')->get('default_scheme'));
  }
}

/**
 * Make alterations to the core 'image_style_form' form.
 *
 * A fieldset is added if the image style is Textimage relevant.
 */
function textimage_form_image_style_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $image_style = $form_state->getFormObject()->getEntity();
  $form['textimage_options'] = [
    '#type' => 'details',
    '#weight' => 10,
    '#tree' => TRUE,
    '#open' => FALSE,
    '#title' => t('Textimage options'),
    '#description' => t('Define Textimage options specific for this image style.'),
  ];
  // Define file storage wrapper used for the style images.
  $scheme_options = \Drupal::service('stream_wrapper_manager')->getNames(StreamWrapperInterface::WRITE_VISIBLE);
  $form['textimage_options']['uri_scheme'] = [
    '#type' => 'radios',
    '#options' => $scheme_options,
    '#title' => t('Image destination'),
    '#description' => t('Select where Textimage image files should be stored. Private file storage has significantly more overhead than public files, but allows access restriction.'),
    '#default_value' => $image_style->getThirdPartySetting('textimage', 'uri_scheme', \Drupal::service('config.factory')->get('system.file')->get('default_scheme')),
  ];
  // Adds a validate handler to deal with textimage options.
  $form['#validate'][] = '_textimage_form_image_style_form_validate';
}

/**
 * Submit handler to deal with the altered 'image_style_form' form.
 */
function _textimage_form_image_style_form_validate($form, FormStateInterface $form_state) {
  $image_style = $form_state->getFormObject()->getEntity();
  $image_style->setThirdPartySetting('textimage', 'uri_scheme', $form_state->getValue(['textimage_options', 'uri_scheme']));
}

/**
 * Prepares variables to get a Textimage from text.
 *
 * Default template: textimage-formatter.html.twig.
 */
function template_preprocess_textimage_formatter(&$variables) {
  // Render only if the image URI is passed in.
  if ($image_uri = $variables['uri']) {
    // Get alt and title from field item if missing from variables.
    if (!$variables['title'] && $variables['item']) {
      $variables['title'] = $variables['item']->getValue()['title'];
    }
    if (!$variables['alt'] && $variables['item']) {
      $variables['alt'] = $variables['item']->getValue()['alt'];
    }

    // Build anchor link data if needed.
    if ($variables['anchor_url']) {
      if (is_string($variables['anchor_url'])) {
        $href = $variables['anchor_url'];
      }
      else {
        $href = $variables['anchor_url']->toString();
      }
      $variables['anchor_attributes'] = new Attribute([
        'title' => $variables['title'],
        'href' => $href,
      ]);
    }

    // Build image container attributes if needed.
    if (!empty($variables['image_container_attributes'])) {
      $variables['image_container_attributes'] = new Attribute($variables['image_container_attributes']);
    }

    // Get the <img>.
    $variables['image'] = [
      '#theme' => 'image__textimage',
      '#uri' => $image_uri,
      '#width' => $variables['width'],
      '#height' => $variables['height'],
      '#attributes' => $variables['attributes'],
    ];
    if (!empty($variables['title'])) {
      $variables['image']['#title'] = $variables['title'];
    }
    if (!empty($variables['alt'])) {
      $variables['image']['#alt'] = $variables['alt'];
    }
  }
}
