use :node;

var Node = module.require('../Node').Node,

ForInStatement = module.require('./ForInStatement').ForInStatement;

fn ForOfStatement(key, value, object, body)

extends Node {

this.type = 'ForOfStatement';

this.key = key;
this.key.parent = this;

this.value = value;
if this.value? {
  this.value.parent = this;
}

this.object = object;
this.object.parent = this;

this.body = body;
this.body.parent = this;

}

ForOfStatement.prototype.codegen = () -> {

if !super.codegen() {
  return;
}

this.object = this.object.codegen();

if this.value? {
  this.value = this.value.codegen(false);
  this.body.defineIdentifier(this.value);

  if this.object.hasCallExpression() {
    var id = {
      "type": "Identifier",
      "name": exports.ForOfStatement.getNextVariableName()
    };

    var context = this.getContext();
    context.node.body.splice(context.position, 0, {
      "type": "VariableDeclaration",
      "declarations": [{
        "type": "VariableDeclarator",
        "id": id,
        "init": this.object
      }],
      "kind": "let",
      "codeGenerated": true
    });

    this.object = id;
  }

  this.body.body = [{
    "type": "VariableDeclaration",
    "codeGenerated": true,
    "declarations": [{
      "type": "VariableDeclarator",
      "id": this.value,
      "init": {
        "type": "MemberExpression",
        "computed": "true",
        "object": this.object,
        "property": this.key
      }
    }],
    "kind": "let",
  }].concat(this.body.body);
}

var forInLoop = (new ForInStatement(this.key, 
  null, 
  {
    "type": "CallExpression",
    "codeGenerated": true,
    "callee": {
      "type": "MemberExpression",
      "computed": false,
      "object": {
        "type": "Identifier",
        "name": "Object"
      },
      "property": {
        "type": "Identifier",
        "name": "keys"
      }
    },
    "arguments": [this.object]
  },
  this.body
)).codegen();

this.type = forInLoop.type;
this.right = forInLoop.right;
this.left = forInLoop.left;
this.each = forInLoop.each;

return this;

};

ForOfStatement.getNextVariableName = () -> {

if (!this.forOfIndex) { 
  this.forOfIndex = 0; 
}

return "forOf" + this.forOfIndex++;

};

ForOfStatement.resetVariableNames = () -> {

this.forOfIndex = 0;

};

exports.ForOfStatement = ForOfStatement;