/**
 * https://github.com/wieringen/tinycolorpicker
 * Rewrote and made file eslint compatible...
 * ~Stevil
 */

;(function ($) {
  const pluginName = 'tinycolorpicker'
  const defaults = {
    colors: [
      '#ffffff',
      '#A7194B',
      '#FE2712',
      '#FB9902',
      '#FABC02',
      '#FEFE33',
      '#D0EA2B',
      '#66B032',
      '#0391CE',
      '#0247FE',
      '#3D01A5',
      '#8601AF',
    ],
    backgroundUrl: null,
  }

  function Plugin($container, options) {
    /**
     * The options of the colorpicker extended with the defaults.
     *
     * @property options
     * @type Object
     */
    this.options = $.extend({}, defaults, options)

    /**
     * @property _defaults
     * @type Object
     * @private
     * @default defaults
     */
    this._defaults = defaults

    /**
     * @property _name
     * @type String
     * @private
     * @final
     * @default 'tinycolorpicker'
     */
    this._name = pluginName

    const self = this
    const $track = $container.find('.track')
    const $color = $container.find('.color')
    let $canvas = null
    const $colorInput = $container.find('.colorInput')
    const $dropdown = $container.find('.dropdown')
    const $dropdownItem = $dropdown.find('li').remove()

    let context = null
    let mouseIsDown = false
    const hasCanvas = !!document.createElement('canvas').getContext
    const touchEvents = 'ontouchstart' in document.documentElement

    /**
     * The current active color in hex.
     *
     * @property colorHex
     * @type String
     * @default ""
     */
    this.colorHex = ''

    /**
     * The current active color in rgb.
     *
     * @property colorRGB
     * @type String
     * @default ""
     */
    this.colorRGB = ''

    /**
     * @method _initialize
     * @private
     */
    function _initialize() {
      if (hasCanvas) {
        $canvas = $('<canvas></canvas>')
        $track.append($canvas)

        context = $canvas[0].getContext('2d')

        _setImage()
      } else {
        $.each(self.options.colors, function (index, color) {
          const $clone = $dropdownItem.clone()

          $clone.css('backgroundColor', color)
          $clone.attr('data-color', color)

          $dropdown.append($clone)
        })
      }

      _setEvents()

      return self
    }

    /**
     * @method _setImage
     * @private
     */
    function _setImage() {
      // eslint-disable-next-line no-undef
      const colorPicker = new Image()
      const backgroundUrl = $track
        .css('background-image')
        .replace(/"/g, '')
        .replace(/url\(|\)$/gi, '')

      colorPicker.crossOrigin = 'Anonymous'
      $track.css('background-image', 'none')

      $(colorPicker).on('load', function () {
        $canvas.attr('width', this.width)
        $canvas.attr('height', this.height)

        context.drawImage(colorPicker, 0, 0, this.width, this.height)
      })

      colorPicker.src = self.options.backgroundUrl || backgroundUrl
    }

    /**
     * @method _setEvents
     * @private
     */
    function _setEvents() {
      const eventType = touchEvents ? 'touchstart' : 'mousedown'

      if (hasCanvas) {
        $color.bind(eventType, function (event) {
          event.preventDefault()
          event.stopPropagation()

          $track.toggle()

          $(document).bind('mousedown.colorpicker', function (event) {
            $(document).unbind('.colorpicker')

            self.close()
          })
        })

        if (!touchEvents) {
          $canvas.mousedown(function (event) {
            mouseIsDown = true

            _getColorCanvas(event)

            $(document).bind('mouseup.colorpicker', function (event) {
              $(document).unbind('.colorpicker')

              self.close()

              return false
            })

            return false
          })

          $canvas.mousemove(_getColorCanvas)
        } else {
          $canvas.bind('touchstart', function (event) {
            mouseIsDown = true

            _getColorCanvas(event.originalEvent.touches[0])

            return false
          })

          $canvas.bind('touchmove', function (event) {
            _getColorCanvas(event.originalEvent.touches[0])

            return false
          })

          $canvas.bind('touchend', function (event) {
            self.close()

            return false
          })
        }
      } else {
        $color.bind('mousedown', function (event) {
          event.preventDefault()
          event.stopPropagation()

          $dropdown.toggle()
        })

        $dropdown.delegate('li', 'mousedown', function (event) {
          event.preventDefault()
          event.stopImmediatePropagation()

          const color = $(this).attr('data-color')

          self.setColor(color)

          $dropdown.hide()
        })
      }
    }

    /**
     * @method _getColorCanvas
     * @private
     */
    function _getColorCanvas(event) {
      if (mouseIsDown) {
        const $target = $(event.target)
        const offset = $target.offset()
        const colorData = context.getImageData(event.pageX - offset.left, event.pageY - offset.top, 1, 1).data

        self.setColor('rgb(' + colorData[0] + ',' + colorData[1] + ',' + colorData[2] + ')')

        /**
         * The change event will trigger when a new color is set.
         *
         * @event change
         */
        $container.trigger('change', [self.colorHex, self.colorRGB])
      }
    }

    /**
     * Set the color to a given hex or rgb color.
     *
     * @method setColor
     * @chainable
     */
    this.setColor = function (color) {
      if (color.indexOf('#') >= 0) {
        self.colorHex = color
        self.colorRGB = self.hexToRgb(self.colorHex)
      } else {
        self.colorRGB = color
        self.colorHex = self.rgbToHex(self.colorRGB)
      }

      $color.find('.colorInner').css('backgroundColor', self.colorHex)
      $colorInput.val(self.colorHex)
    }

    /**
     * Close the picker
     *
     * @method close
     * @chainable
     */
    this.close = function () {
      mouseIsDown = false

      $track.hide()
    }

    /**
     * Convert hex to rgb
     *
     * @method hexToRgb
     * @chainable
     */
    this.hexToRgb = function (hex) {
      const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)

      return 'rgb(' + parseInt(result[1], 16) + ',' + parseInt(result[2], 16) + ',' + parseInt(result[3], 16) + ')'
    }

    /**
     * Convert rgb to hex
     *
     * @method rgbToHex
     * @chainable
     */
    this.rgbToHex = function (rgb) {
      const result = rgb.match(/\d+/g)

      function hex(x) {
        const digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']
        return isNaN(x) ? '00' : digits[(x - (x % 16)) / 16] + digits[x % 16]
      }

      return '#' + hex(result[0]) + hex(result[1]) + hex(result[2])
    }

    return _initialize()
  }

  /**
   * @class tinycolorpicker
   * @constructor
   * @param {Object} options
   * @param {Array} [options.colors=[]] fallback colors for old browsers (ie8-).
   * @param {String} [options.backgroundUrl=''] It will look for a css image on the track div. If not found it will look if there's a url in this property.
   */
  $.fn[pluginName] = function (options) {
    return this.each(function () {
      if (!$.data(this, 'plugin_' + pluginName)) {
        $.data(this, 'plugin_' + pluginName, new Plugin($(this), options))
      }
    })
  }
})(jQuery)
