package ast;

import java.util.ArrayList;
import java.util.List;

/**
 * Represents a method invocation in AST (Abstract Syntax Tree)
 *
 * @author s-yamagiwa
 * @apiNote Type arguments aren't supported because it isn't necessary in DTRAM code generator.
 */
public class MethodInvocation extends Expression {
	/**
	 * The receiver expression of the invocation
	 * defaults to {@code null}
	 */
	private Expression receiver;
	
	/**
	 * The method name to be called by this invocation
	 */
	private String methodName;
	
	/**
	 * All arguments used in the called method
	 */
	private List<Expression> arguments;
	
	public MethodInvocation(String methodName) {
		this(null, methodName);
	}
	
	public MethodInvocation(Expression receiver, String methodName) {
		this(receiver, methodName, List.of());
	}
	
	public MethodInvocation(Expression receiver, String methodName, List<Expression> arguments) {
		this.receiver = receiver;
		this.methodName = methodName;
		this.arguments = arguments;
	}
	
	@Override
	public Expression replace(Variable variable, Expression expression) {
		List<Expression> replacedExpressions = new ArrayList<>();
		
		for (Expression argument : arguments) {
			replacedExpressions.add(argument.replace(variable, expression));
		}
		
		if (receiver == null) {
			return new MethodInvocation(null, methodName, replacedExpressions);
		}
		
		return new MethodInvocation(receiver.replace(variable, expression), methodName, replacedExpressions);
	}
	
	public Expression getReceiver() {
		return receiver;
	}
	
	public void setReceiver(Expression receiver) {
		this.receiver = receiver;
	}
	
	public String getMethodName() {
		return methodName;
	}
	
	public void setMethodName(String methodName) {
		this.methodName = methodName;
	}
	
	public List<Expression> getArguments() {
		return arguments;
	}
	
	public void setArguments(List<Expression> arguments) {
		this.arguments = arguments;
	}
	
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		if (receiver != null) {
			builder.append(receiver.toString()).append(".");
		}
		
		builder.append(methodName).append("(");
		
		if (arguments != null && !arguments.isEmpty()) {
			for (int i = 0; i < arguments.size(); i++) {
				Expression argument = arguments.get(i);
				
				builder.append(argument.toString());
				
				if (i < arguments.size() - 1) {
					builder.append(", ");
				}
			}
		}
		
		builder.append(")");
		
		return builder.toString();
	}
}
