import { Duration, isDuration } from ‘./constructor’; import toInt from ‘../utils/to-int’; 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’;

// ASP.NET json date format regex var aspNetRegex = /(-)?(?:(d*).)?(d+):(d+)(?::(d+).?(d{3})?)?/;

// from 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 var isoRegex = /^(-)?P(?:(?:(*)Y)?(?:(*)M)?(?:(*)D)?(?:T(?:(*)H)?(?:(*)M)?(?:(*)S)?)?|(*)W)$/;

export function createDuration (input, key) {

var duration = input,
    // matching against regexp is expensive, do it on demand
    match = null,
    sign,
    ret,
    diffRes;

if (isDuration(input)) {
    duration = {
        ms : input._milliseconds,
        d  : input._days,
        M  : input._months
    };
} else if (typeof input === 'number') {
    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(match[MILLISECOND]) * sign
    };
} else if (!!(match = isoRegex.exec(input))) {
    sign = (match[1] === '-') ? -1 : 1;
    duration = {
        y : parseIso(match[2], sign),
        M : parseIso(match[3], sign),
        d : parseIso(match[4], sign),
        h : parseIso(match[5], sign),
        m : parseIso(match[6], sign),
        s : parseIso(match[7], sign),
        w : 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;

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;
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;

}