var AST = require('./program');

var err = 'Assignment is only possible on variables or properties.',
	posterr = 'Only the literal 1 is possible for post assignments.',
	assignableOps = /[\+\-\*\/\%]/;

AST.Assignment = function(left, right){
	if (!(left instanceof AST.Variable || left instanceof AST.Property)) throw new Error(err);
	this.left = left;
	this.right = AST.Expression(right);
};

AST.Assignment.prototype = new AST.Expression();

AST.Assignment.prototype.writeTo = function(writer, format){
	var left = this.left, right = this.right;

	left.writeTo(writer, format);

	if (right instanceof AST.Operator && right.left === left && assignableOps.test(right.operator)){
		if (right.right instanceof AST.Literal && right.right.value == 1){
			if (right.operator == '+'){
				writer('++');
				return;
			} else if (right.operator == '-'){
				writer('--');
				return;
			}
		}
		writer(' ' + right.operator + '= ');
		right = right.right;
	} else {
		writer(' = ');
	}
	right.writeTo(writer, format);
};

AST.PostAssignment = function(left, right, operator){
	if (!(left instanceof AST.Variable || left instanceof AST.Property)) throw new Error(err);
	this.left = left;
	this.operator = operator;
	this.right = AST.Expression(right);
	if (!(this.right instanceof AST.Operator) || this.right.left !== left || !(this.right.right instanceof AST.Literal) || this.right.right.value != 1) throw new Error(posterr);
}

AST.PostAssignment.prototype = new AST.Expression();

AST.PostAssignment.prototype.writeTo = function(writer, format){
	this.expression.writeTo(writer, format);
	writer(this.operator + this.operator);
};

AST.Expression.prototype.assignTo = function(expr){
	return new AST.Assignment(expr, this);
};

AST.Variable.prototype.assign = AST.Property.prototype.assign = function(expr){
	return new AST.Assignment(this, expr);
};

AST.Variable.prototype.increment = AST.Property.prototype.increment = function(){
	return new AST.Assignment(this, new AST.Add(this, 1));
};

AST.Variable.prototype.decrement = AST.Property.prototype.decrement = function(){
	return new AST.Assignment(this, new AST.Subtract(this, 1));
};

AST.Variable.prototype.postIncrement = AST.Property.prototype.postIncrement = function(){
	return new AST.PostAssignment(this, new AST.Add(this, 1));
};

AST.Variable.prototype.postDecrement = AST.Property.prototype.postDecrement = function(){
	return new AST.PostAssignment(this, new AST.Subtract(this, 1));
};