/*
 * Cloud 9 Carousel 2.0
 *   Cleaned up, refactored, and improved version of CloudCarousel
 *
 * See the demo and get the latest version on GitHub:
 *   http://specious.github.io/cloud9carousel/
 *
 * Copyright (c) 2014 by Ildar Sagdejev ( http://twitter.com/tknomad )
 * Copyright (c) 2011 by R. Cecco ( http://www.professorcloud.com )
 * MIT License
 *
 * Please retain this copyright header in all versions of the software
 *
 * Requires:
 *  - jQuery 1.3.0 or later -OR- Zepto 1.1.1 or later
 *
 * Optional (jQuery only):
 *  - Reflection support via reflection.js plugin by Christophe Beyls
 *     http://www.digitalia.be/software/reflectionjs-for-jquery
 *  - Mousewheel support via mousewheel plugin
 *     http://plugins.jquery.com/mousewheel/
 */

;(function ($) {
  //
  // Detect CSS transform support
  //
  var transform = (function () {
    var vendors = ['webkit', 'moz', 'ms']
    var style = document.createElement('div').style
    var trans = 'transform' in style ? 'transform' : undefined

    for (var i = 0, count = vendors.length; i < count; i++) {
      var prop = vendors[i] + 'Transform'
      if (prop in style) {
        trans = prop
        break
      }
    }

    return trans
  })()

  var Item = function (element, options) {
    element.item = this
    this.element = element

    if (element.tagName === 'IMG') {
      this.fullWidth = element.width
      this.fullHeight = element.height
    } else {
      element.style.display = 'inline-block'
      this.fullWidth = element.offsetWidth
      this.fullHeight = element.offsetHeight
    }

    element.style.position = 'absolute'

    if (options.mirror && this.element.tagName === 'IMG') {
      // Wrap image in a div together with its generated reflection
      this.reflection = $(element).reflect(options.mirror).next()[0]

      var $reflection = $(this.reflection)
      this.reflection.fullHeight = $reflection.height()
      $reflection.css('margin-top', options.mirror.gap + 'px')
      $reflection.css('width', '100%')
      element.style.width = '100%'

      // The item element now contains the image and reflection
      this.element = this.element.parentNode
      this.element.item = this
      this.element.alt = element.alt
      this.element.title = element.title
    }

    if (transform && options.transforms) this.element.style[transform + 'Origin'] = '0 0'

    this.moveTo = function (x, y, scale) {
      this.width = this.fullWidth * scale
      this.height = this.fullHeight * scale
      this.x = x
      this.y = y
      this.scale = scale

      var style = this.element.style
      style.zIndex = ('' + scale * 100) | 0

      if (transform && options.transforms) {
        style[transform] = 'translate(' + x + 'px, ' + y + 'px) scale(' + scale + ')'
      } else {
        // The gap between the image and its reflection doesn't resize automatically
        if (options.mirror && this.element.tagName === 'IMG')
          this.reflection.style.marginTop = options.mirror.gap * scale + 'px'

        style.width = this.width + 'px'
        style.left = x + 'px'
        style.top = y + 'px'
      }
    }
  }

  var time = (function () {
    return !window.performance || !window.performance.now
      ? function () {
          return +new Date()
        }
      : function () {
          return performance.now()
        }
  })()

  //
  // Detect requestAnimationFrame() support
  //
  // Support legacy browsers:
  //   http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
  //
  var cancelFrame = window.cancelAnimationFrame || window.cancelRequestAnimationFrame
  var requestFrame = window.requestAnimationFrame

  ;(function () {
    var vendors = ['webkit', 'moz', 'ms']

    for (var i = 0, count = vendors.length; i < count && !cancelFrame; i++) {
      cancelFrame =
        window[vendors[i] + 'CancelAnimationFrame'] ||
        window[vendors[i] + 'CancelRequestAnimationFrame']
      requestFrame = requestFrame && window[vendors[i] + 'RequestAnimationFrame']
    }
  })()

  let myTime = -1

  var Carousel = function (element, options) {
    var self = this

    // 邵根
    myTime = window.setInterval(() => {
      try {
        clearInterval(myTime)
        window.moveFu(self)
      } catch (error) {}
    }, 200)

    var $container = $(element)
    this.items = []
    this.xOrigin = options.xOrigin === null ? $container.width() * 0.5 : options.xOrigin
    this.yOrigin = options.yOrigin === null ? $container.height() * 0.1 : options.yOrigin
    this.xRadius = options.xRadius === null ? $container.width() / 2.3 : options.xRadius
    this.yRadius = options.yRadius === null ? $container.height() / 6 : options.yRadius
    this.farScale = options.farScale
    this.rotation = this.destRotation = Math.PI / 2 // start with the first item positioned in front
    this.speed = options.speed
    this.smooth = options.smooth
    this.fps = options.fps
    this.timer = 0
    this.autoPlayAmount = options.autoPlay
    this.autoPlayDelay = options.autoPlayDelay
    this.autoPlayTimer = 0
    this.onLoaded = options.onLoaded
    this.onRendered = options.onRendered

    this.itemOptions = {
      transforms: options.transforms
    }

    if (options.mirror) {
      this.itemOptions.mirror = $.extend({ gap: 2 }, options.mirror)
    }

    $container.css({ position: 'relative', overflow: 'hidden' })

    // Rotation:
    //  *      0 : right
    //  *   Pi/2 : front
    //  *   Pi   : left
    //  * 3 Pi/2 : back
    this.rotateItem = function (itemIndex, rotation) {
      var item = this.items[itemIndex]
      var sin = Math.sin(rotation)
      var farScale = this.farScale
      var scale = farScale + (1 - farScale) * (sin + 1) * 0.5

      item.moveTo(
        this.xOrigin + scale * (Math.cos(rotation) * this.xRadius - item.fullWidth * 0.5),
        this.yOrigin + scale * sin * this.yRadius,
        scale
      )
    }

    this.render = function () {
      var count = this.items.length
      var spacing = (2 * Math.PI) / count
      var radians = this.rotation

      for (var i = 0; i < count; i++) {
        this.rotateItem(i, radians)
        radians += spacing
      }

      if (typeof this.onRendered === 'function') this.onRendered(this)
    }

    this.playFrame = function () {
      var rem = self.destRotation - self.rotation
      var now = time()
      var dt = (now - self.lastTime) * 0.002
      self.lastTime = now

      if (Math.abs(rem) < 0.003) {
        self.rotation = self.destRotation
        self.pause()
      } else {
        // Rotate asymptotically closer to the destination
        self.rotation = self.destRotation - rem / (1 + self.speed * dt)
        self.scheduleNextFrame()
      }

      self.render()
    }

    this.scheduleNextFrame = function () {
      this.lastTime = time()

      this.timer =
        this.smooth && cancelFrame
          ? requestFrame(self.playFrame)
          : setTimeout(self.playFrame, 1000 / this.fps)
    }

    this.itemsRotated = function () {
      return (this.items.length * (Math.PI / 2 - this.rotation)) / (2 * Math.PI)
    }

    this.floatIndex = function () {
      var count = this.items.length
      var floatIndex = this.itemsRotated() % count

      // Make sure float-index is positive
      return floatIndex < 0 ? floatIndex + count : floatIndex
    }

    this.nearestIndex = function () {
      return Math.round(this.floatIndex()) % this.items.length
    }

    let myIndex = -1

    this.nearestItem = function () {
      // 获取索引

      if (this.nearestIndex() !== myIndex) {
        // 邵根
        window.getIndexFu(this.nearestIndex())
        myIndex = this.nearestIndex()
      }

      return this.items[this.nearestIndex()]
    }

    this.play = function () {
      if (this.timer === 0) this.scheduleNextFrame()
    }

    this.pause = function () {
      this.smooth && cancelFrame ? cancelFrame(this.timer) : clearTimeout(this.timer)
      this.timer = 0
    }

    //
    // Spin the carousel.  Count is the number (+-) of carousel items to rotate
    //
    this.go = function (count) {
      this.destRotation += ((2 * Math.PI) / this.items.length) * count
      this.play()
    }

    this.deactivate = function () {
      this.pause()
      clearInterval(this.autoPlayTimer)
      options.buttonLeft.unbind('click')
      options.buttonRight.unbind('click')
      $container.unbind('.cloud9')
    }

    this.autoPlay = function () {
      this.autoPlayTimer = setInterval(function () {
        self.go(self.autoPlayAmount)
      }, this.autoPlayDelay)
    }

    this.enableAutoPlay = function () {
      // Stop auto-play on mouse over
      $container.bind('mouseover.cloud9', function () {
        clearInterval(self.autoPlayTimer)
      })

      // Resume auto-play when mouse leaves the container
      $container.bind('mouseout.cloud9', function () {
        self.autoPlay()
      })

      this.autoPlay()
    }

    this.bindControls = function () {
      options.buttonLeft.bind('click', function () {
        self.go(-1)
        return false
      })

      options.buttonRight.bind('click', function () {
        self.go(1)
        return false
      })

      if (options.mouseWheel) {
        $container.bind('mousewheel.cloud9', function (event, delta) {
          self.go(delta > 0 ? 1 : -1)
          return false
        })
      }

      if (options.bringToFront) {
        $container.bind('click.cloud9', function (event) {
          var hits = $(event.target).closest('.' + options.itemClass)

          if (hits.length !== 0) {
            // var idx = self.items.indexOf(hits[0].item)
            //   var count = self.items.length
            //   var diff = idx - (self.floatIndex() % count)
            //   // Choose direction based on which way is shortest
            //   if (2 * Math.abs(diff) > count) diff += diff > 0 ? -count : count
            //   self.destRotation = self.rotation
            //   self.go(-diff)
          }
        })
      }
    }

    var items = $container.find('.' + options.itemClass)

    this.finishInit = function () {
      //
      // Wait until all images have completely loaded
      //
      for (var i = 0; i < items.length; i++) {
        var item = items[i]
        if (
          item.tagName === 'IMG' &&
          (item.width === undefined || (item.complete !== undefined && !item.complete))
        )
          return
      }

      clearInterval(this.initTimer)

      // Init items
      for (i = 0; i < items.length; i++)
        this.items.push(new Item(items[i], this.itemOptions))

      // Disable click-dragging of items
      $container.bind('mousedown onselectstart', function () {
        return false
      })

      if (this.autoPlayAmount !== 0) this.enableAutoPlay()
      this.bindControls()
      this.render()

      if (typeof this.onLoaded === 'function') this.onLoaded(this)
    }

    this.initTimer = setInterval(function () {
      self.finishInit()
    }, 50)
  }

  //
  // The jQuery plugin
  //
  $.fn.Cloud9Carousel = function (options) {
    return this.each(function () {
      /* For full list of options see the README */
      options = $.extend(
        {
          xOrigin: null, // null: calculated automatically
          yOrigin: null,
          xRadius: null,
          yRadius: null,
          farScale: 0.5, // scale of the farthest item
          transforms: true, // enable CSS transforms
          smooth: true, // enable smooth animation via requestAnimationFrame()
          fps: 30, // fixed frames per second (if smooth animation is off)
          speed: 4, // positive number
          autoPlay: 0, // [ 0: off | number of items (integer recommended, positive is clockwise) ]
          autoPlayDelay: 4000,
          bringToFront: false,
          itemClass: 'cloud9-item',
          handle: 'carousel'
        },
        options
      )

      $(this).data(options.handle, new Carousel(this, options))
    })
  }
})(window.jQuery || window.Zepto)
