package de.dhbwstuttgart.bytecode.utilities;

import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.syntaxtree.statement.*;

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

import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
import de.dhbwstuttgart.syntaxtree.FormalParameter;
import de.dhbwstuttgart.syntaxtree.ParameterList;
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
import de.dhbwstuttgart.syntaxtree.statement.Literal;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;

public class KindOfLambda implements StatementVisitor{
	private ParameterList params;
	private boolean isInstanceCapturingLambda = false;
	private List<RefTypeOrTPHOrWildcardOrGeneric> argumentList = new ArrayList<>();
	private ArrayList<String> usedVars = new ArrayList<>();
	private boolean hasThis = false;
	private ArrayList<String> definedLocals = new ArrayList<>();
	
	public KindOfLambda(LambdaExpression lambdaExpression) {
		this.params = lambdaExpression.params;
		lambdaExpression.methodBody.accept(this);
		
	}
	
	public ArrayList<String> getUsedVars() {
		return usedVars;
	}
	
	public boolean isInstanceCapturingLambda() {
		return this.isInstanceCapturingLambda;
	}
	
	public List<RefTypeOrTPHOrWildcardOrGeneric> getArgumentList() {
		return argumentList;
	}
	
	public boolean isHasThis() {
		return hasThis;
	}
	
	@Override
	public void visit(ArgumentList argumentList) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void visit(LambdaExpression lambdaExpression) {
		
	}

	@Override
	public void visit(Assign assign) {
		assign.rightSide.accept(this);
	}

	@Override
	public void visit(BinaryExpr binary) {
		binary.lexpr.accept(this);
		binary.rexpr.accept(this);
	}

	@Override
	public void visit(Block block) {
		for(Statement stmt : block.getStatements()) {
			stmt.accept(this);
		}
	}

	@Override
	public void visit(CastExpr castExpr) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void visit(EmptyStmt emptyStmt) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void visit(FieldVar fieldVar) {
		fieldVar.receiver.accept(this);
	}

	@Override
	public void visit(ForStmt forStmt) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void visit(IfStmt ifStmt) {
		ifStmt.expr.accept(this);
		ifStmt.then_block.accept(this);
		ifStmt.else_block.accept(this);
	}

	@Override
	public void visit(InstanceOf instanceOf) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void visit(LocalVar localVar) {
		if(!contain(params, localVar.name) && !definedLocals.contains(localVar.name)) {
			argumentList.add(localVar.getType());
			if(hasThis) {
				usedVars.add(1, localVar.name);
			} else {
				usedVars.add(0, localVar.name);
			}
			if(!isInstanceCapturingLambda)
				isInstanceCapturingLambda=true;
		}
	}

	private boolean contain(ParameterList params2, String name) {
		Iterator<FormalParameter> itr = params2.iterator();
		while(itr.hasNext()) {
			FormalParameter fp = itr.next();
			if(fp.getName().equals(name))
				return true;
		}
		return false;
	}

	@Override
	public void visit(LocalVarDecl localVarDecl) {
		definedLocals.add(localVarDecl.getName());
	}

	@Override
	public void visit(MethodCall methodCall) {
		methodCall.receiver.accept(this);
	}

	@Override
	public void visit(NewClass methodCall) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void visit(NewArray newArray) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void visit(ExpressionReceiver receiver) {
		receiver.expr.accept(this);
	}

	@Override
	public void visit(UnaryExpr unaryExpr) {
		
	}

	@Override
	public void visit(Return aReturn) {
		aReturn.retexpr.accept(this);
	}

	@Override
	public void visit(ReturnVoid aReturn) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void visit(StaticClassName staticClassName) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void visit(Super aSuper) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void visit(This aThis) {
		if(!hasThis) {
			hasThis = true;
			this.argumentList.add(0,aThis.getType());
		}
		if(!isInstanceCapturingLambda) {
			this.isInstanceCapturingLambda = true;
			
		}
	}

	@Override
	public void visit(WhileStmt whileStmt) {
		whileStmt.expr.accept(this);
		whileStmt.loopBlock.accept(this);
		
	}

	@Override
	public void visit(DoStmt whileStmt) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void visit(Literal literal) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void visit(AssignToField assignLeftSide) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void visit(AssignToLocal assignLeftSide) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void visit(SuperCall superCall) {
		// TODO Auto-generated method stub
		
	}
}
