(function ($) {

Drupal.behaviors.dateYearRange = {};

Drupal.behaviors.dateYearRange.attach = function (context, settings) {
  var $textfield, $textfields, i;

  // Turn the years back and forward fieldsets into dropdowns.
  $textfields = $('input.select-list-with-custom-option', context).once('date-year-range');
  for (i = 0; i < $textfields.length; i++) {
    $textfield = $($textfields[i]);
    new Drupal.dateYearRange.SelectListWithCustomOption($textfield);
  }
};


Drupal.dateYearRange = {};

/**
 * Constructor for the SelectListWithCustomOption object.
 *
 * This object is responsible for turning the years back and forward textfields
 * into dropdowns with an 'other' option that lets the user enter a custom
 * value.
 */
Drupal.dateYearRange.SelectListWithCustomOption = function ($textfield) {
  this.$textfield = $textfield;
  this.$description = $textfield.next('div.description');
  this.defaultValue = $textfield.val();
  this.$dropdown = this.createDropdown();
  this.$dropdown.insertBefore($textfield);
};

/**
 * Get the value of the textfield as it existed on page load.
 *
 * @param {String} type
 *   The type of the variable to be returned. Defaults to string.
 * @return
 *   The original value of the textfield. Returned as an integer, if the type
 *   parameter was 'int'.
 */
Drupal.dateYearRange.SelectListWithCustomOption.prototype.getOriginal = function (type) {
  var original;
  if (type === 'int') {
    original = parseInt(this.defaultValue, 10);
    if (window.isNaN(original)) {
      original = 0;
    }
  }
  else {
    original = this.defaultValue;
  }
  return original;
};

/**
 * Get the correct first value for the dropdown.
 */
Drupal.dateYearRange.SelectListWithCustomOption.prototype.getStartValue = function () {
  var direction = this.getDirection();
  var start;
  switch (direction) {
    case 'back':
      // For the 'years back' dropdown, the first option should be -10, unless
      // the default value of the textfield is even smaller than that.
      start = Math.min(this.getOriginal('int'), -10);
      break;
    case 'forward':
      start = 0;
      break;
  }
  return start;
};

/**
 * Get the correct last value for the dropdown.
 */
Drupal.dateYearRange.SelectListWithCustomOption.prototype.getEndValue = function () {
  var direction = this.getDirection();
  var end;
  var originalString = this.getOriginal();
  switch (direction) {
    case 'back':
      end = 0;
      break;
    case 'forward':
      // If the original value of the textfield is an absolute year such as
      // 2020, don't try to include it in the dropdown.
      if (originalString.indexOf('+') === -1) {
        end = 10;
      }
      // If the original value is a relative value (+x), we want it to be
      // included in the possible dropdown values.
      else {
        end = Math.max(this.getOriginal('int'), 10);
      }
      break;
  }
  return end;
};

/**
 * Create a dropdown select list with the correct options for this textfield.
 */
Drupal.dateYearRange.SelectListWithCustomOption.prototype.createDropdown = function () {
  var $dropdown = $('<select>').addClass('form-select date-year-range-select');
  var $option, i, value;
  var start = this.getStartValue();
  var end = this.getEndValue();
  var direction = this.getDirection();
  for (i = start; i <= end; i++) {
    // Make sure we include the +/- sign in the option value.
    value = i;
    if (i > 0) {
      value = '+' + i;
    }
    // Zero values must have a + or - in front.
    if (i === 0) {
      if (direction === 'back') {
        value = '-' + i;
      }
      else {
        value = '+' + i;
      }
    }
    $option = $('<option>' + Drupal.formatPlural(value, '@count year from now', '@count years from now') + '</option>').val(value);
    $dropdown.append($option);
  }
  // Create an 'Other' option.
  $option = $('<option class="custom-option">' + Drupal.t('Other') + '</option>').val('');
  $dropdown.append($option);

  // When the user changes the selected option in the dropdown, perform
  // appropriate actions (such as showing or hiding the textfield).
  $dropdown.bind('change', $.proxy(this.handleDropdownChange, this));

  // Set the initial value of the dropdown.
  this._setInitialDropdownValue($dropdown);
  return $dropdown;
};

Drupal.dateYearRange.SelectListWithCustomOption.prototype._setInitialDropdownValue = function ($dropdown) {
  var textfieldValue = this.getOriginal();
  // Determine whether the original textfield value exists in the dropdown.
  var possible = $dropdown.find('option[value="' + textfieldValue + '"]');
  // If the original textfield value is one of the dropdown options, preselect
  // it and hide the 'other' textfield.
  if (possible.length) {
    $dropdown.val(textfieldValue);
    this.hideTextfield();
  }
  // If the original textfield value isn't one of the dropdown options, choose
  // the 'Other' option in the dropdown.
  else {
    $dropdown.val('');
  }
};

/**
 * Determine whether this is the "years back" or "years forward" textfield.
 */
Drupal.dateYearRange.SelectListWithCustomOption.prototype.getDirection = function () {
  if (this.direction) {
    return this.direction;
  }
  var direction;
  if (this.$textfield.hasClass('back')) {
    direction = 'back';
  }
  else if (this.$textfield.hasClass('forward')) {
    direction = 'forward';
  }
  this.direction = direction;
  return direction;
};

/**
 * Change handler for the dropdown, to modify the textfield as appropriate.
 */
Drupal.dateYearRange.SelectListWithCustomOption.prototype.handleDropdownChange = function () {
  // Since the dropdown changed, we need to make the content of the textfield
  // match the (new) selected option.
  this.syncTextfield();

  // Show the textfield if the 'Other' option was selected, and hide it if one
  // of the preset options was selected.
  if ($(':selected', this.$dropdown).hasClass('custom-option')) {
    this.revealTextfield();
  }
  else {
    this.hideTextfield();
  }
};

/**
 * Display the textfield and its description.
 */
Drupal.dateYearRange.SelectListWithCustomOption.prototype.revealTextfield = function () {
  this.$textfield.show();
  this.$description.show();
};

/**
 * Hide the textfield and its description.
 */
Drupal.dateYearRange.SelectListWithCustomOption.prototype.hideTextfield = function () {
  this.$textfield.hide();
  this.$description.hide();
};

/**
 * Copy the selected value of the dropdown to the textfield.
 *
 * FAPI doesn't know about the JS-only dropdown, so the textfield needs to
 * reflect the value of the dropdown.
 */
Drupal.dateYearRange.SelectListWithCustomOption.prototype.syncTextfield = function () {
  var value = this.$dropdown.val();
  this.$textfield.val(value);
};

})(jQuery);
