package cmaj7.tree;

import java.io.IOException;
import java.io.Writer;

public class PrettyPrinter implements Visitor<Void> {
	Writer out;
	
	
	public PrettyPrinter(Writer out) {
		super();
		this.out = out;
	}

	@Override
	public Void visit(BinOpExp node) {
		try {
			out.write("(");
			node.lhs.welcome(this);
			out.write(node.op.opSymbol);
			node.rhs.welcome(this);
			out.write(")");
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public Void visit(IntLiteral node) {
		try {
			out.write(""+node.n);
		} catch (IOException e) {
			
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public Void visit(Variable node) {
		try {
			out.write(node.name);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public Void visit(IfExpr ifExpr) {
		try {
			out.write("if ");
			ifExpr.cond.welcome(this);
			out.write(" then ");
			ifExpr.alt1.welcome(this);
			out.write(" else ");
			ifExpr.alt2.welcome(this);

		} catch (IOException e) {
			
			e.printStackTrace();
		}
		
		return null;
	}

	@Override
	public Void visit(Program program) {
		for (ConstrDef constr:program.constrs){
			constr.welcome(this);
		}
		for (FunDef fun:program.funs){
			fun.welcome(this);
		}
		program.body.welcome(this);
		return null;
	}

	@Override
	public Void visit(FunDef funDef) {
		try {
			out.write("define ");
			out.write(funDef.name);
			out.write("(");
			boolean isFirst=true;
			for (String param:funDef.params){
				if (isFirst){
					isFirst=false;
				}else{
					out.write(", ");
				}
				out.write(param);				
			}
			out.write(") = ");
			funDef.body.welcome(this);
			out.write(".\n");
			
		} catch (IOException e) {
			
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public Void visit(FunCall funCall) {
		try {
			out.write(funCall.name);
			out.write("(");
			boolean isFirst=true;
			for (Node arg:funCall.args){
				if (isFirst){
					isFirst=false;
				}else{
					out.write(", ");
				}
				arg.welcome(this);		
			}
			out.write(")");
		} catch (IOException e) {
			
			e.printStackTrace();
		}
		
		return null;
	}

	@Override
	public Void visit(ConstrDef constrDef) {
		try {
			out.write("constructor ");
			out.write(constrDef.name);
			out.write(" "+constrDef.arity);
			out.write(".\n");

		} catch (IOException e) {
			
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public Void visit(CaseExpr caseExpr) {
		try {
			out.write("case ");
			caseExpr.cond.welcome(this);
			out.write(" of \n");
			for (Node n:caseExpr.cases){
				n.welcome(this);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return null;
	}

	@Override
	public Void visit(SingleCase singleCase) {
		try {
			out.write(singleCase.name);
			for (String v:singleCase.vars){
				out.write(" "+v);
			}
			out.write(" -> ");
			singleCase.expr.welcome(this);
			out.write(".\n");
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public Void visit(StringLiteral node) {
		// TODO Auto-generated method stub
		return null;
	}

}
