/**
 * slider 滑块组件
 */

layui.define('component', function(exports) {
  'use strict';

  var $ = layui.$;
  var lay = layui.lay;

  var component = layui.component({
    name: 'slider',
    config: {
      type: 'default', // 滑块类型，垂直：vertical
      min: 0, // 最小值
      max: 100, // 最大值，默认100
      value: 0, // 初始值，默认为0
      step: 1, // 间隔值
      showstep: false, // 间隔点开启
      tips: true, // 文字提示，开启
      tipsAlways: false, // 文字提示，始终开启
      input: false, // 输入框，关闭
      range: false, // 范围选择，与输入框不能同时开启，默认关闭
      height: 200, // 配合 type:"vertical" 使用，默认200px
      disabled: false, // 滑块禁用，默认关闭
      theme: '#16baaa' // 主题颜色
    },
    CONST: {
      ELEM_VIEW: 'layui-slider',
      SLIDER_BAR: 'layui-slider-bar',
      SLIDER_WRAP: 'layui-slider-wrap',
      SLIDER_WRAP_BTN: 'layui-slider-wrap-btn',
      SLIDER_TIPS: 'layui-slider-tips',
      SLIDER_INPUT: 'layui-slider-input',
      SLIDER_INPUT_TXT: 'layui-slider-input-txt',
      SLIDER_INPUT_BTN: 'layui-slider-input-btn',
      ELEM_HOVER: 'layui-slider-hover',
    },
    render: function (rerender) {
      var that = this;
      var options = that.config;

      //间隔值不能小于等于 0
      if (options.step <= 0) options.step = 1;

      //最大值不能小于最小值
      if (options.max < options.min) options.max = options.min + options.step;

      //判断是否开启双滑块
      if (options.range) {
        options.value = typeof (options.value) == 'object' ? options.value : [options.min, options.value];
        var minValue = Math.min(options.value[0], options.value[1])
          , maxValue = Math.max(options.value[0], options.value[1]);
        options.value[0] = Math.max(minValue, options.min);
        options.value[1] = Math.max(maxValue, options.min);
        options.value[0] = Math.min(options.value[0], options.max);
        options.value[1] = Math.min(options.value[1], options.max);

        var scaleFir = (options.value[0] - options.min) / (options.max - options.min) * 100;
        var scaleSec = (options.value[1] - options.min) / (options.max - options.min) * 100;
        var scale = scaleSec - scaleFir + '%';
        scaleFir = scaleFir + '%';
        scaleSec = scaleSec + '%';
      } else {
        //如果初始值是一个数组，则获取数组的最小值
        if (typeof options.value == 'object') {
          options.value = Math.min.apply(null, options.value);
        }

        //初始值不能小于最小值且不能大于最大值
        if (options.value < options.min) options.value = options.min;
        if (options.value > options.max) options.value = options.max;

        var scale = (options.value - options.min) / (options.max - options.min) * 100 + '%';
      }


      //如果禁用，颜色为统一的灰色
      var theme = options.disabled ? '#c2c2c2' : options.theme;

      //滑块
      var temp = '<div class="layui-slider ' + (options.type === 'vertical' ? 'layui-slider-vertical' : '') + '">' + (options.tips ? '<div class="' + CONST.SLIDER_TIPS + '" ' + (options.tipsAlways ? '' : 'style="display:none;"') + '></div>' : '') +
        '<div class="layui-slider-bar" style="background:' + theme + '; ' + (options.type === 'vertical' ? 'height' : 'width') + ':' + scale + ';' + (options.type === 'vertical' ? 'bottom' : 'left') + ':' + (scaleFir || 0) + ';"></div><div class="layui-slider-wrap" style="' + (options.type === 'vertical' ? 'bottom' : 'left') + ':' + (scaleFir || scale) + ';">' +
        '<div class="layui-slider-wrap-btn" style="border: 2px solid ' + theme + ';"></div></div>' + (options.range ? '<div class="layui-slider-wrap" style="' + (options.type === 'vertical' ? 'bottom' : 'left') + ':' + scaleSec + ';"><div class="layui-slider-wrap-btn" style="border: 2px solid ' + theme + ';"></div></div>' : '') + '</div>';

      var othis = $(options.elem);
      var hasRender = othis.next('.' + CONST.ELEM_VIEW);
      //生成替代元素
      hasRender[0] && hasRender.remove(); //如果已经渲染，则Rerender
      that.elemTemp = $(temp);

      //把数据缓存到滑块上
      if (options.range) {
        that.elemTemp.find('.' + CONST.SLIDER_WRAP).eq(0).data('value', options.value[0]);
        that.elemTemp.find('.' + CONST.SLIDER_WRAP).eq(1).data('value', options.value[1]);
      } else {
        that.elemTemp.find('.' + CONST.SLIDER_WRAP).data('value', options.value);
      }

      //插入替代元素
      othis.html(that.elemTemp);

      //垂直滑块
      if (options.type === 'vertical') {
        that.elemTemp.height(options.height + 'px');
      }

      //显示间断点
      if (options.showstep) {
        var number = (options.max - options.min) / options.step, item = '';
        for (var i = 1; i < number + 1; i++) {
          var step = i * 100 / number;
          if (step < 100) {
            item += '<div class="layui-slider-step" style="' + (options.type === 'vertical' ? 'bottom' : 'left') + ':' + step + '%"></div>'
          }
        }
        that.elemTemp.append(item);
      }

      //插入输入框
      if (options.input && !options.range) {
        var elemInput = $('<div class="layui-slider-input"><div class="layui-slider-input-txt"><input type="text" class="layui-input"></div><div class="layui-slider-input-btn"><i class="layui-icon layui-icon-up"></i><i class="layui-icon layui-icon-down"></i></div></div>');
        othis.css("position", "relative");
        othis.append(elemInput);
        othis.find('.' + CONST.SLIDER_INPUT_TXT).children('input').val(options.value);
        if (options.type === 'vertical') {
          elemInput.css({
            left: 0
            , top: -48
          });
        } else {
          that.elemTemp.css("margin-right", elemInput.outerWidth() + 15);
        }
      }

      //给未禁止的滑块滑动事件
      if (!options.disabled) {
        that.slide();
      } else {
        that.elemTemp.addClass(CONST.CLASS_DISABLED);
        that.elemTemp.find('.' + CONST.SLIDER_WRAP_BTN).addClass(CONST.CLASS_DISABLED);
      }

      /**
       * @description 设置提示文本内容
       * @param {Element} sliderWrapBtnElem 提示文本节点元素
       */
      function setSliderTipsTxt(sliderWrapBtnElem) {
        var value = sliderWrapBtnElem.parent().data('value');
        var tipsTxt = options.setTips ? options.setTips(value) : value;
        that.elemTemp.find('.' + CONST.SLIDER_TIPS).html(tipsTxt);
      }

      /**
       * @description 计算提示文本元素的 position left
       * @param {Element} sliderWrapBtnElem 提示文本节点元素
       */
      function calcSliderTipsLeft(sliderWrapBtnElem) {
        var sliderWidth = options.type === 'vertical' ? options.height : that.elemTemp[0].offsetWidth;
        var sliderWrap = that.elemTemp.find('.' + CONST.SLIDER_WRAP);
        var tipsLeft = options.type === 'vertical' ? (sliderWidth - sliderWrapBtnElem.parent()[0].offsetTop - sliderWrap.height()) : sliderWrapBtnElem.parent()[0].offsetLeft;
        var left = tipsLeft / sliderWidth * 100;
        return left
      }

      /**
       * @description 设置提示文本元素的 position left
       * @param {number} left 要设置的 left 的大小
       */
      function setSliderTipsLeft(left) {
        if (options.type === 'vertical') {
          that.elemTemp.find('.' + CONST.SLIDER_TIPS).css({
            "bottom": left + '%',
            "margin-bottom": "20px",
            "display": "inline-block"
          });
        } else {
          that.elemTemp.find('.' + CONST.SLIDER_TIPS).css({
            "left": left + '%',
            "display": "inline-block"
          });
        }
      }

      //判断是否要始终显示提示文本
      if (options.tips) {
        if (options.tipsAlways) {
          var sliderWrapBtnElem = that.elemTemp.find('.' + CONST.SLIDER_WRAP_BTN);
          setSliderTipsTxt(sliderWrapBtnElem)
          var left = calcSliderTipsLeft(sliderWrapBtnElem);
          setSliderTipsLeft(left)
        } else {
          //划过滑块显示数值
          var timer;
          that.elemTemp.find('.' + CONST.SLIDER_WRAP_BTN).on('mouseover', function () {
            setSliderTipsTxt($(this))
            var left = calcSliderTipsLeft($(this));
            clearTimeout(timer);
            timer = setTimeout(function () {
              setSliderTipsLeft(left)
            }, 300);
          }).on('mouseout', function () {
            clearTimeout(timer);
            if (!options.tipsAlways) {
              that.elemTemp.find('.' + CONST.SLIDER_TIPS).css("display", "none");
            }
          });
        }
      }
    },
    extendsInstance: function(){
      var that = this;
      var options = that.config;
      return {
        setValue: function (value, index) {
          value = value > options.max ? options.max : value;
          value = value < options.min ? options.min : value;
          options.value = value;
          return that.slide('set', value, index || 0);
        }
      };
    }
  });

  var CONST = component.CONST;
  var Class = component.Class;

  // 数值精度
  Class.prototype.precision = function(){
    var that = this;
    var options = that.config;
    var precisions = $.map([options.min, options.max, options.step], function(v, i){
      var decimalArr = String(v).split('.');
      return decimalArr[1] ? decimalArr[1].length : 0;
    })
    return Math.max.apply(null, precisions);
  }

  //滑块滑动
  Class.prototype.slide = function(setValue, value, i){
    var that = this;
    var options = that.config;
    var sliderAct = that.elemTemp;
    var sliderWidth = function(){
      return options.type === 'vertical' ? options.height : sliderAct[0].offsetWidth
    };
    var sliderWrap = sliderAct.find('.' + CONST.SLIDER_WRAP);
    var sliderTxt = sliderAct.next('.' + CONST.SLIDER_INPUT);
    var inputValue = sliderTxt.children('.' + CONST.SLIDER_INPUT_TXT).children('input').val();
    var step = 100 / ((options.max - options.min) / options.step);
    var precision = that.precision();
    var change = function(offsetValue, index, from){
      if(Math.ceil(offsetValue) * step > 100){
        offsetValue = Math.ceil(offsetValue) * step
      }else{
        offsetValue = Math.round(offsetValue) * step
      }
      offsetValue = offsetValue > 100 ? 100: offsetValue;
      offsetValue = offsetValue < 0 ? 0: offsetValue;
      sliderWrap.eq(index).css((options.type === 'vertical' ?'bottom':'left'), offsetValue + '%');
      var firLeft = valueTo(sliderWrap[0].offsetLeft);
      var secLeft = options.range ? valueTo(sliderWrap[1].offsetLeft) : 0;
      if(options.type === 'vertical'){
        sliderAct.find('.' + CONST.SLIDER_TIPS).css({"bottom":offsetValue + '%', "margin-bottom":"20px"});
        firLeft = valueTo(sliderWidth() - sliderWrap[0].offsetTop - sliderWrap.height());
        secLeft = options.range ? valueTo(sliderWidth() - sliderWrap[1].offsetTop - sliderWrap.height()) : 0;
      }else{
        sliderAct.find('.' + CONST.SLIDER_TIPS).css("left",offsetValue + '%');
      }
      firLeft = firLeft > 100 ? 100: firLeft;
      secLeft = secLeft > 100 ? 100: secLeft;
      var minLeft = Math.min(firLeft, secLeft)
      ,wrapWidth = Math.abs(firLeft - secLeft);
      if(options.type === 'vertical'){
        sliderAct.find('.' + CONST.SLIDER_BAR).css({"height":wrapWidth + '%', "bottom":minLeft + '%'});
      }else{
        sliderAct.find('.' + CONST.SLIDER_BAR).css({"width":wrapWidth + '%', "left":minLeft + '%'});
      }
      var selfValue = options.min + (options.max - options.min) * offsetValue / 100;
      selfValue = Number(parseFloat(selfValue).toFixed(precision));
      inputValue = selfValue;
      sliderTxt.children('.' + CONST.SLIDER_INPUT_TXT).children('input').val(inputValue);
      sliderWrap.eq(index).data('value', selfValue);
      sliderAct.find('.' + CONST.SLIDER_TIPS).html(options.setTips ? options.setTips(selfValue) : selfValue);

      //如果开启范围选择，则返回数组值
      if(options.range){
        var arrValue = [
          sliderWrap.eq(0).data('value'),
          sliderWrap.eq(1).data('value')
        ];
        if(arrValue[0] > arrValue[1]) arrValue.reverse(); //如果前面的圆点超过了后面的圆点值，则调换顺序
      }

      that.value = options.range ? arrValue : selfValue; // 最新值
      options.change && options.change(that.value); // change 回调

      // 值完成选中的事件
      if(from === 'done') options.done && options.done(that.value);
    };
    var valueTo = function(value){
      var oldLeft = value / sliderWidth() * 100 / step;
      var left =  Math.round(oldLeft) * step;
      if(value == sliderWidth()){
        left =  Math.ceil(oldLeft) * step;
      }
      return left;
    };

    //拖拽元素
    var elemMove = $(['<div class="layui-auxiliar-moving" id="LAY-slider-moving"></div'].join(''));
    var createMoveElem = function(sliderBtnElem, move, up){
      var upCall = function(){
        // 移动端延时一秒关闭
        up && up(lay.touchEventsSupported() ? 1000 : 0);
        elemMove.remove();
        options.done && options.done(that.value);
        // 移动端
        if (lay.touchEventsSupported()) {
          sliderBtnElem[0].removeEventListener('touchmove', move, lay.passiveSupported ? { passive: false } : false);
          sliderBtnElem[0].removeEventListener('touchend', upCall);
          sliderBtnElem[0].removeEventListener('touchcancel', upCall);
        }
      };
      $('#LAY-slider-moving')[0] || $('body').append(elemMove);
      elemMove.on('mousemove', move);
      elemMove.on('mouseup', upCall).on('mouseleave', upCall);
      // 移动端
      if (lay.touchEventsSupported()) {
        sliderBtnElem[0].addEventListener('touchmove', move, lay.passiveSupported ? { passive: false } : false);
        sliderBtnElem[0].addEventListener('touchend', upCall);
        sliderBtnElem[0].addEventListener('touchcancel', upCall);
      }
    };

    //动态赋值
    if(setValue === 'set'){
      return change((value - options.min) / (options.max - options.min) * 100 / step, i, 'done');
    }

    //滑块滑动
    sliderAct.find('.' + CONST.SLIDER_WRAP_BTN).each(function(index){
      var othis = $(this);
      othis.on('mousedown touchstart', function(e){
        e = e || window.event;
        if(e.type === 'touchstart'){
          e.clientX = e.originalEvent.touches[0].clientX;
          e.clientY = e.originalEvent.touches[0].clientY;
        }

        var oldleft = othis.parent()[0].offsetLeft;
        var oldx = e.clientX;
        if(options.type === 'vertical'){
          oldleft = sliderWidth() - othis.parent()[0].offsetTop - sliderWrap.height()
          oldx = e.clientY;
        }

        var move = function(e){
          e = e || window.event;
          if (e.type === 'touchmove') {
            e.clientX = e.touches[0].clientX;
            e.clientY = e.touches[0].clientY;
          }
          var left = oldleft + (options.type === 'vertical' ? (oldx - e.clientY) : (e.clientX - oldx));
          if(left < 0)left = 0;
          if(left > sliderWidth())left = sliderWidth();
          var reaLeft = left / sliderWidth() * 100 / step;
          change(reaLeft, index);
          othis.addClass(CONST.ELEM_HOVER);
          sliderAct.find('.' + CONST.SLIDER_TIPS).show();
          e.preventDefault();
        };

        var up = function(delay){
          othis.removeClass(CONST.ELEM_HOVER);
          if(!options.tipsAlways){
            setTimeout(function(){
              sliderAct.find('.' + CONST.SLIDER_TIPS).hide();
            }, delay);
          }
        };

        createMoveElem(othis, move, up)
      });
    });

    // 点击滑块
    sliderAct.on('click', function(e){
      var main = $('.' + CONST.SLIDER_WRAP_BTN);
      var othis = $(this);
      if(!main.is(event.target) && main.has(event.target).length === 0 && main.length){
        var index;
        var offset = options.type === 'vertical'
          ? (sliderWidth() - e.clientY + othis.offset().top - $(window).scrollTop())
        :(e.clientX - othis.offset().left - $(window).scrollLeft());

        if(offset < 0)offset = 0;
        if(offset > sliderWidth()) offset = sliderWidth();
        var reaLeft = offset / sliderWidth() * 100 / step;
        if(options.range){
          if(options.type === 'vertical'){
            index = Math.abs(offset - parseInt($(sliderWrap[0]).css('bottom'))) > Math.abs(offset -  parseInt($(sliderWrap[1]).css('bottom'))) ? 1 : 0;
          } else {
            index = Math.abs(offset - sliderWrap[0].offsetLeft) > Math.abs(offset - sliderWrap[1].offsetLeft) ? 1 : 0;
          }
        } else {
          index = 0;
        }
        change(reaLeft, index, 'done');
        e.preventDefault();
      }
    });

    //点击加减输入框
    sliderTxt.children('.' + CONST.SLIDER_INPUT_BTN).children('i').each(function(index){
      $(this).on('click', function(){
        inputValue = sliderTxt.children('.' + CONST.SLIDER_INPUT_TXT).children('input').val();
        if(index == 1){ //减
          inputValue = inputValue - options.step < options.min
            ? options.min
          : Number(inputValue) - options.step;
        }else{
          inputValue = Number(inputValue) + options.step > options.max
            ? options.max
          : Number(inputValue) + options.step;
        }
        var inputScale =  (inputValue - options.min) / (options.max - options.min) * 100 / step;
        change(inputScale, 0, 'done');
      });
    });

    //获取输入框值
    var getInputValue = function(){
      var realValue = this.value;
      realValue = isNaN(realValue) ? 0 : realValue;
      realValue = realValue < options.min ? options.min : realValue;
      realValue = realValue > options.max ? options.max : realValue;
      this.value = realValue;
      var inputScale =  (realValue - options.min) / (options.max - options.min) * 100 / step;
      change(inputScale, 0, 'done');
    };
    sliderTxt.children('.' + CONST.SLIDER_INPUT_TXT).children('input').on('keydown', function(e){
      if(e.keyCode === 13){
        e.preventDefault();
        getInputValue.call(this);
      }
    }).on('change', getInputValue);
  };

  exports(CONST.MOD_NAME, component);
})
