<?php

namespace Drupal\author_field\Plugin\Field\FieldFormatter;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Form\FormStateInterface;

/**
 * Plugin implementation of the configurable 'Author Field' formatter.
 *
 * The author field formatter configures the labels of the author,
 * link to author name,
 * link to ORCID ID, link types, etc. It views the author information
 * based on the configuration for the author field.
 *
 * @FieldFormatter(
 *   id = "configurable_author_field_formatter",
 *   module = "author_field",
 *   label = @Translation("Author field"),
 *   field_types = {
 *     "author_field"
 *   }
 * )
 */
class ConfigurableAuthorFieldFormatter extends FormatterBase {
  /*---------------------------------------------------------------------
   *
   * View.
   *
   *---------------------------------------------------------------------*/

  /**
   * Set up values for form elements to view in the theme template.
   */
  public function viewElements(FieldItemListInterface $items, $langcode): array {
    $element = [];

    $this->sanitizeSettings();

    /** @var \Drupal\author_field\Plugin\Field\FieldType\AuthorFieldItem $item */
    foreach ($items as $delta => $item) {
      $values = $item->getValue();
      $element[$delta] = [
        '#theme' => 'configurable_author_field_formatter',
        '#attributes' => [
          'class' => [
            'author_field',
          ],
        ],
      ];

      // Name Settings.
      $element[$delta]['#author_name_label'] = $this->getSetting('authorNameLabel');
      $element[$delta]['#author_name_label_link'] = $this->getSetting('authorNameLabelLink');

      // Email Settings.
      $element[$delta]['#author_email_label'] = $this->getSetting('authorEmailLabel');

      // Organization Settings.
      $element[$delta]['#author_organization_label'] = $this->getSetting('authorOrganizationLabel');

      // ORCID Settings.
      $element[$delta]['#show_orcid_url'] = $this->getSetting('showORCIDUrl');
      $element[$delta]['#orcid_url_label'] = $this->getSetting('orcidUrlLabel');
      $element[$delta]['#orcid_label_icon_or_link'] = $this->getSetting('orcidLabelIconOrLink');
      $element[$delta]['#orcid_open_link_in'] = $this->getSetting('ORCIDOpenLinkIn');
      $element[$delta]['#show_orcid_url_link'] = $this->getSetting('showORCIDUrlLink');
      $element[$delta]['#orcid_url_no_referrer'] = $this->getSetting('orcidurlnoreferrer');
      $element[$delta]['#orcid_url_no_opener'] = $this->getSetting('orcidurlnoopener');
      $element[$delta]['#orcid_url_no_follow'] = $this->getSetting('orcidurlnofollow');

      $element[$delta]['#author_url_list_style'] = $this->getSetting('authorUrlListStyle');
      $element[$delta]['#author_url_list_separator'] = $this->getSetting('authorUrlListSeparator');
      $element[$delta]['#author_no_of_urls_to_show'] = $this->getSetting('authorNoOfUrlsToShow');

      // Variables.
      $element[$delta]['#author_name'] = $values['given_name'] . ' ' . $values['family_name'];
      $element[$delta]['#email'] = $values['email'];
      $element[$delta]['#orcid_id'] = $values['orcid_id'];
      $element[$delta]['#organization_name'] = $values['organization_name'];
    }

    return $element;
  }

  /**
   * Set up the default values for form elements in formatter.
   */
  public static function defaultSettings(): array {
    return array_merge(
          [
            'authorNameLabel' => 'Name',
            'authorEmailLabel' => 'Email',
            'orcidUrlLabel' => 'Name identifier',
            'authorOrganizationLabel' => 'Organization',
            'authorNameLabelLink' => TRUE,
            'orcidLabelIconOrLink' => 'url',
            'showORCIDUrl' => TRUE,
            'showORCIDUrlLink' => TRUE,
            'ORCIDOpenLinkIn' => '_self',
            'orcidurlnoreferrer' => FALSE,
            'orcidurlnoopener' => FALSE,
            'orcidurlnofollow' => FALSE,
          ],
          parent::defaultSettings());
  }

