'use strict';

exports.init = function (app, config, auditLogger) {

    function log(context) {
        var auditLog = {};
        var method = context.method;
        var req = context.req;

        auditLog.method = req.method;
        auditLog.url = req.originalUrl;
        auditLog.eventName = method.sharedClass.name;
        auditLog.subEventName = method.name;
        auditLog.arguments = {
            params: req.params,
            query: req.query,
            headers: req.headers,
            args: context.args
        };

        // remove request and response because of size and cicular references
        if (auditLog.arguments.args.req) {
            delete auditLog.arguments.args.req;
        }
        if (auditLog.arguments.args.res) {
            delete auditLog.arguments.args.res;
        }
        // fix authorizedRoles with for JSON invalid keys '$...'
        if (auditLog.arguments.args.options && auditLog.arguments.args.options.authorizedRoles) {
            auditLog.arguments.args.options.authorizedRoles = Object.keys(auditLog.arguments.args.options.authorizedRoles);
        }

        auditLog.result = Array.isArray(context.result) ?
        context.result.map(function (entry) {
            return entry.toJSON();
        }) : ((context.result && context.result.toJSON) ?
            context.result.toJSON() : {});
        auditLog.error = context.error || {};
        auditLog.status = context.error  ?
            (context.error.statusCode || context.error.status || context.res.statusCode) :
            (context.result && Object.keys(context.result) > 0 ? 200 : 204);

        var currentUser = {};

        var logWithUser = function () {
            currentUser.ip = req.ip ||
                req._remoteAddress ||
                (req.connection && req.connection.remoteAddress) ||
                undefined;
            auditLog.user = currentUser;

            process.nextTick(function () {
                auditLogger.info({'log': auditLog});
            });
        };

        try {
            if (!req.currentUser) {
                if (req.accessToken) {
                    app.models.User.findById(
                        req.accessToken.userId,
                        function (err, user) {
                            if (user) {
                                currentUser = user.toObject();
                                req.currentUser = currentUser;
                            } else {
                                currentUser.name = 'USER NOT FOUND';
                            }
                            logWithUser();
                        }
                    );
                } else {
                    currentUser.name = 'ANONYMOUS';
                    logWithUser();
                }
            } else {
                currentUser = req.currentUser;
                logWithUser();
            }
        } catch (e) {
            // catch logging error to prevent them from kiling the process
            console.log(e);
        }
    }

    var models = app.models();
    models.forEach(function (Model) {

        Model.afterRemote('**', function (context, unused, next) {
            log(context);
            next();
        });
        Model.afterRemoteError('**', function (context, next) {
            log(context);
            next();
        });
    });
};

@@ -594,16 +594,17 @@
 e and ci
+r
 cular re
@@ -806,32 +806,33 @@
 .res;%0A        %7D%0A
+%0A
         // fix a
@@ -830,294 +830,70 @@
  // 
-fix authorizedRoles with for JSON invalid keys '$...'%0A        if (auditLog.arguments.args.options && auditLog.arguments.args.options.authorizedRoles) %7B%0A            auditLog.arguments.args.options.authorizedRoles = Object.keys(auditLog.arguments.args.options.authorizedRoles);%0A        %7D%0A
+use loopbacks toJSON to remove circular references from models
 %0A   
@@ -944,26 +944,30 @@
 .result)
- ?%0A
+%0A  
        
+   ?
  context
@@ -996,28 +996,16 @@
 entry) %7B
-%0A           
  return 
@@ -1019,16 +1019,19 @@
 oJSON();
+ %7D)
 %0A       
@@ -1031,18 +1031,19 @@
         
-%7D)
+   
  : ((con
@@ -1081,28 +1081,16 @@
 oJSON) ?
-%0A           
  context
@@ -1198,19 +1198,16 @@
 xt.error
-  ?
 %0A       
@@ -1202,32 +1202,34 @@
 rror%0A           
+ ?
  (context.error.
@@ -1289,18 +1289,16 @@
 tusCode)
- :
 %0A       
@@ -1301,16 +1301,18 @@
         
+ :
  (contex
@@ -1655,16 +1655,197 @@
 tUser;%0A%0A
+            // $ and . are not allowed as keys in mongo, so escape them all%0A            auditLog = JSON.parse(JSON.stringify(auditLog).replace(/%5C$/g, '___').replace(/%5C./g, '__'));%0A%0A
         

escape $ and . for mongodb json keys