'use strict';

var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');

var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);

var _constants = require('../utils/constants');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var MDL_RIPPLE_CONTAINER = 'mdlext-lightboard__slide__ripple-container'; /**
                                                                          * @license
                                                                          * Copyright 2016 Leif Olsen. All Rights Reserved.
                                                                          *
                                                                          * Licensed under the Apache License, Version 2.0 (the "License");
                                                                          * you may not use this file except in compliance with the License.
                                                                          * You may obtain a copy of the License at
                                                                          *
                                                                          *      http://www.apache.org/licenses/LICENSE-2.0
                                                                          *
                                                                          * Unless required by applicable law or agreed to in writing, software
                                                                          * distributed under the License is distributed on an "AS IS" BASIS,
                                                                          * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
                                                                          * See the License for the specific language governing permissions and
                                                                          * limitations under the License.
                                                                          *
                                                                          * This code is built with Google Material Design Lite,
                                                                          * which is Licensed under the Apache License, Version 2.0
                                                                          */

/**
 * A lightboard is a translucent surface illuminated from behind, used for situations
 * where a shape laid upon the surface needs to be seen with high contrast. In the "old days" of photography
 * photograpers used a lightboard to get a quick view of their slides. The goal is to create a responsive lightbox
 * design, based on flex layout, similar to what is used in Adobe LightRoom to browse images.
 */

