/**
 * Mixin to handle spin.
 * @mixin ApSpinMixin
 */

'use strict'

import React, {PropTypes as types} from 'react'
import argx from 'argx'

const SPIN_PROP_KEY = '_apSpin'

/** @lends ApSpinMixin */
let ApSpinMixin = {

  // --------------------
  // Custom
  // --------------------
  $apSpinMixed: true,

  /**
   * Count active spin.
   * @param {string} name - Name of spin.
   * @returns {number} - Number of spins.
   */
  getSpinCount (name) {
    const s = this
    name = name || 'default'
    let counts = s.state[ SPIN_PROP_KEY ] || {}
    return Number(counts[ name ] || 0)
  },

  /**
   * Set active spin count.
   * @param {string} name - Name of spin.
   * @param {number} count  - Count to set.
   */
  setSpinCount (name, count) {
    const s = this
    name = name || 'default'
    let counts = s.state[ SPIN_PROP_KEY ] || {}
    counts[ name ] = count
    if (s.isMounted()) {
      s.setState({ [SPIN_PROP_KEY]: counts })
    }
  },

  /**
   * Check if spin exists.
   * @returns {boolean} - Exists or not.
   */
  hasSpin (name) {
    const s = this
    name = name || 'default'
    return s.getSpinCount(name) > 0
  },

  /**
   * Increment spin count.
   * @param {string} name - Name of spin.
   */
  incrementSpinCount (name) {
    const s = this
    s.setSpinCount(name, s.getSpinCount(name) + 1)
  },

  /**
   * Decrement spin count.
   * @param {string} name - Name of spin.
   */
  decrementSpinCount (name) {
    const s = this
    s.setSpinCount(name, s.getSpinCount(name) - 1)
  },

  /**
   * Rest spin count
   * @param {string} name - Name of spin.
   */
  resetSpinCount (name) {
    const s = this
    s.setSpinCount(name, 0)
  },

  /**
   * Add spin count while active.
   * @param {string|number|symbol} name - Name of spin.
   * @param {function} action - Action to do.
   */
  spinWhile (name, action) {
    let args = argx(arguments)
    name = args.shift('string|number|symbol')
    action = args.pop('function')
    const s = this
    s.incrementSpinCount(name)
    let promise = action()
    if (!promise) {
      throw new Error('[ApSpinMixin] action must return a promise.')
    }
    return promise
      .then((result) => {
        s.decrementSpinCount(name)
        return Promise.resolve(result)
      })
      .catch((err) => {
        s.decrementSpinCount(name)
        return Promise.reject(err)
      })
  },

  // --------------------
  // Specs
  // --------------------
  getInitialState () {
    const s = this
    return {
      [SPIN_PROP_KEY]: {}
    }
  }

  // --------------------
  // Lifecycle
  // --------------------

}

export default Object.freeze(ApSpinMixin)
