import _toConsumableArray from 'babel-runtime/helpers/toConsumableArray';
import _Object$getPrototypeOf from 'babel-runtime/core-js/object/get-prototype-of';
import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
import _createClass from 'babel-runtime/helpers/createClass';
import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
import _get from 'babel-runtime/helpers/get';
import _inherits from 'babel-runtime/helpers/inherits';
/*
Copyright 2013-2015 ASIAL CORPORATION

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.

*/

import onsElements from '../ons/elements';
import util from '../ons/util';
import autoStyle from '../ons/autostyle';
import ModifierUtil from '../ons/internal/modifier-util';
import BaseCheckboxElement from './base/base-checkbox';
import contentReady from '../ons/content-ready';
import GestureDetector from '../ons/gesture-detector';

var scheme = {
  '': 'switch--*',
  '.switch__input': 'switch--*__input',
  '.switch__handle': 'switch--*__handle',
  '.switch__toggle': 'switch--*__toggle'
};

var locations = {
  ios: [1, 21],
  material: [0, 16]
};

/**
 * @element ons-switch
 * @category form
 * @description
 *   [en]
 *     Switch component. The switch can be toggled both by dragging and tapping.
 *
 *     Will automatically displays a Material Design switch on Android devices.
 *   [/en]
 *   [ja]スイッチを表示するコンポーネントです。[/ja]
 * @modifier material
 *   [en]Material Design switch[/en]
 *   [ja][/ja]
 * @codepen LpXZQQ
 * @tutorial vanilla/Reference/switch
 * @guide theming.html#modifiers [en]More details about the `modifier` attribute[/en][ja]modifier属性の使い方[/ja]
 * @example
 * <ons-switch checked></ons-switch>
 * <ons-switch disabled></ons-switch>
 * <ons-switch modifier="material"></ons-switch>
 */

