/**
 * Copyright 2016 the WHATAP project authors. All rights reserved.
 * Use of this source code is governed by a license that
 * can be found in the LICENSE file.
 */

var LocalContext = require('../trace/local-context'),
    TraceContextManager = require('../trace/trace-context-manager'),
    Logger = require('../logger');

var Interceptor = function(agent){
    this.agent = agent;
};

Interceptor.prototype.init = function() {

};

Interceptor.prototype.before = function(obj, funcs, advice, isCallback) {
    if(obj == null) return false;

    if(!Array.isArray(funcs)) funcs = [funcs];

    funcs.forEach(function(func) {
        var orig = obj[func];
        if(!orig) return;

        obj[func] = function proxy() {
            if(isCallback) {
                var selfFunc = this;
                advice(this, arguments, function() {
                    return orig.apply(selfFunc, arguments);
                });
            } else {
                try {
                    advice(this, arguments);
                } catch (e) {
                    Logger.printError("WHATAP-114", "Interceptor error", e);
                }
                return orig.apply(this, arguments);
            }
        };
    });
};

Interceptor.prototype.after = function(obj, funcs, advice) {
    if(!obj) return false;

    if(!Array.isArray(funcs)) funcs = [funcs];

    funcs.forEach(function(func) {
        var orig = obj[func];
        if(!orig) return;

        obj[func] = function() {

            var ret = orig.apply(this, arguments);

            var funcRet;
            try {
                funcRet = advice(this, arguments, ret);
            } catch(e) {
                Logger.printError('WHATAP-115', 'Interceptor after error', e);
            }

            return funcRet || ret;
        };

        obj[func].__whatapAOPInfo__ = {
            obj: obj,
            func: func,
            orig: orig
        };
    });
};

Interceptor.prototype.both = function(obj, funcs, beforeFunc, afterFunc) {
    if(!obj) return false;

    if(!Array.isArray(funcs)) funcs = [funcs];

    funcs.forEach(function(func) {
        var orig = obj[func];
        if(!orig) return;

        obj[func] = function() {
            var ctx = TraceContextManager.getCurrentContext();
            var local_ctx = new LocalContext(ctx, null, null);

            try {
                beforeFunc(this, arguments, local_ctx);
            } catch(e) {
                Logger.printError('WHATAP-116', 'Interceptor both before error', e);
            }

            var ret = orig.apply(this, arguments);
            var funcRet;
            try {
                if(afterFunc){
                    funcRet = afterFunc(this, arguments, ret, local_ctx);
                }
            } catch(e) {
                Logger.printError("WHATAP-117", "Interceptor both after error", e);
            }

            return funcRet || ret;
        };
    });
};

Interceptor.prototype.functionHook = function(args, pos, beforeFunc, afterFunc) {
    if(!args) return false;

    if(args.length <= pos) return false;
    if(pos === -1) pos = args.length - 1;

    var orig = (typeof args[pos] === 'function') ? args[pos] : undefined;
    if(!orig) return false;

    args[pos] = function wrapper() {
        if(beforeFunc) {
            try {
                beforeFunc(this, arguments);
            } catch(e) {
                Logger.printError("WHATAP-118", 'Interceptor functionhook before error', e);
            }
        }

        var result = orig.apply(this, arguments);

        if(afterFunc) {
            try {
                afterFunc(this, arguments, result);
            } catch(e) {
                Logger.printError("WHATAP-119", 'Interceptor functionhook after error', e);
            }
        }
        return result;
    };
    return true;
};

exports.Interceptor = Interceptor;