package name.panitz.fun4u.visitor;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import name.panitz.fun4u.tree.App;
import name.panitz.fun4u.tree.CaseExpr;
import name.panitz.fun4u.tree.ConstructorDef;
import name.panitz.fun4u.tree.Definition;
import name.panitz.fun4u.tree.Exp;
import name.panitz.fun4u.tree.FunctionDef;
import name.panitz.fun4u.tree.IfExp;
import name.panitz.fun4u.tree.IntLiteral;
import name.panitz.fun4u.tree.OpExp;
import name.panitz.fun4u.tree.Pack;
import name.panitz.fun4u.tree.Param;
import name.panitz.fun4u.tree.Program;
import name.panitz.fun4u.tree.Type;
import name.panitz.fun4u.tree.Var;

public class MakeConstructorcalls implements Visitor {
	Map<String,Integer> constructorTable=null; 
	Exp newExp=null;
		
	public MakeConstructorcalls(Map<String, Integer> constructorTable) {
		super();
		this.constructorTable = constructorTable;
	}

	@Override
	public void visit(Type type) {
	}

	@Override
	public void visit(Param param) {
	}

	@Override
	public void visit(IfExp ifExp) {
		ifExp.cond.welcome(this);
		ifExp.cond=newExp;
		ifExp.alt1.welcome(this);
		ifExp.alt1=newExp;
		ifExp.alt2.welcome(this);
		ifExp.alt2=newExp;
		newExp = ifExp;
	}

	@Override
	public void visit(App app) {
		List<Exp> newArgs=new ArrayList<Exp>();
		for (Exp arg:app.args){
			arg.welcome(this);
			newArgs.add(newExp);
		}
		if (constructorTable.containsKey(app.functionName)){
			newExp = new Pack(app.functionName,newArgs);
		}else{
			newExp=app;
			app.args=newArgs;
		}
		
	}

	@Override
	public void visit(OpExp opExp) {
		opExp.left.welcome(this);
		opExp.left=newExp;
		opExp.right.welcome(this);
		opExp.right=newExp;
		newExp=opExp;
	}

	@Override
	public void visit(Var var) {
		newExp=var;
	}

	@Override
	public void visit(IntLiteral intLiteral) {
		newExp=intLiteral;
	}

	@Override
	public void visit(FunctionDef functionDef) {
		functionDef.body.welcome(this);
		functionDef.body=newExp;
	}

	@Override
	public void visit(Program program) {
		for (Definition def:program.definitions){
			def.welcome(this);
		}
		program.e.welcome(this);
		program.e=newExp;
	}

	@Override
	public void visit(CaseExpr caseExpr) {
		caseExpr.e.welcome(this);
		caseExpr.e=newExp;
		newExp = caseExpr;
	}

	@Override
	public void visit(Pack pack) {
		List<Exp> newArgs=new ArrayList<Exp>();
		for (Exp arg:pack.args){
			arg.welcome(this);
			newArgs.add(newExp);
		}	
		pack.args=newArgs;
	}

	@Override
	public void visit(ConstructorDef constructorDef) {
	}
}
