'use strict'

function isFunction (funktion) {
    return typeof funktion === 'function'
}

function defineProperty (obj, name, value) {
    var enumerable = !!obj[name] && obj.propertyIsEnumerable(name)
    Object.defineProperty(obj, name, {
        configurable: true,
        enumerable: enumerable,
        writable: true,
        value: value
    })
}

var shimmer = function () {
}

var wrap = function (nodule, name, wrapper) {
    if (!nodule || !nodule[name]) {
        return;
    }

    if (!wrapper) {
        return;
    }

    if (!isFunction(nodule[name]) || !isFunction(wrapper)) {
        return
    }

    var original = nodule[name]
    var wrapped = wrapper(original, name)

    defineProperty(wrapped, '__original', original)
    defineProperty(wrapped, '__unwrap', function () {
        if (nodule[name] === wrapped) defineProperty(nodule, name, original)
    })
    defineProperty(wrapped, '__wrapped', true)

    defineProperty(nodule, name, wrapped)
    return wrapped
}

function unwrap (nodule, name) {
    if (!nodule || !nodule[name]) {
        return
    }

    if (!nodule[name].__unwrap) {
    } else {
        return nodule[name].__unwrap()
    }
}

function massWrap (nodules, names, wrapper) {
    if (!nodules) {
        return
    } else if (!Array.isArray(nodules)) {
        nodules = [nodules]
    }

    if (!(names && Array.isArray(names))) {
        return
    }

    nodules.forEach(function (nodule) {
        names.forEach(function (name) {
            wrap(nodule, name, wrapper)
        })
    })
}

function massUnwrap (nodules, names) {
    if (!nodules) {
        return
    } else if (!Array.isArray(nodules)) {
        nodules = [nodules]
    }

    if (!(names && Array.isArray(names))) {
        return
    }

    nodules.forEach(function (nodule) {
        names.forEach(function (name) {
            unwrap(nodule, name)
        })
    })
}

shimmer.wrap = wrap;
shimmer.unwrap = unwrap;
shimmer.massWrap = massWrap;
shimmer.massUnwrap = massUnwrap;

module.exports = shimmer;