(function () {
  'use strict';

  //const LIGHTBOARD = 'mdlext-lightboard';

  var LIGHTBOARD_ROLE = 'grid';
  var SLIDE = 'mdlext-lightboard__slide';
  var SLIDE_ROLE = 'gridcell';
  var SLIDE_TABSTOP = 'mdlext-lightboard__slide__frame';
  /**
   * @constructor
   * @param {Element} element The element that will be upgraded.
   */
  var MaterialExtLightboard = function MaterialExtLightboard(element) {
    // Stores the element.
    this.element_ = element;

    // Initialize instance.
    this.init();
  };
  window['MaterialExtLightboard'] = MaterialExtLightboard;

  // Helpers
  var getSlide = function getSlide(element) {
    return element ? element.closest('.' + SLIDE) : null;
  };

  // Private methods.

  /**
   * Select a slide, i.e. set aria-selected="true"
   * @param element
   * @private
   */
  MaterialExtLightboard.prototype.selectSlide_ = function (element) {
    var slide = getSlide(element);
    if (slide && !slide.hasAttribute('aria-selected')) {
      [].concat((0, _toConsumableArray3.default)(this.element_.querySelectorAll('.' + SLIDE + '[aria-selected="true"]'))).forEach(function (selectedSlide) {
        return selectedSlide.removeAttribute('aria-selected');
      });

      slide.setAttribute('aria-selected', 'true');
    }
  };

  /**
   * Dispatch select event
   * @param {Element} slide The slide that caused the event
   * @private
   */
  MaterialExtLightboard.prototype.dispatchSelectEvent_ = function (slide) {
    this.element_.dispatchEvent(new CustomEvent('select', {
      bubbles: true,
      cancelable: true,
      detail: { source: slide }
    }));
  };

  /**
   * Handles custom command event, 'first', 'next', 'prev', 'last', 'select' or upgrade
   * @param event. A custom event
   * @private
   */
  MaterialExtLightboard.prototype.commandHandler_ = function (event) {
    event.preventDefault();
    event.stopPropagation();

    if (event && event.detail) {
      this.command(event.detail);
    }
  };

  // Public methods

  /**
   * Initialize lightboard slides
   * @public
   */
  MaterialExtLightboard.prototype.upgradeSlides = function () {

    var addRipple = function addRipple(slide) {
      // Use slide frame as ripple container
      if (!slide.querySelector('.' + MDL_RIPPLE_CONTAINER)) {
        var a = slide.querySelector('.' + SLIDE_TABSTOP);
        if (a) {
          var rippleContainer = a;
          rippleContainer.classList.add(MDL_RIPPLE_CONTAINER);
          rippleContainer.classList.add(_constants.MDL_RIPPLE_EFFECT);
          var ripple = document.createElement('span');
          ripple.classList.add(_constants.MDL_RIPPLE);
          rippleContainer.appendChild(ripple);
          componentHandler.upgradeElement(rippleContainer, _constants.MDL_RIPPLE_COMPONENT);
        }
      }
    };

    var hasRippleEffect = this.element_.classList.contains(_constants.MDL_RIPPLE_EFFECT);

    [].concat((0, _toConsumableArray3.default)(this.element_.querySelectorAll('.' + SLIDE))).forEach(function (slide) {

      slide.setAttribute('role', SLIDE_ROLE);

      if (!slide.querySelector('a')) {
        slide.setAttribute('tabindex', '0');
      }
      if (hasRippleEffect) {
        addRipple(slide);
      }
    });
  };
  MaterialExtLightboard.prototype['upgradeSlides'] = MaterialExtLightboard.prototype.upgradeSlides;

  /**
   * Execute command
   * @param detail
   * @public
   */
  MaterialExtLightboard.prototype.command = function (detail) {
    var _this = this;

    var firstSlide = function firstSlide() {
      return _this.element_.querySelector('.' + SLIDE + ':first-child');
    };

    var lastSlide = function lastSlide() {
      return _this.element_.querySelector('.' + SLIDE + ':last-child');
    };

    var nextSlide = function nextSlide() {
      var slide = _this.element_.querySelector('.' + SLIDE + '[aria-selected="true"]').nextElementSibling;
      return slide ? slide : firstSlide();
    };

    var prevSlide = function prevSlide() {
      var slide = _this.element_.querySelector('.' + SLIDE + '[aria-selected="true"]').previousElementSibling;
      return slide ? slide : lastSlide();
    };

    if (detail && detail.action) {
      var action = detail.action,
          target = detail.target;


      var slide = void 0;
      switch (action.toLowerCase()) {
        case 'select':
          slide = getSlide(target);
          this.dispatchSelectEvent_(slide);
          break;
        case 'first':
          slide = firstSlide();
          break;
        case 'next':
          slide = nextSlide();
          break;
        case 'prev':
          slide = prevSlide();
          break;
        case 'last':
          slide = lastSlide();
          break;
        case 'upgrade':
          this.upgradeSlides();
          break;
        default:
          throw new Error('Unknown action "' + action + '". Action must be one of "first", "next", "prev", "last", "select" or "upgrade"');
      }

      if (slide) {
        var a = slide.querySelector('a');
        if (a) {
          a.focus();
        } else {
          slide.focus();
        }

        // Workaround for JSDom testing:
        // In JsDom 'element.focus()' does not trigger any focus event
        if (!slide.hasAttribute('aria-selected')) {
          this.selectSlide_(slide);
        }
      }
    }
  };
  MaterialExtLightboard.prototype['command'] = MaterialExtLightboard.prototype.command;

  /**
   * Initialize component
   */
  MaterialExtLightboard.prototype.init = function () {
    var _this2 = this;

    var keydownHandler = function keydownHandler(event) {

      if (event.target !== _this2.element_) {
        var action = void 0;
        var target = void 0;
        switch (event.keyCode) {
          case _constants.VK_HOME:
            action = 'first';
            break;
          case _constants.VK_END:
            action = 'last';
            break;
          case _constants.VK_ARROW_UP:
          case _constants.VK_ARROW_LEFT:
            action = 'prev';
            break;
          case _constants.VK_ARROW_DOWN:
          case _constants.VK_ARROW_RIGHT:
            action = 'next';
            break;
          case _constants.VK_ENTER:
          case _constants.VK_SPACE:
            action = 'select';
            target = event.target;
            break;
        }
        if (action) {
          event.preventDefault();
          event.stopPropagation();
          _this2.command({ action: action, target: target });
        }
      }
    };

    var clickHandler = function clickHandler(event) {
      event.preventDefault();
      event.stopPropagation();

      if (event.target !== _this2.element_) {
        _this2.command({ action: 'select', target: event.target });
      }
    };

    var focusHandler = function focusHandler(event) {
      event.preventDefault();
      event.stopPropagation();

      if (event.target !== _this2.element_) {
        _this2.selectSlide_(event.target);
      }
    };

    if (this.element_) {
      this.element_.setAttribute('role', LIGHTBOARD_ROLE);

      if (this.element_.classList.contains(_constants.MDL_RIPPLE_EFFECT)) {
        this.element_.classList.add(_constants.MDL_RIPPLE_EFFECT_IGNORE_EVENTS);
      }

      // Remove listeners, just in case ...
      this.element_.removeEventListener('command', this.commandHandler_);
      this.element_.removeEventListener('keydown', keydownHandler);
      this.element_.removeEventListener('click', clickHandler);
      this.element_.removeEventListener('focus', focusHandler);

      this.element_.addEventListener('command', this.commandHandler_.bind(this), false);
      this.element_.addEventListener('keydown', keydownHandler, true);
      this.element_.addEventListener('click', clickHandler, true);
      this.element_.addEventListener('focus', focusHandler, true);

      this.upgradeSlides();

      this.element_.classList.add(_constants.IS_UPGRADED);
    }
  };

  // The component registers itself. It can assume componentHandler is available
  // in the global scope.
  /* eslint no-undef: 0 */
  /* jshint undef:false */
  componentHandler.register({
    constructor: MaterialExtLightboard,
    classAsString: 'MaterialExtLightboard',
    cssClass: 'mdlext-js-lightboard',
    widget: true
  });
})();