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

import org.momut.ooas.ast.AstNodeTypeEnum;
import org.momut.ooas.ast.IAst;
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.MainModule;
import org.momut.ooas.ast.identifiers.MethodIdentifier;
import org.momut.ooas.ast.identifiers.Module;
import org.momut.ooas.ast.identifiers.NamedActionIdentifier;
import org.momut.ooas.ast.identifiers.NondetIdentifierList;
import org.momut.ooas.ast.identifiers.ParameterIdentifier;
import org.momut.ooas.ast.identifiers.PrioIdentifierList;
import org.momut.ooas.ast.identifiers.SelfTypeIdentifier;
import org.momut.ooas.ast.identifiers.SeqIdentifierList;
import org.momut.ooas.ast.identifiers.TypeIdentifier;
import org.momut.ooas.ast.identifiers.UnspecIdentifierList;
import org.momut.ooas.ast.types.EnumType;
import org.momut.ooas.ast.types.FunctionType;
import org.momut.ooas.ast.types.ListType;
import org.momut.ooas.ast.types.TypeKind;
import org.momut.ooas.ast.types.Type;
import org.momut.ooas.codegen.OoasCodeEmitter;
import org.momut.ooas.visitors.OoaCompleteAstTraversalVisitor;

/// <summary>
/// Knows how to construct a C-CADP identifier from an AST-Identifier
/// (enums, attributes, variables, parameters supported)
/// </summary>
public final class CadpIdentifier extends OoaCompleteAstTraversalVisitor
{
	private final OoasCodeEmitter m_emitter = new OoasCodeEmitter();
	private final String m_stateVariablePrefix;

	/// <summary>
	/// enums are mapped to ints, so an enum identifier simply gets an integer.
	/// </summary>
	@Override
	public  void visit(EnumIdentifier enumIdentifier)
	{
		if (enumIdentifier.HaveValue())
		{
			m_emitter.Append(enumIdentifier.Value());
			m_emitter.Append(" /* ");
			m_emitter.Append(enumIdentifier.tokenText());
			m_emitter.Append(" */ ");
		}
		else
		{
			final EnumType anEnum = (EnumType)enumIdentifier.type();
			m_emitter.Append(anEnum.listOfEnumSymbols().indexOf(enumIdentifier));
			m_emitter.Append(" /* ");
			m_emitter.Append(enumIdentifier.tokenText());
			m_emitter.Append(" */ ");
		}
	}

	@Override
	public  void visit(AttributeIdentifier attributeIdentifier)
	{
		if (m_stateVariablePrefix != null && !m_stateVariablePrefix.equals(""))
		{
			m_emitter.Append(m_stateVariablePrefix);
			m_emitter.Append("->");
		}
		m_emitter.Append(attributeIdentifier.tokenText());
	}
	@Override
	public  void visit(ExpressionVariableIdentifier expressionVariableIdentifier)
	{
		// expression vars are local..
		m_emitter.Append(expressionVariableIdentifier.tokenText());
	}
	@Override
	public  void visit(ParameterIdentifier parameterIdentifier)
	{
		/* handed in as parameter to named action, hence no state ref. necessary. */
		if (parameterIdentifier.tokenText().equals("result"))
			m_emitter.Append(String.format("*param_%1$s", parameterIdentifier.tokenText()));
		else
			m_emitter.Append(String.format("param_%1$s", parameterIdentifier.tokenText()));
	}
	@Override
	public  void visit(LocalVariableIdentifier localVariableIdentifier)
	{
		m_emitter.Append(localVariableIdentifier.tokenText());
	}
	@Override
	public  void visit(TypeIdentifier typeIdentifier)
	{
		m_emitter.Append("aType_");
		if (typeIdentifier.type().kind() == TypeKind.ListType)
		{
			m_emitter.Append("list_");
			final ListType alist = (ListType)typeIdentifier.type();
			if (alist.maxNumberOfElements() >= 0)
				m_emitter.Append(String.format("%1$s_", alist.maxNumberOfElements()));
			else
				m_emitter.Append(String.format("dyn_", alist.maxNumberOfElements()));

			visit(alist.innerType().identifier());
		}
		else if (typeIdentifier.type().kind() == TypeKind.FunctionType)
		{
			final FunctionType funType = (FunctionType) typeIdentifier.type();
			m_emitter.Append(typeIdentifier.tokenText());
			for (final Type x : funType.parameter())
			{
				m_emitter.Append("_");
				m_emitter.Append(x.toString());
			}
			if (funType.returnType() != null)
			{
				m_emitter.Append("__");
				m_emitter.Append(funType.returnType().toString());
			}
		}
		else
			m_emitter.Append(typeIdentifier.tokenText());
	}

	@Override
	public  void visit(SelfTypeIdentifier aself)
	{
		m_emitter.Append(aself.tokenText());
	}

	@Override
	public  void visit(MethodIdentifier methodIdentifier)
	{
		m_emitter.Append(methodIdentifier.tokenText());
	}
	@Override
	public  void visit(NamedActionIdentifier namedActionIdentifier)
	{
		m_emitter.Append(namedActionIdentifier.tokenText());
	}
	@Override
	public  void visit(MainModule mainModule)
	{
		throw new UnsupportedOperationException();
	}
	@Override
	public  void visit(Module module)
	{
		throw new UnsupportedOperationException();
	}
	@Override
	public  void visit(NondetIdentifierList nondetIdentifierList)
	{
		throw new UnsupportedOperationException();
	}
	@Override
	public  void visit(SeqIdentifierList seqIdentifierList)
	{
		throw new UnsupportedOperationException();
	}
	@Override
	public  void visit(PrioIdentifierList prioIdentifierList)
	{
		throw new UnsupportedOperationException();
	}
	@Override
	public  void visit(UnspecIdentifierList unspecIdentifierList)
	{
		throw new UnsupportedOperationException();
	}

	@Override
	protected  void VisitAstElement(IAst element, IAst parent)
	{
		if (element.nodeType() == AstNodeTypeEnum.identifier)
			super.VisitAstElement(element, parent);
	}

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

	public CadpIdentifier(String stateVariablePrefix)
	{
		super(null);
		m_stateVariablePrefix = stateVariablePrefix;
	}


	public static String GetIdentifierString(TypeIdentifier typeIdentifier)
	{
		final CadpIdentifier ident = new CadpIdentifier("");
		ident.visit(typeIdentifier);
		return ident.toString();
	}
	public static String GetIdentifierString(ParameterIdentifier aParam)
	{
		final CadpIdentifier anid = new CadpIdentifier("");
		anid.visit(aParam);
		return anid.toString();
	}
	public static Object GetIdentifierString(Identifier x)
	{
		final CadpIdentifier anid = new CadpIdentifier(OoaCADPVisitor.StateVariablePrefix);
		x.Accept(anid);
		return anid.toString();
	}
}