  /**
   * View current summaries for the author field formatter.
   */
  public function settingsSummary(): array {
    // Sanitize current settings.
    $this->sanitizeSettings();

    // Summarize.
    $summary = [];

    if ($this->getSetting('authorNameLabel')) {
      $summary[] = $this->t('Labels: @label',
        [
          '@label' =>
          $this->getSetting('authorNameLabel') . ', ' .
          $this->getSetting('authorEmailLabel') . ', ' .
          $this->getSetting('authorOrganizationLabel') . ', ' .
          $this->getSetting('orcidUrlLabel'),
        ]
      );
    }

    if ($this->getSetting('authorNameLabelLink')) {
      $summary[] = $this->t('Name: Links to ORCID URL');
    }

    if ($this->getSetting('showORCIDUrlLink')) {
      switch ($this->getSetting('orcidLabelIconOrLink')) {
        case 'icon':
          $summary[] = $this->t('ORCID URL: Icon');
          break;

        case 'url':
          $summary[] = $this->t('ORCID URL: URL');
          break;
      }
    }

    if (!$this->getSetting('showORCIDUrlLink')) {
      $summary[] = $this->t('ORCID URL: No link');
    }
    else {
      switch ($this->getSetting('ORCIDOpenLinkIn')) {
        case '_self':
          $summary[] = $this->t('ORCID URL: Open in current tab/window');
          break;

        case '_blank':
          $summary[] = $this->t('ORCID URL: Open in new tab/window');
          break;
      }

      $text = '';
      if ($this->getSetting('orcidurlnoreferrer')) {
        $text .= 'noreferrer ';
      }

      if ($this->getSetting('orcidurlnoopener')) {
        $text .= 'noopener ';
      }

      if ($this->getSetting('orcidurlnofollow')) {
        $text .= 'nofollow ';
      }

      if (empty($text) === FALSE) {
        $summary[] = 'ORCID URL: ' . $text;
      }
    }

    return $summary;
  }

  /**
   * Returns an array of choices for how to open a link.
   *
   * @return string[]
   *   Returns an associative array with internal names as keys and
   *   human-readable translated names as values.
   */
  protected static function getAuthorOpenLinkInValues(): array {
    return [
      '_self' => t('Open link in the same tab/window'),
      '_blank' => t('Open link in a new tab/window'),
    ];
  }

  /**
   * Returns an array of list styles.
   *
   * @return string[]
   *   Returns an associative array with internal names as keys and
   *   human-readable translated names as values.
   */
  protected static function getOrcidLabelOptions(): array {
    return [
      'icon' => t('Icon next to author name'),
      'url' => t('URL'),
    ];
  }

