/**
  *
  *                      OOAS Compiler
  *
  *       Copyright 2015, AIT Austrian Institute of Technology.
  * This code is based on the C# Version of the OOAS Compiler, which is
  * copyright 2015 by the Institute of Software Technology, Graz University
  * of Technology with portions copyright by the AIT Austrian Institute of
  * Technology. All rights reserved.
  *
  * SEE THE "LICENSE" FILE FOR THE TERMS UNDER WHICH THIS FILE IS PROVIDED.
  *
  * If you modify the file please update the list of contributors below to in-
  * clude your name. Please also stick to the coding convention of using TABs
  * to do the basic (block-level) indentation and spaces for anything after
  * that. (Enable the display of special chars and it should be pretty obvious
  * what this means.) Also, remove all trailing whitespace.
  *
  * Contributors:
  *               Willibald Krenn (AIT)
  *               Stephan Zimmerer (AIT)
  *               Markus Demetz (AIT)
  *               Christoph Czurda (AIT)
  *
  */


package org.momut.ooas.visitors;

import java.util.Stack;

import org.momut.ooas.ast.expressions.Expression;
import org.momut.ooas.ast.expressions.ExpressionKind;
import org.momut.ooas.ast.expressions.IdentifierExpression;
import org.momut.ooas.ast.identifiers.IdentifierKind;
import org.momut.ooas.ast.identifiers.MethodIdentifier;
import org.momut.ooas.ast.statements.Assignment;
import org.momut.ooas.ast.types.FunctionType;
import org.momut.ooas.ast.types.OoActionSystemType;
import org.momut.ooas.parser.ParserMessage;
import org.momut.ooas.parser.ParserState;

/// <summary>
/// This visitor scans all methods and decides whether they are pure, i.e. there is no state-update.
/// </summary>
public final class OoaMethodPureClassifierVisitor extends OoaCompleteAstTraversalVisitor
{

	Stack<MethodIdentifier> currentMethod = new Stack<MethodIdentifier>();

	@Override
	public void visit(MethodIdentifier methodIdentifier)
	{
		currentMethod.push(methodIdentifier);
		((FunctionType)currentMethod.peek().type()).SetIsPureFunction(true); // assume is true..

		super.visit(currentMethod.peek());

		if (((FunctionType)currentMethod.peek().type()).isPureFunction())
		{
			m_ParserState.AddMessage(
					new ParserMessage(m_ParserState.filename, methodIdentifier.line(),
							methodIdentifier.column(), String.format("Found pure method: %s",
									methodIdentifier.tokenText())));
		} else
			m_ParserState.AddMessage(
					new ParserMessage(m_ParserState.filename, methodIdentifier.line(),
							methodIdentifier.column(), String.format("Found extended method: %s",
									methodIdentifier.tokenText())));

		currentMethod.pop();
	}

	@Override
	public void visit(OoActionSystemType systemType)
	{
		boolean functionPure = false; //introduce variable with save value
		if (currentMethod.size() > 0 && currentMethod.peek() != null) //if we are determining the pureness...
		{
			functionPure = ((FunctionType)currentMethod.peek().type()).isPureFunction(); //...save the current value
		}
		super.visit(systemType); // go down in recursion
		if ( currentMethod.size() > 0 && currentMethod.peek() != null) //but restore old pureness!
		{
			((FunctionType)currentMethod.peek().type()).SetIsPureFunction(functionPure);
		}
	}


	@Override
	public void visit(Assignment assignment)
	{

		boolean assignmentPure = true;
		if (currentMethod.size() > 0 && currentMethod.peek() != null)
		{
			for (Expression x: assignment.places())
			{
				if (x.kind() != ExpressionKind.Identifier)
					assignmentPure = false;
				else if (((IdentifierExpression)x).identifier().kind() == IdentifierKind.AttributeIdentifier)
					assignmentPure = false;
			}
			boolean functionPure = assignmentPure && ((FunctionType)currentMethod.peek().type()).isPureFunction();
			((FunctionType)currentMethod.peek().type()).SetIsPureFunction(functionPure);
		}
		super.visit(assignment);
	}



	public OoaMethodPureClassifierVisitor(ParserState aState)
	{
		super (aState);
	}
}
