/**
  *
  *                      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.codegen.prologsymbolic;

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

import org.momut.ooas.ast.expressions.AccessExpression;
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.Identifier;
import org.momut.ooas.ast.identifiers.IdentifierKind;
import org.momut.ooas.ast.statements.Assignment;
import org.momut.ooas.ast.statements.SeqBlock;
import org.momut.ooas.ast.statements.Statement;
import org.momut.ooas.codegen.prolog.OoaPrologExpression;
import org.momut.ooas.codegen.prolog.OoaPrologIdentifier;
import org.momut.ooas.codegen.prolog.OoaPrologStatement;
import org.momut.ooas.codegen.prolog.OoaPrologType;
import org.momut.ooas.codegen.prolog.Scratchbook;
import org.momut.ooas.utils.exceptions.NotImplementedException;

public class OoaPrologSymbolicStatement extends OoaPrologStatement
{
	public static class Factory extends OoaPrologStatement.Factory
	{
		@Override
		public /*override*/ OoaPrologStatement create(
				OoaPrologExpression.Factory exprFactory,
				OoaPrologIdentifier.Factory idFactory,
				OoaPrologType.Factory typeFactory,
				Scratchbook scratchbook)
		{
			return new OoaPrologSymbolicStatement(exprFactory, idFactory, typeFactory, scratchbook);
		}
	}

	@Override
	public /*override*/ void visit(Assignment assignment)
	{
		if (assignment.nondetExpression() != null)
			throw new NotImplementedException();

		final Iterator<Expression> aPlaceIt = assignment.places().iterator();
		final Iterator<Expression> aValueIt = assignment.values().iterator();
		final ArrayList<String> assignments = new ArrayList<String>();

		while (aPlaceIt.hasNext())
		{
			final Expression aPlace = aPlaceIt.next();
			final Expression aValue = aValueIt.next();

			final OoaPrologExpression prologPlace = createExpressionVisitor(true);
			aPlace.Accept(prologPlace);
			assert(prologPlace.tmpVariables().size() == 1);

			final OoaPrologExpression prologValue = createExpressionVisitor();
			aValue.Accept(prologValue);
			assert(prologValue.tmpVariables().size() == 1);

			m_emitter.Append(prologValue.toString());

			if (aPlace.kind() == ExpressionKind.Access &&
					((AccessExpression)aPlace).right().kind() == ExpressionKind.Identifier &&
					((IdentifierExpression)((AccessExpression)aPlace).right()).identifier().kind() == IdentifierKind.AttributeIdentifier)
			{
				//access to attribute is always 'self.XY'...
				assignments.add(String.format("%s := %s", prologPlace.tmpVariables().get(0), prologValue.tmpVariables().get(0)));
			}
			else
				if (prologPlace.tmpVariables().get(0).equals("RESULT"))
					assignments.add(String.format("unify( RESULT = %s)", prologValue.tmpVariables().get(0)));
				else
					assignments.add(String.format("%s = %s", prologPlace.tmpVariables().get(0), prologValue.tmpVariables().get(0)));

			if (prologPlace.toString().length() > 0)
			{
				String place = prologPlace.toString();
				place = place.trim();
				if (place.endsWith(","))
					place = place.substring(0, place.length() - 1);

				assignments.add(place);
			}
		}

		int pos = 0;
		for (final String s: assignments)
		{
			if (pos != 0)
				m_emitter.Append(",");
			pos++;
			m_emitter.Append(s);
		}
	}

	@Override
	public /*override*/ void visit(SeqBlock seqBlock)
	{
		int y = 0;
		if (seqBlock.symbols().symbolList().size() > 0)
		{
			m_emitter.Append(" [");
			for (final Identifier sym: seqBlock.symbols().symbolList())
			{
				if (y != 0)
					m_emitter.AppendLine(", ");
				else
					y++;

				final OoaPrologType atype = createTypeVisitor();
				sym.type().Accept(atype);
				final OoaPrologIdentifier anIdent = createIdentifierVisitor();
				sym.Accept(anIdent);
				m_emitter.Append(String.format("%s:%s", anIdent.toString(), atype.toString()));
			}
			m_emitter.Append("]: ( ");
		}

		y = 0;
		for (final Statement x: seqBlock.statements())
		{
			if (y != 0)
				m_emitter.AppendLine(", ");
			else
				y++;
			m_emitter.Append("(");
			VisitSub(x, seqBlock);
			m_emitter.Append(")");
		}

		if (seqBlock.symbols().symbolList().size() > 0)
			m_emitter.Append(")");
	}


	protected OoaPrologSymbolicStatement(
			OoaPrologExpression.Factory exprFactory,
			OoaPrologIdentifier.Factory idFactory,
			OoaPrologType.Factory typeFactory,
			Scratchbook scratchbook)
	{
		super (exprFactory, idFactory, typeFactory, scratchbook);
	}
}
