package gr.uom.java.ast.decomposition;

import gr.uom.java.ast.MethodInvocationObject;
import gr.uom.java.ast.decomposition.cfg.AbstractVariable;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;

import org.eclipse.jdt.core.dom.Statement;

public class TryStatementObject extends CompositeStatementObject {
	private List<CatchClauseObject> catchClauses;
	private CompositeStatementObject finallyClause;
	
	public TryStatementObject(Statement statement, AbstractMethodFragment parent) {
		super(statement, StatementType.TRY, parent);
		this.catchClauses = new ArrayList<CatchClauseObject>();
	}

	public List<AbstractStatement> getStatementsInsideTryBlock() {
		CompositeStatementObject tryBlock = (CompositeStatementObject)getStatements().get(0);
		return tryBlock.getStatements();
	}

	public boolean hasResources() {
		return !super.getExpressions().isEmpty();
	}

	public void addCatchClause(CatchClauseObject catchClause) {
		catchClauses.add(catchClause);
		catchClause.setParent(this);
	}

	public List<CatchClauseObject> getCatchClauses() {
		return catchClauses;
	}

	public void setFinallyClause(CompositeStatementObject finallyClause) {
		this.finallyClause = finallyClause;
	}

	public CompositeStatementObject getFinallyClause() {
		return finallyClause;
	}

	public List<AbstractExpression> getExpressions() {
		List<AbstractExpression> expressions = new ArrayList<AbstractExpression>();
		expressions.addAll(super.getExpressions());
		for(CatchClauseObject catchClause : catchClauses) {
			expressions.addAll(catchClause.getExpressions());
		}
		return expressions;
	}

	public List<String> stringRepresentation() {
		List<String> stringRepresentation = new ArrayList<String>();
		stringRepresentation.addAll(super.stringRepresentation());
		for(CatchClauseObject catchClause : catchClauses) {
			stringRepresentation.addAll(catchClause.stringRepresentation());
		}
		if(finallyClause != null) {
			stringRepresentation.addAll(finallyClause.stringRepresentation());
		}
		return stringRepresentation;
	}

	public List<CompositeStatementObject> getIfStatements() {
		List<CompositeStatementObject> ifStatements = new ArrayList<CompositeStatementObject>();
		ifStatements.addAll(super.getIfStatements());
		for(CatchClauseObject catchClause : catchClauses) {
			ifStatements.addAll(catchClause.getIfStatements());
		}
		if(finallyClause != null) {
			ifStatements.addAll(finallyClause.getIfStatements());
		}
		return ifStatements;
	}

	public List<CompositeStatementObject> getSwitchStatements() {
		List<CompositeStatementObject> switchStatements = new ArrayList<CompositeStatementObject>();
		switchStatements.addAll(super.getSwitchStatements());
		for(CatchClauseObject catchClause : catchClauses) {
			switchStatements.addAll(catchClause.getSwitchStatements());
		}
		if(finallyClause != null) {
			switchStatements.addAll(finallyClause.getSwitchStatements());
		}
		return switchStatements;
	}

	public List<TryStatementObject> getTryStatements() {
		List<TryStatementObject> tryStatements = new ArrayList<TryStatementObject>();
		tryStatements.addAll(super.getTryStatements());
		for(CatchClauseObject catchClause : catchClauses) {
			tryStatements.addAll(catchClause.getTryStatements());
		}
		if(finallyClause != null) {
			tryStatements.addAll(finallyClause.getTryStatements());
		}
		return tryStatements;
	}
	
	public boolean hasFinallyClauseClosingVariable(AbstractVariable variable) {
		if(finallyClause != null) {
			Map<AbstractVariable, LinkedHashSet<MethodInvocationObject>> invokedMethodsThroughLocalVariables = 
					finallyClause.getInvokedMethodsThroughLocalVariables();
			for(AbstractVariable key : invokedMethodsThroughLocalVariables.keySet()) {
				if(key.equals(variable)) {
					LinkedHashSet<MethodInvocationObject> methodInvocations = invokedMethodsThroughLocalVariables.get(key);
					for(MethodInvocationObject methodInvocation : methodInvocations) {
						if(methodInvocation.getMethodName().equals("close")) {
							return true;
						}
					}
				}
			}
			Map<AbstractVariable, LinkedHashSet<MethodInvocationObject>> invokedMethodsThroughParameters = 
					finallyClause.getInvokedMethodsThroughParameters();
			for(AbstractVariable key : invokedMethodsThroughParameters.keySet()) {
				if(key.equals(variable)) {
					LinkedHashSet<MethodInvocationObject> methodInvocations = invokedMethodsThroughParameters.get(key);
					for(MethodInvocationObject methodInvocation : methodInvocations) {
						if(methodInvocation.getMethodName().equals("close")) {
							return true;
						}
					}
				}
			}
			Map<AbstractVariable, LinkedHashSet<MethodInvocationObject>> invokedMethodsThroughFields = 
					finallyClause.getInvokedMethodsThroughFields();
			for(AbstractVariable key : invokedMethodsThroughFields.keySet()) {
				if(key.equals(variable)) {
					LinkedHashSet<MethodInvocationObject> methodInvocations = invokedMethodsThroughFields.get(key);
					for(MethodInvocationObject methodInvocation : methodInvocations) {
						if(methodInvocation.getMethodName().equals("close")) {
							return true;
						}
					}
				}
			}
		}
		return false;
	}

	public boolean hasCatchClause() {
		return !catchClauses.isEmpty();
	}
}
