/* $Id$
 *
 * Normalize association lists.
 *
 * Copyright (C) 2008-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#ifndef __NORMALIZE_ASSOC_LISTS_HPP_INCLUDED
#define __NORMALIZE_ASSOC_LISTS_HPP_INCLUDED

#include "frontend/visitor/NullVisitor.hpp"
#include <list>
#include "frontend/ast/Location.hpp"
#include "frontend/misc/DeclarativeRegion.hpp"
#include "frontend/ast/ValDeclaration.hpp"

namespace ast {

//! normalize association lists.
/** This class will reorder association lists into the corresponding
 *  order of the defining port-/parameter-list.
 *  FIXME: what to do with composites? and conversion functions?
 *  FIXME: 
 */
class NormalizeAssocLists : public NullVisitor {
public:
	//! c'tor: initialize members.
	NormalizeAssocLists(
		) : 	pickedUpVal(NULL), 
			pos(-1), 
			positional(true),
			region(NULL),
			arch(NULL),
			hiddenCounter(0) {}

private:
	/** Visit a CompInstStat node.
	 *  @param node CompInstStat node that get's visited.
	 */
	virtual void visit(CompInstStat& node);

	/** Visit a AssociationElement node.
	 *  @param node AssociationElement node that get's visited.
	 */
	virtual void visit(AssociationElement& node);

	/** visit a SimpleName
         *  @param node node that get's visited.
         */
	virtual void visit(SimpleName &node);

	/** visit a TemporaryName
         *  @param node node that get's visited.
         */
	virtual void visit(TemporaryName &node);

	/** visit a SelectedName
         *  @param node node that get's visited.
         */
	virtual void visit(SelectedName &node);

	/** visit a AttributeName
         *  @param node node that get's visited.
         */
	virtual void visit(AttributeName &node);

	/** Visit a Architecture node.
	 *
	 *  @param node Architecture node that get's visited.
	 */
	virtual void visit(Architecture& node);

	/** Visit a Library node.
	 *  @param node Library node that get's visited.
	 */
	virtual void visit(Library &node);

	/** Visit a LibraryList node.
	 *  @param node LibraryList node that get's visited.
	 */
	virtual void visit(LibraryList &node);

	/** find val in formals and return the position. Also remove it from
	 *  from formals and report an error in case val is not in formals.
	 *  @param val ValDeclaration to find/delete in current formals list
	 *  @param loc error location for error reporting.
	 *  @return position number or -1 on error.
	 */
	int findAndRemove(const ValDeclaration *val, Location errLoc);

	/** add associations for unassociated ports of a CompInstStat.
	 *  Reports errors.
	 *  @param node instantiation statement.
	 */
	void addMissingPortAssocs(CompInstStat &node);

	/** add associations for unassociated generics of a CompInstStat.
	 *  Reports errors.
	 *  @param node instantiation statement.
	 */
	void addMissingGenericAssocs(CompInstStat &node);

	/** add associations for unassociated ports/generics of a 
	 *  CompInstStat.
	 *  Reports errors.
	 *  @param node instantiation statement.
	 *  @param unassociated list of unassociated elements.
	 *  @param kind element kind (for error reporting)
	 *  @param symbolType type of symbol when registering hidden symbols.
	 *  @param mapList list of map aspect (generic map, port map).
	 */
	template <typename T>
	void
	addMissingAssocs(
		CompInstStat &node,
		std::list<ValDeclaration*> &unassociated,
		const char *kind,
		enum symType symbolType,
		std::list<AssociationElement*> &mapList);

	/** add one missing association. To be called by addMissingPortAssocs.
	  * Reports errors.
	  * @param loc location for error reporting.
	  * @param formal declaration of the corresponding formal of an open
	  *        association.
	  * @param kind element kind (for reporting errors).
	  * @param symbolType type of symbol when registering hidden symbols.
	  * @param mapList list of map aspect (generic map, port map).
	  */
	template <typename T>
	void
	addMissingAssoc(
		const Location &loc,
		ValDeclaration &formal,
		const char *kind,
		enum symType symbolType,
		std::list<AssociationElement *> &mapList);

	template <typename T>
	static 
	T *createVal(
		std::string *name,
		enum ValDeclaration::Mode pMode,
		Expression *varInit,
		SubtypeIndication *si,
		Location loc);

public:
	/* FIXME used in GenCode as well, move somewhere where it makes 
	 *       more sense!
	 */
	/** make a simple name referring to ValDeclaration val which resides
	 *  in the declarative region lookupRegion.
	 *  @param val ValDeclaration that should be referred to.
	 *  @param lookupRegion region in which val is declared.
	 *  @param loc Location of the generated name.
	 *  @return SimpleName referring to val or NULL on error.
	 */
	static SimpleName *
	makeNameOfVal(
		const ValDeclaration *val,
		const DeclarativeRegion *lookupRegion,
		Location loc);
private:

	/** current list of formals (ports, generics). 
	  * Consumed ports/generics will be removed. */
	std::list<ValDeclaration*> formals;
	
	/** when traversing to a named association, the picked up 
	 *  declaration lands here */
	const ValDeclaration *pickedUpVal;

	/** current position of the first element of ports. */
	int pos;

	/** positional association used so far? */
	bool positional;

	/** region of the entity to lookup ports */
	const DeclarativeRegion *region;

	/** surrounding Architecture of a CompInstStat (or NULL) */
	const Architecture *arch;

	/** counter so that hidden signals have a unique name */
	int hiddenCounter;

	/** order predicate used for sorting port maps by position */
	static bool sortPosPred(AssociationElement *l, AssociationElement *r);
};

}; /* namespace ast */

#endif /* __NORMALIZE_ASSOC_LISTS_HPP_INCLUDED */
