package org.jakstab.analysis.rd;

import java.util.Collections;
import java.util.Set;

import org.jakstab.AnalysisProperties;
import org.jakstab.analysis.*;
import org.jakstab.cfa.CFAEdge;
import org.jakstab.cfa.Location;
import org.jakstab.rtl.statements.*;
import org.jakstab.util.Logger;

/**
 * Demo analysis for classroom use.
 * 
 * Template for a reaching definitions analysis based on the CPA framework. All methods that need to
 * be implemented are marked with TODO.  
 */
public class ReachingDefinitionsAnalysis extends SimpleCPA implements ConfigurableProgramAnalysis {

	private static final Logger logger = Logger.getLogger(ReachingDefinitionsAnalysis.class);
	
	public static void register(AnalysisProperties p) {
		// This registers the analysis with the framework
		p.setShortHand('r');
		p.setName("Reaching definitions analysis");
		p.setDescription("For each program point, calculate the set of variable definitions that reach it.");
		p.setExplicit(false);
	}

	@Override
	public AbstractState initStartState(Location location) {
		// TODO Return the initial state for a program entry location "label" here.
		return new RDState(); // Dummy
	}

	@Override
	public AbstractState merge(AbstractState s1, AbstractState s2) {
		// TODO Implement the merge operator
		return s2; // Dummy
	}

	@Override
	public Set<AbstractState> post(AbstractState state, CFAEdge edge) {
		// TODO Implement the abstract transfer relation.
		
		// Read statement from control flow edge
		RTLStatement statement = (RTLStatement)edge.getTransformer();
		// Cast the current abstract state to it's type
		final RDState curState = (RDState)state;
		
		// Calculate the set of abstract successors using a visitor pattern
		// The DefaultStatementVisitor throws exceptions on every not overridden visit method
		Set<AbstractState> abstractSuccessors = statement.accept(new DefaultStatementVisitor<Set<AbstractState>>() {

			@Override
			protected Set<AbstractState> visitDefault(RTLStatement stmt) {
				// Just return the same state for unsupported statements.
				return Collections.singleton((AbstractState)curState);
			}

			@Override
			public Set<AbstractState> visit(RTLVariableAssignment stmt) {
				// TODO Implement transfer function for assignments
				logger.info("Processing assignment at " + stmt.getLabel() + ": " + stmt.toString());
				return Collections.singleton((AbstractState)curState); // Dummy
			}

			@Override
			public Set<AbstractState> visit(RTLAssume stmt) {
				// TODO Implement transfer function for assume
				logger.info("Processing assume at " + stmt.getLabel() + ": " + stmt.toString());
				return Collections.singleton((AbstractState)curState); // Dummy
			}

		});
		
		return abstractSuccessors;
	}

	@Override
	public boolean stop(AbstractState s, ReachedSet reached) {
		// TODO Implement stop operator
		// You can use the following template, but since
		// lessOrEqual in RDState currently always returns
		// false, the analysis would never terminate.
//		for (AbstractState a : reached) {
//			if (s.lessOrEqual(a)) {
//				return true;
//			}
//		}
//		return false;

		return true; // Dummy
	}
}
