/* ConstructExtendsGraphVisitor - Decompiled by JODE
 * Visit http://jode.sourceforge.net/
 */
package alloy.semantic;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Vector;

import alloy.ast.ASTDepthFirstVisitor;
import alloy.ast.Module;
import alloy.ast.QualifiedName;
import alloy.ast.SigExpr;
import alloy.ast.Signature;
import alloy.util.Dbg;
import alloy.util.Msg;

import salvo.jesus.graph.DirectedAcyclicGraph;
import salvo.jesus.graph.DirectedAcyclicGraphImpl;
import salvo.jesus.graph.Vertex;

public class ConstructExtendsGraphVisitor extends ASTDepthFirstVisitor
{
    public DirectedAcyclicGraph extendsDAG = new DirectedAcyclicGraphImpl();
    private HashMap _nameToVertex = new HashMap();
    private ModuleScope _curModuleScope;
    private ModuleScopeTable _moduleNameToModuleScope
	= ModuleScopeTable.getInstance();
    
    private class InvalidExtensionException extends Exception
    {
	private InvalidExtensionException() {
	    /* empty */
	}
    }
    
    public void visit(Module module) {
	_curModuleScope
	    = _moduleNameToModuleScope.get(module.getName().nodeString());
	module.getSignatures().applyVisitor(this);
    }
    
    public void visit(Signature signature) {
	Vertex vertex = getSigVertex(signature);
	Iterator iterator = signature.getExtends().getSigExprIter();
	while (iterator.hasNext()) {
	    SigExpr sigexpr = (SigExpr) iterator.next();
	    try {
		Vertex vertex_0_ = getExtendedSigVertex(sigexpr);
		salvo.jesus.graph.DirectedEdge directededge
		    = extendsDAG.getEdge(vertex, vertex_0_);
		if (directededge != null)
		    Dbg.user(new Msg("signature already extended", sigexpr));
		else {
		    salvo.jesus.graph.Edge edge
			= extendsDAG.addEdge(vertex, vertex_0_);
		    if (edge == null)
			Dbg.user(new Msg("cyclic extension", sigexpr));
		    else {
			LocalScope localscope
			    = ((LocalScope)
			       signature.getLocalScope().getParents().next());
			LocalScope localscope_1_
			    = (LocalScope) ((Signature) vertex_0_.getObject())
					       .getLocalScope
					       ().getParents
					       ().next();
			localscope.addParent(localscope_1_);
		    }
		}
	    } catch (ModuleScope.MultipleMappingsException multiplemappingsexception) {
		Dbg.user(new Msg(multiplemappingsexception.mappingsString(),
				 sigexpr));
	    } catch (ModuleScope.NoParagraphException noparagraphexception) {
		Dbg.user(new Msg("extension of non-existent sig", sigexpr));
	    } catch (InvalidExtensionException invalidextensionexception) {
		Dbg.user(new Msg("extension of non-signature", sigexpr));
	    }
	}
    }
    
    public ArrayList getSortedSigs() {
	Vector vector = extendsDAG.reverseTopologicalSort();
	ArrayList arraylist = new ArrayList();
	Iterator iterator = vector.iterator();
	while (iterator.hasNext()) {
	    Vertex vertex = (Vertex) iterator.next();
	    arraylist.add(vertex.getObject());
	}
	return arraylist;
    }
    
    private Vertex getExtendedSigVertex(SigExpr sigexpr)
	throws ModuleScope.MultipleMappingsException,
	       ModuleScope.NoParagraphException, InvalidExtensionException {
	QualifiedName qualifiedname = sigexpr.getSig();
	Object object = null;
	alloy.ast.Paragraph paragraph;
	if (qualifiedname.hasEmptyPath())
	    paragraph = _curModuleScope.getParagraphUnqual(qualifiedname);
	else
	    paragraph = _curModuleScope.getParagraph(qualifiedname);
	if (!(paragraph instanceof Signature))
	    throw new InvalidExtensionException();
	return getSigVertex((Signature) paragraph);
    }
    
    private Vertex getSigVertex(Signature signature) {
	String string = signature.getName().nodeString();
	Object object = null;
	Vertex vertex;
	if (_nameToVertex.containsKey(string))
	    vertex = (Vertex) _nameToVertex.get(string);
	else {
	    vertex = new Vertex(signature);
	    _nameToVertex.put(string, vertex);
	    extendsDAG.add(vertex);
	}
	return vertex;
    }
}