  /**
   * Configure the form elements in the formatter.
   */
  public function settingsForm(array $form, FormStateInterface $formState): array {
    $this->sanitizeSettings();

    $weight = 0;
    $marker = rand();
    $elements = [];

    $elements['sectionAuthorNameTitle'] = [
      '#markup' => $this->t('<div><b>Author Name Settings</b></div>'),
      '#weight' => $weight++,
    ];
    $elements['sectionAuthorNameBreak'] = [
      '#markup' => '<hr>',
      '#weight' => $weight++,
    ];

    $elements['authorNameLabel'] = [
      '#title' => $this->t('Name Label'),
      '#type' => 'textfield',
      '#size' => 10,
      '#default_value' => $this->getSetting('authorNameLabel'),
      '#weight' => $weight++,
      '#attributes' => [
        'autocomplete' => 'off',
        'autocapitalize' => 'none',
        'spellcheck' => 'false',
        'autocorrect' => 'off',
      ],
      '#wrapper_attributes' => [
        'class' => [
          '',
        ],
      ],
    ];

    $elements['authorNameLabelLink'] = [
      '#title' => $this->t('Link to the ORCID'),
      '#type' => 'checkbox',
      '#default_value' => $this->getSetting('authorNameLabelLink'),
      '#weight' => $weight++,
          // '#options' => $this->getAuthorNameLinkLabels(),
      '#wrapper_attributes' => [
        'class' => [
          '',
        ],
      ],
      '#attributes' => [
        'class' => [
          'showAuthorNameLabelLink-' . $marker,
        ],
      ],
    ];

    $elements['sectionAuthorEmailTitle'] = [
      '#markup' => $this->t('<div><b>Author Email Settings</b></div>'),
      '#weight' => $weight++,
    ];
    $elements['sectionAuthorEmailBreak'] = [
      '#markup' => '<hr>',
      '#weight' => $weight++,
    ];

    $elements['authorEmailLabel'] = [
      '#title' => $this->t('Email Label'),
      '#type' => 'textfield',
      '#size' => 10,
      '#default_value' => $this->getSetting('authorEmailLabel'),
      '#weight' => $weight++,
      '#attributes' => [
        'autocomplete' => 'off',
        'autocapitalize' => 'none',
        'spellcheck' => 'false',
        'autocorrect' => 'off',
      ],
      '#wrapper_attributes' => [
        'class' => [
          '',
        ],
      ],
    ];

    $elements['sectionAuthorOrganizationTitle'] = [
      '#markup' => $this->t('<div><b>Author Organization Settings</b></div>'),
      '#weight' => $weight++,
    ];
    $elements['sectionAuthorOrganizationBreak'] = [
      '#markup' => '<hr>',
      '#weight' => $weight++,
    ];

    $elements['authorOrganizationLabel'] = [
      '#title' => $this->t('Organization Label'),
      '#type' => 'textfield',
      '#size' => 10,
      '#default_value' => $this->getSetting('authorOrganizationLabel'),
      '#weight' => $weight++,
      '#attributes' => [
        'autocomplete' => 'off',
        'autocapitalize' => 'none',
        'spellcheck' => 'false',
        'autocorrect' => 'off',
      ],
      '#wrapper_attributes' => [
        'class' => [
          '',
        ],
      ],
    ];

    $elements['sectionOrcidurlTitle'] = [
      '#markup' => $this->t('<div><b>ORCID URL Settings</b></div>'),
      '#weight' => $weight++,
    ];
    $elements['sectionOrcidUrlBreak'] = [
      '#markup' => '<hr>',
      '#weight' => $weight++,
    ];

    $elements['showORCIDUrl'] = [
      '#title' => $this->t('Show ORCID URL'),
      '#type' => 'checkbox',
      '#default_value' => $this->getSetting('showORCIDUrl'),
      '#weight' => $weight++,
      '#wrapper_attributes' => [
        'class' => [
          '',
        ],
      ],
      '#attributes' => [
        'class' => [
          'showORCIDUrl-' . $marker,
        ],
      ],
    ];

    $elements['orcidUrlLabel'] = [
      '#title' => $this->t('Label'),
      '#type' => 'textfield',
      '#size' => 10,
      '#default_value' => $this->getSetting('orcidUrlLabel'),
      '#weight' => $weight++,
      '#attributes' => [
        'autocomplete' => 'off',
        'autocapitalize' => 'none',
        'spellcheck' => 'false',
        'autocorrect' => 'off',
      ],
      '#wrapper_attributes' => [
        'class' => [
          'formatter_suite-padding-left-15',
        ],
      ],
      '#states' => [
        'visible' => [
          '.showORCIDUrl-' . $marker => [
            'checked' => TRUE,
          ],
        ],
      ],
    ];

    $elements['orcidLabelIconOrLink'] = [
      '#title' => $this->t('Show as'),
      '#type' => 'select',
      '#default_value' => $this->getSetting('orcidLabelIconOrLink'),
      '#weight' => $weight++,
      '#options' => $this->getOrcidLabelOptions(),
      '#wrapper_attributes' => [
        'class' => [
          'formatter_suite-padding-radios-15',
        ],
      ],
      '#attributes' => [
        'class' => [
          'showOrcidLabelIconOrLink-' . $marker,
        ],
      ],
      '#states' => [
        'visible' => [
          '.showORCIDUrl-' . $marker => [
            'checked' => TRUE,
          ],
        ],
      ],
    ];

    $elements['showORCIDUrlLink'] = [
      '#title' => $this->t('Link to the item'),
      '#type' => 'checkbox',
      '#default_value' => $this->getSetting('showORCIDUrlLink'),
      '#weight' => $weight++,
      '#wrapper_attributes' => [
        'class' => [
          'formatter_suite-padding-left-15',
        ],
      ],
      '#attributes' => [
        'class' => [
          'showORCIDUrlLink-' . $marker,
        ],
      ],
      '#states' => [
        'visible' => [
          '.showORCIDUrl-' . $marker => [
            'checked' => TRUE,
          ],
        ],
      ],
    ];

    $elements['ORCIDOpenLinkIn'] = [
      '#title' => $this->t('Use link to'),
      '#type' => 'select',
      '#options' => $this->getAuthorOpenLinkInValues(),
      '#default_value' => $this->getSetting('ORCIDOpenLinkIn'),
      '#weight' => $weight++,
      '#wrapper_attributes' => [
        'class' => [
          'formatter_suite-orcid-link-open-link-in',
        ],
      ],
      '#states' => [
        'visible' => [
          '.showORCIDUrl-' . $marker => [
            'checked' => TRUE,
          ],
        ],
        'disabled' => [
          '.showORCIDUrlLink-' . $marker => [
            'checked' => FALSE,
          ],
        ],
      ],
    ];

    $elements['orcidurlnoreferrer'] = [
      '#title' => $this->t('Do not pass the current site as the referrer ("noreferrer")'),
      '#type' => 'checkbox',
      '#default_value' => $this->getSetting('orcidurlnoreferrer'),
      '#weight' => $weight++,
      '#wrapper_attributes' => [
        'class' => [
          'formatter_suite-orcid-link-noreferrer',
        ],
      ],
      '#states' => [
        'visible' => [
          '.showORCIDUrl-' . $marker => [
            'checked' => TRUE,
          ],
        ],
        'disabled' => [
          '.showORCIDUrlLink-' . $marker => [
            'checked' => FALSE,
          ],
        ],
      ],
    ];

    $elements['orcidurlnoopener'] = [
      '#title' => $this->t('Do not share the current page context ("noopener")'),
      '#type' => 'checkbox',
      '#default_value' => $this->getSetting('orcidurlnoopener'),
      '#weight' => $weight++,
      '#wrapper_attributes' => [
        'class' => [
          'formatter_suite-orcid-link-noopener',
        ],
      ],
      '#states' => [
        'visible' => [
          '.showORCIDUrl-' . $marker => [
            'checked' => TRUE,
          ],
        ],
        'disabled' => [
          '.showORCIDUrlLink-' . $marker => [
            'checked' => FALSE,
          ],
        ],
      ],
    ];

    $elements['orcidurlnofollow'] = [
      '#title' => $this->t('Do not treat the link as an endorsement ("nofollow")'),
      '#type' => 'checkbox',
      '#default_value' => $this->getSetting('orcidurlnofollow'),
      '#weight' => $weight++,
      '#wrapper_attributes' => [
        'class' => [
          'formatter_suite-orcid-link-nofollow',
        ],
      ],
      '#states' => [
        'visible' => [
          '.showORCIDUrl-' . $marker => [
            'checked' => TRUE,
          ],
        ],
        'disabled' => [
          '.showORCIDUrlLink-' . $marker => [
            'checked' => FALSE,
          ],
        ],
      ],
    ];

    return $elements;
  }

