// Generated by CoffeeScript 1.7.1

/*

Dynamic Modules
===============
> Compiles CoffeeScript modules and loads JS modules in a VM, together
> with only a few allowed node.js modules.
 */

(function() {
  var cryptico, cryptoJS, cs, db, exports, issueNeedleCall, issueRequest, logFunction, needle, request, vm;

  db = require('./persistence');

  vm = require('vm');

  needle = require('needle');

  request = require('request');

  cs = require('coffee-script');

  cryptico = require('my-cryptico');

  cryptoJS = require('crypto-js');


  /*
  Module call
  -----------
  Initializes the dynamic module handler.
  
  @param {Object} args
   */

  exports = module.exports = (function(_this) {
    return function(args) {
      var numBits, passPhrase;
      _this.log = args.logger;
      if (!_this.strPublicKey && args['keygen']) {
        db(args);
        passPhrase = args['keygen'];
        numBits = 1024;
        _this.oPrivateRSAkey = cryptico.generateRSAKey(passPhrase, numBits);
        _this.strPublicKey = cryptico.publicKeyString(_this.oPrivateRSAkey);
        _this.log.info("DM | Public Key generated: " + _this.strPublicKey);
      }
      return module.exports;
    };
  })(this);

  exports.getPublicKey = (function(_this) {
    return function() {
      return _this.strPublicKey;
    };
  })(this);

  issueNeedleCall = function(logger) {
    return function(method, url, data, options, cb) {
      var err;
      try {
        return needle.request(method, url, data, options, (function(_this) {
          return function(err, resp, body) {
            try {
              return cb(err, resp, body);
            } catch (_error) {
              err = _error;
              return logger('Error during needle request! ' + err.message);
            }
          };
        })(this));
      } catch (_error) {
        err = _error;
        return logger('Error before needle request! ' + err.message);
      }
    };
  };

  issueRequest = function(logger) {
    return function(options, cb) {
      var err;
      try {
        return request(options, (function(_this) {
          return function(err, resp, body) {
            try {
              return cb(err, resp, body);
            } catch (_error) {
              err = _error;
              return logger('Error during request! ' + err.message);
            }
          };
        })(this));
      } catch (_error) {
        err = _error;
        return logger('Error before request! ' + err.message);
      }
    };
  };

  logFunction = function(uId, rId, mId) {
    return function(msg) {
      return db.appendLog(uId, rId, mId, msg);
    };
  };


  /*
  Try to run a JS module from a string, together with the
  given parameters. If it is written in CoffeeScript we
  compile it first into JS.
  
  @public compileString ( *src, id, params, lang* )
  @param {String} src
  @param {String} id
  @param {Object} params
  @param {String} lang
   */

  exports.compileString = (function(_this) {
    return function(src, userId, ruleId, modId, lang, dbMod, cb) {
      var answ, err, fTryToLoad;
      answ = {
        code: 200,
        message: 'Successfully compiled'
      };
      if (lang === 'CoffeeScript') {
        try {
          src = cs.compile(src);
        } catch (_error) {
          err = _error;
          answ.code = 400;
          answ.message = 'Compilation of CoffeeScript failed at line ' + err.location.first_line;
        }
      }
      fTryToLoad = function(params) {
        var logFunc, msg, oDecrypted, sandbox;
        if (params) {
          try {
            oDecrypted = cryptico.decrypt(params, _this.oPrivateRSAkey);
            params = JSON.parse(oDecrypted.plaintext);
          } catch (_error) {
            err = _error;
            _this.log.warn("DM | Error during parsing of user defined params for " + userId + ", " + ruleId + ", " + modId);
            _this.log.warn(err);
            params = {};
          }
        } else {
          params = {};
        }
        logFunc = logFunction(userId, ruleId, modId);
        sandbox = {
          id: userId + '.' + modId + '.vm',
          params: params,
          needlereq: issueNeedleCall(logFunc),
          request: issueRequest(logFunc),
          cryptoJS: cryptoJS,
          log: logFunc,
          debug: console.log,
          exports: {}
        };
        try {
          vm.runInNewContext(src, sandbox, sandbox.id);
        } catch (_error) {
          err = _error;
          answ.code = 400;
          msg = err.message;
          if (!msg) {
            msg = 'Try to run the script locally to track the error! Sadly we cannot provide the line number';
          }
          answ.message = 'Loading Module failed: ' + msg;
        }
        return cb({
          answ: answ,
          module: sandbox.exports,
          logger: sandbox.log
        });
      };
      if (dbMod) {
        return dbMod.getUserParams(modId, userId, function(err, obj) {
          return fTryToLoad(obj);
        });
      } else {
        return fTryToLoad();
      }
    };
  })(this);

}).call(this);