var SwitchElement = function (_BaseCheckboxElement) {
  _inherits(SwitchElement, _BaseCheckboxElement);

  function SwitchElement() {
    _classCallCheck(this, SwitchElement);

    var _this = _possibleConstructorReturn(this, (SwitchElement.__proto__ || _Object$getPrototypeOf(SwitchElement)).call(this));

    contentReady(_this, function () {
      _this.attributeChangedCallback('modifier', null, _this.getAttribute('modifier'));
    });

    _this._onChange = _this._onChange.bind(_this);
    _this._onRelease = _this._onRelease.bind(_this);
    _this._lastTimeStamp = 0;
    return _this;
  }

  _createClass(SwitchElement, [{
    key: '_getPosition',


    /* Own props */

    value: function _getPosition(e) {
      var l = this._locations;
      return Math.min(l[1], Math.max(l[0], this._startX + e.gesture.deltaX));
    }
  }, {
    key: '_emitChangeEvent',
    value: function _emitChangeEvent() {
      util.triggerElementEvent(this, 'change', {
        value: this.checked,
        switch: this,
        isInteractive: true
      });
    }
  }, {
    key: '_onChange',
    value: function _onChange(event) {
      if (event && event.stopPropagation) {
        event.stopPropagation();
      }

      this._emitChangeEvent();
    }
  }, {
    key: '_onClick',
    value: function _onClick(ev) {
      if (ev.target.classList.contains(this.defaultElementClass + '__touch') || ev.timeStamp - this._lastTimeStamp < 50 // Prevent second click triggered by <label>
      ) {
          ev.preventDefault();
        }
      this._lastTimeStamp = ev.timeStamp;
    }
  }, {
    key: '_onHold',
    value: function _onHold(e) {
      if (!this.disabled) {
        ModifierUtil.addModifier(this, 'active');
        document.addEventListener('release', this._onRelease);
      }
    }
  }, {
    key: '_onDragStart',
    value: function _onDragStart(e) {
      if (this.disabled || ['left', 'right'].indexOf(e.gesture.direction) === -1) {
        ModifierUtil.removeModifier(this, 'active');
        return;
      }

      e.consumed = true;

      ModifierUtil.addModifier(this, 'active');
      this._startX = this._locations[this.checked ? 1 : 0]; // - e.gesture.deltaX;

      this.addEventListener('drag', this._onDrag);
      document.addEventListener('release', this._onRelease);
    }
  }, {
    key: '_onDrag',
    value: function _onDrag(e) {
      e.stopPropagation();
      this._handle.style.left = this._getPosition(e) + 'px';
    }
  }, {
    key: '_onRelease',
    value: function _onRelease(e) {
      var l = this._locations;
      var position = this._getPosition(e);
      var previousValue = this.checked;

      this.checked = position >= (l[0] + l[1]) / 2;

      if (this.checked !== previousValue) {
        this._emitChangeEvent();
      }

      this.removeEventListener('drag', this._onDrag);
      document.removeEventListener('release', this._onRelease);

      this._handle.style.left = '';
      ModifierUtil.removeModifier(this, 'active');
    }
  }, {
    key: 'click',
    value: function click() {
      var ev = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

      if (!this.disabled) {
        this.checked = !this.checked;
        this._emitChangeEvent();
        this._lastTimeStamp = ev.timeStamp || 0;
      }
    }
  }, {
    key: 'connectedCallback',
    value: function connectedCallback() {
      var _this2 = this;

      contentReady(this, function () {
        _this2._input.addEventListener('change', _this2._onChange);
      });

      this.addEventListener('dragstart', this._onDragStart);
      this.addEventListener('hold', this._onHold);
      this.addEventListener('tap', this.click);
      this.addEventListener('click', this._onClick);
      this._gestureDetector = new GestureDetector(this, { dragMinDistance: 1, holdTimeout: 251, passive: true });
    }
  }, {
    key: 'disconnectedCallback',
    value: function disconnectedCallback() {
      var _this3 = this;

      contentReady(this, function () {
        _this3._input.removeEventListener('change', _this3._onChange);
      });

      this.removeEventListener('dragstart', this._onDragStart);
      this.removeEventListener('hold', this._onHold);
      this.removeEventListener('tap', this.click);
      this.removeEventListener('click', this._onClick);
      if (this._gestureDetector) {
        this._gestureDetector.dispose();
      }
    }
  }, {
    key: 'attributeChangedCallback',
    value: function attributeChangedCallback(name, last, current) {
      if (name === 'modifier') {
        var md = (current || '').indexOf('material') !== -1;
        this._locations = locations[md ? 'material' : 'ios'];
      }

      _get(SwitchElement.prototype.__proto__ || _Object$getPrototypeOf(SwitchElement.prototype), 'attributeChangedCallback', this).call(this, name, last, current);
    }

    /**
     * @event change
     * @description
     *   [en]Fired when the switch is toggled.[/en]
     *   [ja]ON/OFFが変わった時に発火します。[/ja]
     * @param {Object} event
     *   [en]Event object.[/en]
     *   [ja]イベントオブジェクト。[/ja]
     * @param {Object} event.switch
     *   [en]Switch object.[/en]
     *   [ja]イベントが発火したSwitchオブジェクトを返します。[/ja]
     * @param {Boolean} event.value
     *   [en]Current value.[/en]
     *   [ja]現在の値を返します。[/ja]
     * @param {Boolean} event.isInteractive
     *   [en]True if the change was triggered by the user clicking on the switch.[/en]
     *   [ja]タップやクリックなどのユーザの操作によって変わった場合にはtrueを返します。[/ja]
     */

    /**
     * @attribute modifier
     * @type {String}
     * @description
     *  [en]The appearance of the switch.[/en]
     *  [ja]スイッチの表現を指定します。[/ja]
     */

    /**
     * @attribute disabled
     * @description
     *   [en]Whether the switch is be disabled.[/en]
     *   [ja]スイッチを無効の状態にする場合に指定します。[/ja]
     */

    /**
     * @attribute checked
     * @description
     *   [en]Whether the switch is checked.[/en]
     *   [ja]スイッチがONの状態にするときに指定します。[/ja]
     */

    /**
     * @attribute input-id
     * @type {String}
     * @description
     *   [en]Specify the `id` attribute of the inner `<input>` element. This is useful when using `<label for="...">` elements.[/en]
     *   [ja][/ja]
     */

    /**
     * @property checked
     * @type {Boolean}
     * @description
     *   [en]This value is `true` if the switch is checked.[/en]
     *   [ja]スイッチがONの場合に`true`。[/ja]
     */

    /**
     * @property value
     * @type {String}
     * @description
     *   [en]The current value of the input.[/en]
     *   [ja][/ja]
     */

    /**
     * @property disabled
     * @type {Boolean}
     * @description
     *   [en]Whether the element is disabled or not.[/en]
     *   [ja]無効化されている場合に`true`。[/ja]
     */

    /**
     * @property checkbox
     * @readonly
     * @type {HTMLElement}
     * @description
     *   [en]The underlying checkbox element.[/en]
     *   [ja]コンポーネント内部のcheckbox要素になります。[/ja]
     */

  }, {
    key: '_scheme',
    get: function get() {
      return scheme;
    }
  }, {
    key: '_defaultClassName',
    get: function get() {
      return 'switch';
    }
  }, {
    key: '_template',
    get: function get() {
      return '\n      <input type="' + this.type + '" class="' + this._defaultClassName + '__input">\n      <div class="' + this._defaultClassName + '__toggle">\n        <div class="' + this._defaultClassName + '__handle">\n          <div class="' + this._defaultClassName + '__touch"></div>\n        </div>\n      </div>\n    ';
    }
  }, {
    key: 'type',
    get: function get() {
      return 'checkbox';
    }
  }, {
    key: '_handle',
    get: function get() {
      return this.querySelector('.' + this._defaultClassName + '__handle');
    }
  }, {
    key: 'checkbox',
    get: function get() {
      return this._input;
    }
  }], [{
    key: 'observedAttributes',
    get: function get() {
      return [].concat(_toConsumableArray(_get(SwitchElement.__proto__ || _Object$getPrototypeOf(SwitchElement), 'observedAttributes', this)), ['modifier']);
    }
  }]);

  return SwitchElement;
}(BaseCheckboxElement);

export default SwitchElement;


onsElements.Switch = SwitchElement;
customElements.define('ons-switch', SwitchElement);