  /**
   * Sanitize settings to make sure that they are safe and valid.
   *
   * @internal
   * Drupal's class hierarchy for plugins and their settings does not
   * include a 'validate' function, like that for other classes with forms.
   * Validation must therefore occur on use, rather than on form submission.
   *
   * @endinternal
   */
  protected function sanitizeSettings() {
    // Get current settings.
    $orcid_open_link_in = $this->getSetting('ORCIDOpenLinkIn');

    $showORCIDUrl = $this->getSetting('showORCIDUrl');
    $showORCIDUrlLink = $this->getSetting('showORCIDUrlLink');
    $orcidurlnoreferrer = $this->getSetting('orcidurlnoreferrer');
    $orcidurlnoopener = $this->getSetting('orcidurlnoopener');
    $orcidurlnofollow = $this->getSetting('orcidurlnofollow');

    $authorNameLabelLink = $this->getSetting('authorNameLabelLink');
    $orcidLabelIconOrLink = $this->getSetting('orcidLabelIconOrLink');
    $authorNoOfUrlsToShow = $this->getSetting('authorNoOfUrlsToShow');

    // Get setting defaults.
    $defaults = $this->defaultSettings();

    $authorOpenLinkInValues = $this->getAuthorOpenLinkInValues();
    if (empty($orcid_open_link_in) === TRUE || isset($authorOpenLinkInValues[$orcid_open_link_in]) === FALSE) {
      $orcid_open_link_in = $defaults['ORCIDOpenLinkIn'];
      $this->setSetting('ORCIDOpenLinkIn', $orcid_open_link_in);
    }

    $orcidLabelOptions = $this->getOrcidLabelOptions();
    if (empty($orcidLabelIconOrLink) === TRUE || isset($orcidLabelOptions[$orcidLabelIconOrLink]) === FALSE) {
      $orcid_label_icon_or_link = $defaults['orcidLabelIconOrLink'];
      $this->setSetting('orcidLabelIconOrLink', $orcid_label_icon_or_link);
    }

    if (empty($authorNoOfUrlsToShow) === FALSE && is_numeric($authorNoOfUrlsToShow) === FALSE) {
      $author_no_of_urls_to_show = $defaults['authorNoOfUrlsToShow'];
      $this->setSetting('authorNoOfUrlsToShow', $author_no_of_urls_to_show);
    }

    $authorNameLabelLink = boolval($authorNameLabelLink);
    $this->setSetting('authorNameLabelLink', $authorNameLabelLink);

    // Insure boolean values are boolean for ORCID URL.
    $showORCIDUrl = boolval($showORCIDUrl);
    $showORCIDUrlLink = boolval($showORCIDUrlLink);
    $orcidurlnoreferrer = boolval($orcidurlnoreferrer);
    $orcidurlnoopener = boolval($orcidurlnoopener);
    $orcidurlnofollow = boolval($orcidurlnofollow);

    $this->setSetting('showORCIDUrl', $showORCIDUrl);
    $this->setSetting('showORCIDUrlLink', $showORCIDUrlLink);
    $this->setSetting('orcidurlnoreferrer', $orcidurlnoreferrer);
    $this->setSetting('orcidurlnoopener', $orcidurlnoopener);
    $this->setSetting('orcidurlnofollow', $orcidurlnofollow);

    if ($showORCIDUrl === FALSE) {
      $this->setSetting('showORCIDUrlLink', FALSE);
    }
  }

}
