text: 'use strict';
  
  import DOM from './lib/dom';
  import * as _ from './lib/helper';
  
  (function (root, factory) {
      if (typeof define === 'function' && define.amd) {
          define([], function () {
              return (root.jsCustomScroll = factory());
          });
      } else if (typeof exports === 'object') {
          module.exports = factory();
      } else {
          root.jsCustomScroll = factory();
      }
  }(window, function () {
      const root = window;
      const _document = root.document;
  
      function jsCustomScroll(element, userSettings) {
  
          var scrollbar, scrollbarY;
  
          const Default = {
              speedSwipe: 2,
              wheelDelta: 53,
              draggable: true,
              At_Fn_enabled: true,
              minScrollbarLength: 10
          };
  
          const options = _.extend(Default, userSettings);
  
          const isMouseEvent = e => {
              return /^mouse/.test(e.type);
          };
  
          const getThumbSize = thumbSize => {
  
              if (options.minScrollbarLength) {
                  thumbSize = Math.max(thumbSize, options.minScrollbarLength);
              }
              if (options.maxScrollbarLength) {
                  thumbSize = Math.min(thumbSize, options.maxScrollbarLength);
              }
              return thumbSize;
          };
  
          const toInt = n => {
              return parseInt(n, 10) || 0;
          };
  
          const updateGeometry = event => {
  
              options.containerWidth = element.clientWidth;
              options.containerHeight = element.clientHeight;
              options.contentWidth = element.scrollWidth;
              options.contentHeight = element.scrollHeight;
              options.scrollTop = element.scrollTop;
              options.scrollTrip = options.scrollTop / (options.contentHeight - options.containerHeight) * 100;
  
              if (options.contentHeight === options.containerHeight || options.contentHeight === 0 || options.containerHeight === 0) {
                  scrollbar.style.display = 'none';
                  return false;
              } else {
                  scrollbar.style.display = 'block';
              }
  
              options.scrollbarYHeight = getThumbSize(toInt(options.containerHeight * options.containerHeight / options.contentHeight));
              options.scrollbarYTop = toInt(element.scrollTop * (options.containerHeight - options.scrollbarYHeight) / (options.contentHeight - options.containerHeight));
  
              scrollbar.style.height = options.containerHeight + 'px';
              scrollbar.style.top = element.scrollTop + 'px';
  
              scrollbarY.style.top = options.scrollbarYTop + 'px';
              scrollbarY.style.height = options.scrollbarYHeight + 'px';
  
              if (!event || event.type === 'DOMSubtreeModified') {
                  return;
              }
  
              if (options.at && options.at_Fn) {
                  if (options.At_Fn_enabled && options.at <= options.scrollTrip) {
                      let _scrollTop = element.scrollTop;
                      options.At_Fn_enabled = options.at_Fn.call(event, scrollbar, element, options.scrollTrip) || false;
                      element.scrollTop = _scrollTop;
                  }
              }
  
              if (options.scrollTrip === 0 && options.scrollUp) {
                  options.scrollUp.call(event, scrollbar, element);
              }
  
              if (options.scrollTrip === 100 && options.scrollDown) {
                  options.scrollDown.call(event, scrollbar, element);
              }
  
              if (options.scrollTopChange) {
                  options.scrollTopChange.call(event, scrollbar, element);
              }
          };
  
          var start = {};
          var delta = {};
          var isScrolling, isScrollbarY, isScrollbar;
  
          var elementEevents = {
              handleEvent: function (event) {
  
                  switch (event.type) {
                      case 'wheel':
                      case 'mousewheel':
                      case 'MozMousePixelScroll':
                          event.stopImmediatePropagation();
                          this.scroll(event);
                          break;
                      case 'touchstart':
                      case 'mousedown':
                          event.stopImmediatePropagation();
                          isScrollbarY = event.target === scrollbarY;
                          isScrollbar = event.target === scrollbar;
                          if (isScrollbar) {
                              this.start(event);
                          } else if (isScrollbarY || options.draggable) {
                              this.start(event);
                          }
                          break;
                      case 'mousemove':
                      case 'touchmove':
                          if (isScrollbarY) {
                              event.preventDefault ? event.preventDefault() : (event.returnValue = false);
                              event.stopPropagation();
                              this.mouseMoveHandler(event);
                          } else {
                              this.move(event);
                          }
                          break;
                      case 'mouseup':
                      case 'mouseleave':
                      case 'touchend':
                          this.end(event);
                          break;
                  }
  
              },
              scroll: function (e) {
  
                  let _delta = e.deltaY || e.detail || e.wheelDelta * -1;
                  let scrollTop = +options.wheelSpeed * (_delta > 0 ? 1 : -1);
  
                  if (!scrollTop) {
                      scrollTop = Default.wheelDelta * (_delta > 0 ? 1 : -1);
                  }
  
                  e.preventDefault ? e.preventDefault() : (e.returnValue = false);
                  element.scrollTop = element.scrollTop + scrollTop;
              },
              start: function (event) {
  
                  event.preventDefault ? event.preventDefault() : (event.returnValue = false);
  
                  let touches;
                  if (isMouseEvent(event)) {
                      touches = event;
                  } else {
                      touches = event.touches[0];
                  }
  
                  start = {
                      scrollTop: element.scrollTop,
                      x: touches.pageX,
                      y: touches.pageY
                  };
  
                  isScrolling = undefined;
  
                  delta = {};
  
                  if (isScrollbar && isMouseEvent(event)) {
                      let pageYOffset = root.pageYOffset || _document.documentElement.scrollTop;
                      let pos = start.y - toInt(scrollbar.getBoundingClientRect().top + pageYOffset) - options.scrollbarYHeight;
                      element.scrollTop = (pos + (pos < 0 ? options.scrollbarYHeight : 0)) * (options.contentHeight - options.containerHeight) / (options.containerHeight - options.scrollbarYHeight);
                  } else {
                      if (isMouseEvent(event)) {
                          root.addEventListener('mousemove', this, true);
                          root.addEventListener('mouseup', this, true);
                          root.addEventListener('mouseleave', this, true);
                      } else {
                          root.addEventListener('touchmove', this, true);
                          root.addEventListener('touchend', this, true);
                      }
                  }
  
                  return true;
              },
  
              mouseMoveHandler: function (event) {
  
                  delta = {
                      y: event.pageY - start.y
                  };
  
                  let scrollbarYTop = start.scrollTop * (options.containerHeight - options.scrollbarYHeight) / (options.contentHeight - options.containerHeight);
                  element.scrollTop = toInt((scrollbarYTop + delta.y) * (options.contentHeight - options.containerHeight) / (options.containerHeight - options.scrollbarYHeight));
  
                  return true;
              },
              move: function (event) {
  
                  let touches;
  
                  if (isMouseEvent(event)) {
                      touches = event;
                  } else {
                      if (event.touches.length > 1 || event.scale && event.scale !== 1) {
                          return;
                      }
                      touches = event.touches[0];
                  }
  
                  delta = {
                      x: touches.pageX - start.x,
                      y: touches.pageY - start.y
                  };
  
                  if (typeof isScrolling === 'undefined') {
                      isScrolling = !!(isScrolling || Math.abs(delta.x) < Math.abs(delta.y));
                  }
  
                  element.scrollTop = start.scrollTop - delta.y * options.speedSwipe;
  
                  return true;
              },
              end: function (event) {
  
                  if (typeof delta.y !== 'undefined' && Math.abs(delta.y) > 1) {
                      event.stopPropagation();
                      event.preventDefault ? event.preventDefault() : (event.returnValue = false);
                  }
  
                  if (isMouseEvent(event)) {
                      root.removeEventListener('mousemove', elementEevents, true);
                      root.removeEventListener('mouseup', elementEevents, true);
                      root.removeEventListener('mouseleave', elementEevents, true);
                  } else {
                      root.removeEventListener('touchmove', elementEevents, true);
                      root.removeEventListener('touchend', elementEevents, true);
                  }
  
                  isScrollbarY = false;
                  return true;
              }
          };
  
          const addEventListener = () => {
  
              if (_.browser.touch) {
                  element.addEventListener('touchstart', elementEevents, false);
              } else {
                  element.addEventListener('mousedown', elementEevents, false);
              }
  
              if ('onwheel' in _document) {
                  element.addEventListener('wheel', elementEevents, false);
              } else if ('onmousewheel' in _document) {
                  element.addEventListener('mousewheel', elementEevents, false);
              } else {
                  element.addEventListener('MozMousePixelScroll', elementEevents, false);
              }
  
              element.addEventListener('scroll', updateGeometry, false);
              element.addEventListener('DOMSubtreeModified', updateGeometry, false);
              root.addEventListener('resize', updateGeometry, false);
  
          };
  
          const kill = () => {
  
              if (_.browser.touch) {
                  element.removeEventListener('touchstart', elementEevents, false);
              } else {
                  element.removeEventListener('mousedown', elementEevents, false);
              }
  
              if ('onwheel' in _document) {
                  element.removeEventListener('wheel', elementEevents, false);
              } else if ('onmousewheel' in _document) {
                  element.removeEventListener('mousewheel', elementEevents, false);
              } else {
                  element.removeEventListener('MozMousePixelScroll', elementEevents, false);
              }
  
              element.classList.remove('js-scroll-container');
              element.style.overflowY = 'auto';
  
              element.removeEventListener('scroll', updateGeometry, false);
              element.removeEventListener('DOMSubtreeModified', updateGeometry, false);
              root.removeEventListener('resize', updateGeometry, false);
  
              DOM.remove(scrollbar);
          };
  
          const init = () => {
  
              scrollbar = DOM.createTag('div', {
                  class: 'js-scrollbar-y-wrap'
              });
  
              scrollbarY = DOM.createTag('div', {
                  class: 'js-scrollbar-y'
              });
  
              scrollbar.appendChild(scrollbarY);
  
              element.classList.add('js-scroll-container');
              element.appendChild(scrollbar);
  
              if (_.browser.addEventListener) {
                  addEventListener();
              } else {
                  kill();
              }
  
              updateGeometry();
  
              return {
                  getScrollbar: () => {
                      return scrollbar;
                  },
                  getOptions: () => {
                      return options;
                  },
                  setScrollTop: top => {
                      element.scrollTop = top;
                  },
                  setOptions: _options => {
                      for (let i in _options) {
                          options[i] = _options[i];
                      }
                      return options;
                  },
                  update: updateGeometry,
                  kill: kill
              };
          };
  
          return init();
      }
  
      if (root.jQuery || root.Zepto) {
          (function ($) {
              $.fn.jsCustomScroll = function (params) {
                  return this.each(function () {
                      $(this).data('jsCustomScroll', new jsCustomScroll($(this)[0], params || []));
                  });
              };
          })(root.jQuery || root.Zepto);
      }
      return jsCustomScroll;
  }));