/**
 * @file
 * JavaScript behaviors for range element integration.
 */

(function ($, Drupal) {

  'use strict';

  /**
   * Display HTML5 range output in a left/right aligned number input.
   *
   * @type {Drupal~behavior}
   */
  Drupal.behaviors.webformRangeOutputNumber = {
    attach: function (context) {
      $(context).find('.js-form-type-range').once('webform-range-output-number').each(function () {
        // Handle browser that don't support the HTML5 range input.
        if (Modernizr.inputtypes.range === false) {
          return;
        }

        var $element = $(this);
        var $input = $element.find('input[type="range"]');
        var $output = $element.find('input[type="number"]');
        if (!$output.length) {
          return;
        }

        // Set output value.
        $output.val($input.val());

        // Sync input and output values.
        $input.on('input', function () {
          $output.val($input.val());
        });
        $output.on('input', function () {
          $input.val($output.val());
        });
      });
    }
  };

  /**
   * Display HTML5 range output in a floating bubble.
   *
   * @type {Drupal~behavior}
   *
   * @see https://css-tricks.com/value-bubbles-for-range-inputs/
   * @see https://stackoverflow.com/questions/33794123/absolute-positioning-in-relation-to-a-inputtype-range
   */
  Drupal.behaviors.webformRangeOutputBubble = {
    attach: function (context) {
      $(context).find('.js-form-type-range').once('webform-range-output-bubble').each(function () {
        // Handle browser that don't support the HTML5 range input.
        if (Modernizr.inputtypes.range === false) {
          return;
        }

        var $element = $(this);
        var $input = $element.find('input[type="range"]');
        var $output = $element.find('output');
        var display = $output.attr('data-display');

        if (!$output.length) {
          return;
        }

        $element.css('position', 'relative');

        $input.on('input', function () {
          var inputValue = $input.val();

          // Set output text with prefix and suffix.
          var text = ($output.attr('data-field-prefix') || '') +
            inputValue +
            ($output.attr('data-field-suffix') || '');
          $output.text(text);

          // Set output top position.
          var top;
          if (display === 'above') {
            top = $input.position().top - $output.outerHeight() + 2;
          }
          else {
            top = $input.position().top + $input.outerHeight() + 2;
          }

          // It is impossible to accurately calculate the exact position of the
          // range's buttons so we only incrementally move the output bubble.
          var inputWidth = $input.outerWidth();
          var buttonPosition = Math.floor(inputWidth * (inputValue - $input.attr('min')) / ($input.attr('max') - $input.attr('min')));
          var increment = Math.floor(inputWidth / 5);
          var outputWidth = $output.outerWidth();

          // Set output left position.
          var left;
          if (buttonPosition <= increment) {
            left = 0;
          }
          else if (buttonPosition <= increment * 2) {
            left = (increment * 1.5) - outputWidth;
            if (left < 0) {
              left = 0;
            }
          }
          else if (buttonPosition <= increment * 3) {
            left = (increment * 2.5) - (outputWidth / 2);

          }
          else if (buttonPosition <= increment * 4) {
            left = (increment * 4) - outputWidth;
            if (left > (increment * 5) - outputWidth) {
              left = (increment * 5) - outputWidth;
            }
          }
          else if (buttonPosition <= inputWidth) {
            left = (increment * 5) - outputWidth;
          }
          // Also make sure to include the input's left position.
          left = Math.floor($input.position().left + left);

          // Finally, position the output.
          $output.css({top: top, left: left});
        })
          // Fake a change to position output at page load.
          .trigger('input');

        // Add fade in/out event handlers if opacity is defined.
        var defaultOpacity = $output.css('opacity');
        if (defaultOpacity < 1) {
          // Fade in/out on focus/blur of the input.
          $input.on('focus mouseover', function () {
            $output.stop().fadeTo('slow', 1);
          });
          $input.on('blur mouseout', function () {
            $output.stop().fadeTo('slow', defaultOpacity);
          });
          // Also fade in when focusing the output.
          $output.on('touchstart mouseover', function () {
            $output.stop().fadeTo('slow', 1);
          });
        }
      });
    }
  };

})(jQuery, Drupal);
