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

import org.momut.ooas.ast.identifiers.AttributeIdentifier;
import org.momut.ooas.ast.identifiers.EnumIdentifier;
import org.momut.ooas.ast.identifiers.ExpressionVariableIdentifier;
import org.momut.ooas.ast.identifiers.Identifier;
import org.momut.ooas.ast.identifiers.LocalVariableIdentifier;
import org.momut.ooas.ast.identifiers.MethodIdentifier;
import org.momut.ooas.ast.identifiers.NamedActionIdentifier;
import org.momut.ooas.ast.identifiers.ParameterIdentifier;
import org.momut.ooas.ast.identifiers.TypeIdentifier;
import org.momut.ooas.ast.types.FloatType;
import org.momut.ooas.ast.types.IntType;
import org.momut.ooas.codegen.OoasCodeEmitter;
import org.momut.ooas.utils.exceptions.NotImplementedException;
import org.momut.ooas.visitors.OoaIdentifierVisitor;

public final class OoaPrologIdentifier extends OoaIdentifierVisitor
{
	public static class Factory
	{
		public OoaPrologIdentifier create() { return new OoaPrologIdentifier(); }
	}


	OoasCodeEmitter m_emitter;

	private String getUniquePostFix(Identifier id) {
		return (id.line() > 0) && (id.column()>0)
				? String.format("%s_%s", id.line(), id.column())
				: Integer.toString(id.hashCode()).replace("-", "m");
	}

	@Override
	public void visit(EnumIdentifier enumIdentifier)
	{
		assert(false); // handled in visit(IdentifierExpression identifierExpression)
		//AddTokenText(enumIdentifier);
	}

	@Override
	public void visit(AttributeIdentifier attributeIdentifier)
	{
		m_emitter.Append(String.format("attr_%s_%s", attributeIdentifier.tokenText(), getUniquePostFix(attributeIdentifier)));
	}

	@Override
	public void visit(ExpressionVariableIdentifier expressionVariableIdentifier)
	{
		m_emitter.Append(String.format("ExprVar_%s_%s", expressionVariableIdentifier, getUniquePostFix(expressionVariableIdentifier)));
	}

	@Override
	public void visit(ParameterIdentifier parameterIdentifier)
	{
		if (parameterIdentifier.tokenText().equals("result"))
			m_emitter.Append("RESULT"); // methods are transformed into their own predicates, so they have their own scope..
		else
			m_emitter.Append(String.format("_%s_%s", parameterIdentifier.tokenText(), getUniquePostFix(parameterIdentifier)));
	}

	@Override
	public void visit(LocalVariableIdentifier localVariableIdentifier)
	{
		m_emitter.Append(String.format("_%s_%s",
				localVariableIdentifier.tokenText(), getUniquePostFix(localVariableIdentifier)));
	}

	@Override
	public void visit(TypeIdentifier typeIdentifier)
	{
		switch (typeIdentifier.type().kind())
		{
		case Any:          // not supported
		case Null:         // must have some type
			throw new NotImplementedException();

		case OpaqueType:   // must be resolved at this point in time
		case FunctionType: // we do not support declaration of function types
			assert(false);
			throw new NotImplementedException();

		case FloatType:
			final FloatType afloat = (FloatType)typeIdentifier.type();
			m_emitter.Append(String.format("float_%s_%s_%s", afloat.low(), afloat.high(), afloat.precision()));
			break;
		case IntType:
			final IntType intType = (IntType)typeIdentifier.type();
			m_emitter.Append(String.format("%s", intType.identifier().tokenText().toLowerCase().replace("-", "")));
			break;

		case BoolType:
			m_emitter.Append("bool");
			break;

		case EnumeratedType:
			m_emitter.Append(String.format("enum_%s%s", typeIdentifier.prefix, typeIdentifier.tokenText()));
			break;

		case TupleType:
			m_emitter.Append(String.format("tuple_%s%s", typeIdentifier.prefix, typeIdentifier.tokenText()));
			break;

		case ListType:
			m_emitter.Append(String.format("list_%s%s", typeIdentifier.prefix, typeIdentifier.tokenText()));
			break;

		case MapType:
			throw new NotImplementedException();

		case OoActionSystemType:
			m_emitter.Append(String.format("'%s'", typeIdentifier.tokenText()));
			//AddTokenText(typeIdentifier);
			break;

		default:
			throw new NotImplementedException();
		}

	}

	@Override
	public void visit(MethodIdentifier methodIdentifier)
	{
		m_emitter.Append(String.format("'%s'", methodIdentifier.tokenText()));
	}

	@Override
	public void visit(NamedActionIdentifier namedActionIdentifier)
	{
		m_emitter.Append(String.format("'%s'", namedActionIdentifier.tokenText()));
	}


	@Override
	public String toString()
	{
		return m_emitter.toString();
	}

	private OoaPrologIdentifier()
	{
		m_emitter = new OoasCodeEmitter();
	}
}
