text: import { Duration, isDuration } from './constructor'
  import isNumber from '../utils/is-number'
  import toInt from '../utils/to-int'
  import absRound from '../utils/abs-round'
  import hasOwnProp from '../utils/has-own-prop'
  import { DATE, HOUR, MINUTE, SECOND, MILLISECOND } from '../units/constants'
  import { cloneWithOffset } from '../units/offset'
  import { createLocal } from '../create/local'
  import { createInvalid as invalid } from './valid'
  
  // ASP.NET json date format regex
  var aspNetRegex = /^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/
  
  // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
  // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
  // and further modified to allow for strings containing both week and day
  var isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/
  
  export function createDuration (input, key) {
    var duration = input
  
    // matching against regexp is expensive, do it on demand
  
    var match = null
  
    var sign
  
    var ret
  
    var diffRes
  
    if (isDuration(input)) {
      duration = {
        ms: input._milliseconds,
        d: input._days,
        M: input._months
      }
    } else if (isNumber(input)) {
      duration = {}
      if (key) {
        duration[key] = input
      } else {
        duration.milliseconds = input
      }
    } else if (match = aspNetRegex.exec(input)) {
      sign = (match[1] === '-') ? -1 : 1
      duration = {
        y: 0,
        d: toInt(match[DATE]) * sign,
        h: toInt(match[HOUR]) * sign,
        m: toInt(match[MINUTE]) * sign,
        s: toInt(match[SECOND]) * sign,
        ms: toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match
      }
    } else if (match = isoRegex.exec(input)) {
      sign = (match[1] === '-') ? -1 : (match[1] === '+') ? 1 : 1
      duration = {
        y: parseIso(match[2], sign),
        M: parseIso(match[3], sign),
        w: parseIso(match[4], sign),
        d: parseIso(match[5], sign),
        h: parseIso(match[6], sign),
        m: parseIso(match[7], sign),
        s: parseIso(match[8], sign)
      }
    } else if (duration == null) { // checks for null or undefined
      duration = {}
    } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
      diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to))
  
      duration = {}
      duration.ms = diffRes.milliseconds
      duration.M = diffRes.months
    }
  
    ret = new Duration(duration)
  
    if (isDuration(input) && hasOwnProp(input, '_locale')) {
      ret._locale = input._locale
    }
  
    return ret
  }
  
  createDuration.fn = Duration.prototype
  createDuration.invalid = invalid
  
  function parseIso (inp, sign) {
    // We'd normally use ~~inp for this, but unfortunately it also
    // converts floats to ints.
    // inp may be undefined, so careful calling replace on it.
    var res = inp && parseFloat(inp.replace(',', '.'))
    // apply sign while we're at it
    return (isNaN(res) ? 0 : res) * sign
  }
  
  function positiveMomentsDifference (base, other) {
    var res = { milliseconds: 0, months: 0 }
  
    res.months = other.month() - base.month() +
          (other.year() - base.year()) * 12
    if (base.clone().add(res.months, 'M').isAfter(other)) {
      --res.months
    }
  
    res.milliseconds = +other - +(base.clone().add(res.months, 'M'))
  
    return res
  }
  
  function momentsDifference (base, other) {
    var res
    if (!(base.isValid() && other.isValid())) {
      return { milliseconds: 0, months: 0 }
    }
  
    other = cloneWithOffset(other, base)
    if (base.isBefore(other)) {
      res = positiveMomentsDifference(base, other)
    } else {
      res = positiveMomentsDifference(other, base)
      res.milliseconds = -res.milliseconds
      res.months = -res.months
    }
  
    return res
  }
  