(function () {
  'use strict';

  /**
   * @copyright   (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
   * @license     GNU General Public License version 2 or later; see LICENSE.txt
   */

  /* eslint class-methods-use-this: ["error", { "exceptMethods": ["rgbToHex", "hslToRgb"] }] */

  (function (document) {
    /**
     * Regex for hex values e.g. #FF3929
     * @type {RegExp}
     */
    var hexRegex = /^#([a-z0-9]{1,2})([a-z0-9]{1,2})([a-z0-9]{1,2})$/i;

    /**
     * Regex for rgb values e.g. rgba(255, 0, 24, 0.5);
     * @type {RegExp}
     */
    var rgbRegex = /^rgba?\(([0-9]+)[\D]+([0-9]+)[\D]+([0-9]+)(?:[\D]+([0-9](?:.\d+)?))?\)$/i;

    /**
     * Regex for hsl values e.g. hsl(255,0,24);
     * @type {RegExp}
     */
    var hslRegex = /^hsla?\(([0-9]+)[\D]+([0-9]+)[\D]+([0-9]+)[\D]+([0-9](?:.\d+)?)?\)$/i;

    /**
     * Regex for saturation and lightness of hsl - only accepts 1 or 0 or 0.4 or 40
     * @type {RegExp}
     */
    var hslNumberRegex = /^(([0-1])|(0\\.[0-9]+)|([0-9]{1,2})|(100))$/;

    /**
     * Regex for hue values - one to three numbers
     * @type {RegExp}
     */
    var hueRegex = /^[0-9]{1,3}$/;

    /**
     * Creates a slider for the color values hue, saturation and light.
     *
     * @since 4.0.0
     */
    var JoomlaFieldColorSlider = /*#__PURE__*/function () {
      /**
       * @param {HTMLElement} element
       */
      function JoomlaFieldColorSlider(element) {
        var _this = this;
        // Elements
        this.messageSpan = element.querySelector('.form-control-feedback');
        this.mainInput = element.querySelector('.color-input');
        this.input = element.querySelector('#slider-input');
        this.sliders = element.querySelectorAll('.color-slider');
        this.hueSlider = element.querySelector('#hue-slider');
        this.saturationSlider = element.querySelector('#saturation-slider');
        this.lightSlider = element.querySelector('#light-slider');
        this.alphaSlider = element.querySelector('#alpha-slider');

        // Attributes
        this.color = element.dataset.color || '';
        this.default = element.dataset.default || '';
        this.format = this.input.dataset.format || 'hex';
        this.saveFormat = this.mainInput.dataset.format || 'hex';
        this.preview = element.dataset.preview === 'true';
        this.setAlpha = this.format === 'hsla' || this.format === 'rgba';
        this.hue = 360;
        this.saturation = 1;
        this.light = 1;
        this.alpha = 1;
        this.defaultHsl = [this.hue, this.saturation, this.light, this.alpha];
        this.setInitValue();
        this.setBackground();

        // Hide preview field, when selected value should not be visible
        if (!this.preview) {
          this.input.classList.add('hidden');
        } else {
          this.setInputPattern();
        }

        // Always hide main input field (value saved in database)
        this.mainInput.classList.add('hidden');
        Array.prototype.forEach.call(this.sliders, function (slider) {
          slider.addEventListener('change', function () {
            return _this.updateValue(slider);
          });
        });
        this.input.addEventListener('change', function () {
          return _this.changeInput(_this.input);
        });
      }

      /**
       * Set selected value into input field and set it as its background-color.
       */
      var _proto = JoomlaFieldColorSlider.prototype;
      _proto.updateValue = function updateValue(slider) {
        this.showError('');
        var hsl = this.getSliderValueAsHsl(slider.value, slider.dataset.type);
        var rgb = this.hslToRgb(hsl);
        this.hue = hsl[0];
        this.saturation = hsl[1];
        this.light = hsl[2];
        this.alpha = hsl[3];
        this.input.style.border = "2px solid " + this.getRgbString(rgb);
        this.setSliderValues(hsl, slider.dataset.type);
        this.setInputValue(hsl);
        this.setBackground(slider);
      }

      /**
       * React on user changing input value
       *
       * @param {HTMLElement} inputField
       */;
      _proto.changeInput = function changeInput(inputField) {
        var hsl = [this.hue, this.saturation, this.light, this.alpha];
        if (!inputField.value) {
          this.mainInput.value = '';
          this.showError('');
          return;
        }
        if (!this.checkValue(inputField.value)) {
          this.showError('JFIELD_COLOR_ERROR_WRONG_FORMAT');
          this.setInputValue(this.defaultHsl);
        } else {
          this.showError('');
          switch (this.format) {
            case 'hue':
              hsl[0] = inputField.value;
              this.hue = inputField.value;
              break;
            case 'saturation':
              hsl[1] = inputField.value;
              this.saturation = inputField.value;
              break;
            case 'light':
              hsl[2] = inputField.value;
              this.light = inputField.value;
              break;
            case 'alpha':
              hsl[3] = inputField.value;
              this.alpha = inputField.value;
              break;
            default:
              hsl = this.getHsl(inputField.value);
          }
          this.setSliderValues(hsl);
          this.setInputValue(hsl, true);
        }
      }

      /**
       * Check validity of value
       *
       * @param {number|string} value to check
       * @param {string=false} format for which the value gets tested
       * @returns {boolean}
       */;
      _proto.checkValue = function checkValue(value, format) {
        var test = format || this.format;
        switch (test) {
          case 'hue':
            return value <= 360 && hueRegex.test(value);
          case 'saturation':
          case 'light':
          case 'alpha':
            return hslNumberRegex.test(value);
          case 'hsl':
          case 'hsla':
            return hslRegex.test(value);
          case 'hex':
            return hexRegex.test(value);
          case 'rgb':
          case 'rgba':
            return rgbRegex.test(value);
          default:
            return false;
        }
      }

      /**
       * Set validation pattern on input field
       */;
      _proto.setInputPattern = function setInputPattern() {
        var pattern;

        // RegExp has '/' at start and end
        switch (this.format) {
          case 'hue':
            pattern = hueRegex.source.slice(1, -1);
            break;
          case 'saturation':
          case 'light':
          case 'alpha':
            pattern = hslNumberRegex.source.slice(1, -1);
            break;
          case 'hsl':
          case 'hsla':
            pattern = hslRegex.source.slice(1, -1);
            break;
          case 'rgb':
            pattern = rgbRegex.source.slice(1, -1);
            break;
          case 'hex':
          default:
            pattern = hexRegex.source.slice(1, -1);
        }
        this.input.setAttribute('pattern', pattern);
      }

      /**
       * Set linear gradient for slider background
       * @param {HTMLInputElement} [exceptSlider]
       */;
      _proto.setBackground = function setBackground(exceptSlider) {
        var _this2 = this;
        Array.prototype.forEach.call(this.sliders, function (slider) {
          // Jump over changed slider
          if (exceptSlider === slider) {
            return;
          }
          var colors = [];
          var endValue = 100;

          // Longer start color so slider selection matches displayed colors
          colors.push(_this2.getSliderValueAsRgb(0, slider.dataset.type));
          if (slider.dataset.type === 'hue') {
            var steps = Math.floor(360 / 20);
            endValue = 360;
            for (var i = 0; i <= 360; i += steps) {
              colors.push(_this2.getSliderValueAsRgb(i, slider.dataset.type));
            }
          } else {
            for (var _i = 0; _i <= 100; _i += 10) {
              colors.push(_this2.getSliderValueAsRgb(_i, slider.dataset.type));
            }
          }

          // Longer end color so slider selection matches displayed colors
          colors.push(_this2.getSliderValueAsRgb(endValue, slider.dataset.type));
          colors = colors.map(function (value) {
            return _this2.getRgbString(value);
          });
          slider.style.background = "linear-gradient(90deg, " + colors.join(',') + ")";
          slider.style.webkitAppearance = 'none';
        });
      }

      /**
       * Convert given color into hue, saturation and light
       */;
      _proto.setInitValue = function setInitValue() {
        // The initial value can be also a color defined in css
        var cssValue = window.getComputedStyle(this.input).getPropertyValue(this.default);
        this.default = cssValue || this.default;
        if (this.color === '' || typeof this.color === 'undefined') {
          // Unable to get hsl with empty value
          this.input.value = '';
          this.mainInput.value = '';
          return;
        }
        var value = this.checkValue(this.color, this.saveFormat) ? this.color : this.default;
        if (!value) {
          this.showError('JFIELD_COLOR_ERROR_NO_COLOUR');
          return;
        }
        var hsl = [];
        // When given value is a number, use it as defined format and get rest from default value
        if (/^[0-9]+$/.test(value)) {
          hsl = this.default && this.getHsl(this.default);
          if (this.format === 'hue') {
            hsl[0] = value;
          }
          if (this.format === 'saturation') {
            hsl[1] = value > 1 ? value / 100 : value;
          }
          if (this.format === 'light') {
            hsl[2] = value > 1 ? value / 100 : value;
          }
          if (this.format === 'alpha') {
            hsl[3] = value > 1 ? value / 100 : value;
          }
        } else {
          hsl = this.getHsl(value);
        }
        var _hsl = hsl;
        this.hue = _hsl[0];
        this.saturation = _hsl[1];
        this.light = _hsl[2];
        this.alpha = hsl[4] || this.alpha;
        this.defaultHsl = this.default ? this.getHsl(this.default) : hsl;
        this.setSliderValues(hsl);
        this.setInputValue(hsl);
        this.input.style.border = "2px solid " + this.getRgbString(this.hslToRgb(hsl));
      }

      /**
       * Insert message into error message span
       * Message gets handled with Joomla.Text or as empty string
       *
       * @param {string} msg
       */;
      _proto.showError = function showError(msg) {
        this.messageSpan.innerText = msg ? Joomla.Text._(msg) : '';
      }

      /**
       * Convert value into HSLa e.g. #003E7C => [210, 100, 24]
       * @param {array|number|string} value
       * @returns {array}
       */;
      _proto.getHsl = function getHsl(value) {
        var hsl = [];
        if (Array.isArray(value)) {
          hsl = value;
        } else if (hexRegex.test(value)) {
          hsl = this.hexToHsl(value);
        } else if (rgbRegex.test(value)) {
          hsl = this.rgbToHsl(value);
        } else if (hslRegex.test(value)) {
          var matches = value.match(hslRegex);
          hsl = [matches[1], matches[2], matches[3], matches[4]];
        } else {
          this.showError('JFIELD_COLOR_ERROR_CONVERT_HSL');
          return this.defaultHsl;
        }

        // Convert saturation etc. values from e.g. 40 to 0.4
        var i;
        for (i = 1; i < hsl.length; i += 1) {
          hsl[i] = hsl[i] > 1 ? hsl[i] / 100 : hsl[i];
        }
        return hsl;
      }

      /**
       * Returns HSL value from color slider value
       * @params {int} value convert this value
       * @params {string} type type of value: hue, saturation, light or alpha
       * @returns array
       */;
      _proto.getSliderValueAsHsl = function getSliderValueAsHsl(value, type) {
        var h = this.hue;
        var s = this.saturation;
        var l = this.light;
        var a = this.alpha;
        switch (type) {
          case 'alpha':
            a = value;
            break;
          case 'saturation':
            s = value;
            break;
          case 'light':
            l = value;
            break;
          case 'hue':
          default:
            h = value;
        }

        // Percentage light and saturation
        if (l > 1) {
          l /= 100;
        }
        if (s > 1) {
          s /= 100;
        }
        if (a > 1) {
          a /= 100;
        }
        return [h, s, l, a];
      }

      /**
       * Calculates RGB value from color slider value
       * @params {int} value convert this value
       * @params {string} type type of value: hue, saturation, light or alpha
       * @returns array
       */;
      _proto.getSliderValueAsRgb = function getSliderValueAsRgb(value, type) {
        return this.hslToRgb(this.getSliderValueAsHsl(value, type));
      }

      /**
       * Set value in all sliders
       * @param {array} [hsla]
       * @param {string} [except]
       */;
      _proto.setSliderValues = function setSliderValues(_ref, except) {
        var h = _ref[0],
          s = _ref[1],
          l = _ref[2],
          a = _ref[3];
        if (this.hueSlider && except !== 'hue') {
          this.hueSlider.value = Math.round(h);
        }
        if (this.saturationSlider && except !== 'saturation') {
          this.saturationSlider.value = Math.round(s * 100);
        }
        if (this.lightSlider && except !== 'light') {
          this.lightSlider.value = Math.round(l * 100);
        }
        if (a && this.alphaSlider && except !== 'alpha') {
          this.alphaSlider.value = Math.round(a * 100);
        }
      }

      /**
       * Set value in text input fields depending on their format
       * @param {array} hsl
       * @param {boolean=false} onlyMain indicates to change mainInput only
       */;
      _proto.setInputValue = function setInputValue(hsl, onlyMain) {
        var _this3 = this;
        var inputs = [this.mainInput];
        if (!onlyMain) {
          inputs.push(this.input);
        }
        inputs.forEach(function (input) {
          var value;
          switch (input.dataset.format) {
            case 'hsl':
              value = _this3.getHslString(hsl);
              break;
            case 'hsla':
              value = _this3.getHslString(hsl, true);
              break;
            case 'rgb':
              value = _this3.getRgbString(_this3.hslToRgb(hsl));
              break;
            case 'rgba':
              value = _this3.getRgbString(_this3.hslToRgb(hsl), true);
              break;
            case 'hex':
              value = _this3.rgbToHex(_this3.hslToRgb(hsl));
              break;
            case 'alpha':
              value = Math.round(hsl[3] * 100);
              break;
            case 'saturation':
              value = Math.round(hsl[1] * 100);
              break;
            case 'light':
              value = Math.round(hsl[2] * 100);
              break;
            case 'hue':
            default:
              value = Math.round(hsl[0]);
              break;
          }
          input.value = value;
        });
      }

      /**
       * Put RGB values into a string like 'rgb(<R>, <G>, <B>)'
       * @params {array} rgba
       * @params {boolean=false} withAlpha
       * @return {string}
       */;
      _proto.getRgbString = function getRgbString(_ref2, withAlpha) {
        var r = _ref2[0],
          g = _ref2[1],
          b = _ref2[2],
          a = _ref2[3];
        if (withAlpha || this.setAlpha) {
          var alpha = typeof a === 'undefined' ? this.alpha : a;
          return "rgba(" + r + ", " + g + ", " + b + ", " + alpha + ")";
        }
        return "rgb(" + r + ", " + g + ", " + b + ")";
      }

      /**
       * Put HSL values into a string like 'hsl(<H>, <S>%, <L>%, <a>)'
       * @params {array} values
       * @params {boolean=false} withAlpha
       * @return {string}
       */;
      _proto.getHslString = function getHslString(values, withAlpha) {
        var h = values[0],
          s = values[1],
          l = values[2],
          a = values[3];
        s *= 100;
        l *= 100;
        var _map = [h, s, l].map(function (value) {
          return Math.round(value);
        });
        h = _map[0];
        s = _map[1];
        l = _map[2];
        if (withAlpha || this.setAlpha) {
          a = a || this.alpha;
          return "hsla(" + h + ", " + s + "%, " + l + "%, " + a + ")";
        }
        return "hsl(" + h + ", " + s + "%, " + l + "%)";
      }

      /**
       * Returns hsl values out of hex
       * @param {array} rgb
       * @return {string}
       */;
      _proto.rgbToHex = function rgbToHex(rgb) {
        var r = rgb[0].toString(16).toUpperCase();
        var g = rgb[1].toString(16).toUpperCase();
        var b = rgb[2].toString(16).toUpperCase();

        // Double value for hex with '#' and 6 chars
        r = r.length === 1 ? "" + r + r : r;
        g = g.length === 1 ? "" + g + g : g;
        b = b.length === 1 ? "" + b + b : b;
        return "#" + r + g + b;
      }

      /**
       * Returns hsl values out of rgb
       * @param {string|array} values
       * @return {array}
       */;
      _proto.rgbToHsl = function rgbToHsl(values) {
        var rgb = values;
        if (typeof values === 'string') {
          var parts = values.match(rgbRegex);
          rgb = [parts[1], parts[2], parts[3], parts[4]];
        }
        var _rgb$map = rgb.map(function (value) {
            return value > 1 ? value / 255 : value;
          }),
          r = _rgb$map[0],
          g = _rgb$map[1],
          b = _rgb$map[2];
        var max = Math.max(r, g, b);
        var min = Math.min(r, g, b);
        var l = (max + min) / 2;
        var d = max - min;
        var h = 0;
        var s = 0;
        var a = rgb[3] || values[3] || this.alpha;
        if (max !== min) {
          if (max === 0) {
            s = max;
          } else if (min === 1) {
            s = min;
          } else {
            s = (max - l) / Math.min(l, 1 - l);
          }
          switch (max) {
            case r:
              h = 60 * (g - b) / d;
              break;
            case g:
              h = 60 * (2 + (b - r) / d);
              break;
            case b:
            default:
              h = 60 * (4 + (r - g) / d);
              break;
          }
        }
        h = h < 0 ? h + 360 : h;
        a = a > 1 ? a / 100 : a;
        return [h, s, l, a];
      }

      /**
       * Returns hsl values out of hex
       * @param {string} hex
       * @return {array}
       */;
      _proto.hexToHsl = function hexToHsl(hex) {
        var parts = hex.match(hexRegex);
        var r = parts[1];
        var g = parts[2];
        var b = parts[3];
        var rgb = [parseInt(r, 16), parseInt(g, 16), parseInt(b, 16)];
        return this.rgbToHsl(rgb);
      }

      /**
       * Convert HSLa values into RGBa
       * @param {array} hsla
       * @returns {number[]}
       */;
      _proto.hslToRgb = function hslToRgb(_ref3) {
        var h = _ref3[0],
          sat = _ref3[1],
          light = _ref3[2],
          alpha = _ref3[3];
        var r = 1;
        var g = 1;
        var b = 1;

        // Saturation and light were calculated as 0.24 instead of 24%
        var s = sat > 1 ? sat / 100 : sat;
        var l = light > 1 ? light / 100 : light;
        var a = alpha > 1 ? alpha / 100 : alpha;
        if (h < 0 || h > 360 || s < 0 || s > 1 || l < 0 || l > 1) {
          this.showError('JFIELD_COLOR_ERROR_CONVERT_HSL');
          return this.hslToRgb(this.defaultHsl);
        }
        var c = (1 - Math.abs(2 * l - 1)) * s;
        var hi = h / 60;
        var x = c * (1 - Math.abs(hi % 2 - 1));
        var m = l - c / 2;
        if (h >= 0 && h < 60) {
          r = c;
          g = x;
          b = 0;
        } else if (h >= 60 && h < 120) {
          r = x;
          g = c;
          b = 0;
        } else if (h >= 120 && h < 180) {
          r = 0;
          g = c;
          b = x;
        } else if (h >= 180 && h < 240) {
          r = 0;
          g = x;
          b = c;
        } else if (h >= 240 && h < 300) {
          r = x;
          g = 0;
          b = c;
        } else if (h >= 300 && h <= 360) {
          r = c;
          g = 0;
          b = x;
        } else {
          this.showError('JFIELD_COLOR_ERROR_CONVERT_HUE');
          return this.hslToRgb(this.defaultHsl);
        }
        var rgb = [r, g, b].map(function (value) {
          return Math.round((value + m) * 255);
        });
        rgb.push(a);
        return rgb;
      };
      return JoomlaFieldColorSlider;
    }();
    document.addEventListener('DOMContentLoaded', function () {
      var fields = document.querySelectorAll('.color-slider-wrapper');
      if (fields) {
        Array.prototype.forEach.call(fields, function (slider) {
          // eslint-disable-next-line no-new
          new JoomlaFieldColorSlider(slider);
        });
      }
    });
  })(document);

})();
