use :node;

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

fn CaseClause(tests, body)

extends Node {

this.type = 'CaseClause';

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

this.tests = tests;
if this.tests? {
  for test in this.tests {
    test.parent = this;
  }
}

}

CaseClause.prototype.codegen = (branchFallthrough) -> {

if !super.codegen() {
  return;
}

if !this.tests? and !branchFallthrough {
  return this.body.codegen();
}

this.type = "IfStatement";
this.switchCase = true;

var rangeError = false;

if this.tests? {
  for test in this.tests {
    var equalsToDiscriminant;

    if test.type == "Range" {
      var fromCheck;
      if test.start {
        fromCheck = {
          "type": "BinaryExpression",
          "operator": ">=",
          "left": this.parent.discriminant,
          "right": test.start
        };
      }

      var toCheck;
      if test.to {
        toCheck = {
          "type": "BinaryExpression",
          "operator": "<" + ("=" if test.operator == ".." else ""),
          "left": this.parent.discriminant,
          "right": test.to
        };
      }

      if fromCheck && toCheck {
        equalsToDiscriminant = {
          "type": "LogicalExpression",
          "operator": "&&",
          "left": fromCheck,
          "right": toCheck
        };
      } else if fromCheck || toCheck {
        equalsToDiscriminant = fromCheck ?? toCheck;
      } else {
        rangeError = test;
        break;
      }
    } else if test.type == "ArrayExpression" {
      test = test.codegen();

      equalsToDiscriminant = {
        "type": "BinaryExpression",
        "operator": ">=",
        "left": {
          "type": "MemberExpression",
          "computed": false,
          "object": this.parent.discriminant,
          "property": {
            "type": "Identifier",
            "name": "length"
          }
        },
        "right": {
          "type": "Literal",
          "value": test.elements.length
        }
      };

      for element, i in test.elements {
        if element? {
          equalsToDiscriminant = {
            "type": "LogicalExpression",
            "operator": "&&",
            "left": equalsToDiscriminant,
            "right": {
              "type": "BinaryExpression",
              "operator": "===",
              "left": {
                "type": "MemberExpression",
                "computed": true,
                "object": this.parent.discriminant,
                "property": {
                  "type": "Literal",
                  "value": i
                }
              },
              "right": element
            }
          };
        }
      }
    } else {
      equalsToDiscriminant = {
        "type": "BinaryExpression",
        "operator": "===",
        "left": this.parent.discriminant,
        "right": test.codegen()
      };
    }

    if !this.test {
      this.test = equalsToDiscriminant;
    } else {
      this.test = {
        "type": "LogicalExpression",
        "operator": "||",
        "left": this.test,
        "right": equalsToDiscriminant
      };
    }
  }
}

if rangeError {
  Node.getErrorManager().error({
    type: "EmptyRange",
    message: "empty range in case clause is disallowed.",
    loc: rangeError.loc
  });

  return null;
}

this.consequent = this.body.codegen();

if branchFallthrough {
  var fallthroughTest = {
    "type": "BinaryExpression",
    "left": this.parent.fallthroughId,
    "operator": "<",
    "right": {
      "type": "Literal",
      "value": 2
    }
  };

  if !this.tests? {
    this.test = fallthroughTest;
  } else {
    this.test = {
      "type": "LogicalExpression",
      "operator": "&&",
      "left": fallthroughTest,
      "right": this.test
    };
  }
} 

this.alternate = null;

return this;

};

exports.CaseClause = CaseClause;