var EventEmitter = require('events').EventEmitter;
var util = require('util');
var contextify = require('contextify');
var mpath = require('mpath');

function PuzzleBox(opt) {
  EventEmitter.call(this);
  this.options = opt;
  this._code = '';
  this._calls = [];
  this._context = {};
  this._subcontexts = {};
}

util.inherits(PuzzleBox, EventEmitter);

// set the code
PuzzleBox.prototype.code = function(code) {
  this._code = code;
  return this;
};

// set the context object
PuzzleBox.prototype.context = function(context) {
  this.dispose();
  this._context = context;
  return this;
};

// spy on things in the context
// TODO: field accesses and sets
PuzzleBox.prototype.track = function(key, cb) {
  var newFn = this.createReplacement(key, mpath.get(key, this._context));
  mpath.set(key, newFn, this._context);
  return this;
};

// create the sandbox
PuzzleBox.prototype.build = function() {
  // create a global callback
  var that = this;
  this._context.finished = function(){
    process.nextTick(function(){
      that.emit('finished');
    });
  };

  this._sandbox = contextify(this._context);
  return this;
};

// get the sandbox data
PuzzleBox.prototype.sandbox = function(){
  return this._sandbox.getGlobal();
};

// get the call data
PuzzleBox.prototype.calls = function(){
  return this._calls;
};

// build and execute the code
PuzzleBox.prototype.run = function() {
  this.build();
  this.emit('started');
  this._sandbox.run(this._code);
  return this;
};

// clear the memory
PuzzleBox.prototype.dispose = function(){
  if (this._sandbox) {
    this._sandbox.dispose();
    delete this._sandbox;
  }
  return this;
};

// wrap a function
// TODO: also wrap this in a puzzle-box
PuzzleBox.prototype.createReplacement = function(name, fn) {
  var that = this;
  var outFn = function(){
    var args = Array.prototype.slice.call(arguments);
    var scope = this;
    var result = fn.apply(scope, arguments);
    var call = {
      fn: name,
      args: args,
      result: result
    };
    that._calls.push(call);
    that.emit('call', call);
    return call.result;
  };
  return outFn;
};

module.exports = PuzzleBox;
@@ -283,34 +283,8 @@
 %7B%7D;%0A
-  this._subcontexts = %7B%7D;%0A
 %7D%0A%0Au
@@ -1974,16 +1974,38 @@
 : result
+,%0A      context: scope
 %0A    %7D;%0A

save scope to calls