import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;


import name.panitz.fun4u.tree.*;
import name.panitz.fun4u.visitor.*;

public class ListTest {

	/**
	 * @param args
	 */
	public static void main(String[] _)throws IOException {
		Exp i5 = new IntLiteral(5);
		Exp i0 = new IntLiteral(0);
		Exp i1 = new IntLiteral(1);
		Exp i42 = new IntLiteral(42);

		List<Exp> empty = new LinkedList<Exp>();
		Pack nil = new Pack("Nil",empty);
		List<Exp> l1 = new LinkedList<Exp>();
		l1.add(i0);l1.add(nil);
		Pack cons1 = new Pack("Cons",l1);
		List<Exp> l2 = new LinkedList<Exp>();
		l2.add(i5);l2.add(cons1);
		Pack cons2 = new Pack("Cons",l2);
		List<Exp> l3 = new LinkedList<Exp>();
		l3.add(i5);l3.add(cons2);
		Pack cons3 = new Pack("Cons",l3);
		List<Exp> l4 = new LinkedList<Exp>();
		l4.add(i42);l4.add(cons3);
		Pack cons4 = new Pack("Cons",l4);
		
		List<Pair<String,String>> caseFunctions = new LinkedList<Pair<String,String>>();
		caseFunctions.add(new Pair<String,String>("Nil","lengthNilCase"));
		caseFunctions.add(new Pair<String,String>("Cons","lengthConsCase"));
		
		Exp caseExpr = new CaseExpr(new Var("xs"),caseFunctions);
		FunctionDef lengthNilCase = new FunctionDef
		("lengthNilCase"
		,new LinkedList<Param>()
		,i0
		,new Type("int"));
		List<Param> consParams = new LinkedList<Param>();
		consParams.add(new Param("x",new Type("int")));
		consParams.add(new Param("xs",new Type("List")));

		List<Exp> rekursiveParams = new LinkedList<Exp>();
		rekursiveParams.add(new Var("xs"));
		
		FunctionDef lengthConsCase = new FunctionDef
		("lengthConsCase"
		,consParams
		,new OpExp(i1,"+",new App("length", rekursiveParams))
		,new Type("int"));

		FunctionDef headConsCase = new FunctionDef
		("headConsCase"
		,consParams
		,new Var("x")
		,new Type("int"));

		FunctionDef tailConsCase = new FunctionDef
		("tailConsCase"
		,consParams
		,new Var("xs")
		,new Type("int"));
		
		
		List<Param> lengthParams = new LinkedList<Param>();
		lengthParams.add(new Param("xs",new Type("List")));
		
		FunctionDef length = new FunctionDef
		("length"
		,lengthParams
		,caseExpr
		,new Type("int"));

		List<Pair<String,String>> caseHeadFunctions = new LinkedList<Pair<String,String>>();
		caseHeadFunctions.add(new Pair<String,String>("Cons","headConsCase"));
		
		Exp caseHeadExpr = new CaseExpr(new Var("xs"),caseHeadFunctions);
		
		FunctionDef head = new FunctionDef
		("head"
		,lengthParams
		,caseHeadExpr
		,new Type("int"));

		List<Pair<String,String>> caseTailFunctions = new LinkedList<Pair<String,String>>();
		caseTailFunctions.add(new Pair<String,String>("Cons","tailConsCase"));
		
		Exp caseTailExpr = new CaseExpr(new Var("xs"),caseTailFunctions);
		
		FunctionDef tail = new FunctionDef
		("tail"
		,lengthParams
		,caseTailExpr
		,new Type("int"));
		
		
		List<Definition> fs = new ArrayList<Definition>();
		fs.add(lengthConsCase);
		fs.add(lengthNilCase);
		fs.add(length);
		fs.add(headConsCase);
		fs.add(head);
		fs.add(tailConsCase);
		fs.add(tail);
		fs.add(new ConstructorDef("Nil",0));
		fs.add(new ConstructorDef("Cons",2));

		List<Exp> mainArgs = new LinkedList<Exp>();
		mainArgs.add(cons4);
		List<Exp> mainArgs2 = new LinkedList<Exp>();
		mainArgs2.add(new App("tail",mainArgs));
		
		Program prog = new Program(fs,new App("head",mainArgs2));
		Visitor checker = new CheckParams();
		prog.welcome(checker);
		
		Writer w = new FileWriter("Prog.java");
		Visitor v = new GenJava(w);
		prog.welcome(v);
		w.close();

		GenCode gc = new GenCode();
		prog.welcome(gc);

	}

}
