package code.type.visitor;

import code.type.*;

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

/**
 * Prints out the Type in a format suitable for loadiing it by the .txt parser
 *
 * @author jimeng
 * @since November 26, 2002
 */
public class PrintAsTxtLoadable implements TypeVisitor<Object,Object> {

    private final Writer out;

    public PrintAsTxtLoadable(Writer out) {
        this.out = out;
    }

    private void write(String s) {
        try {
            out.write(s);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void writeQualifiedId(String qualifiedName) {
	// TODO: if there is a "." in the module name ... big troubles
	int index = qualifiedName.indexOf('.');
	String moduleName = qualifiedName.substring(0,index);
	String symbolName = qualifiedName.substring(index+1);
        write("\""+moduleName+"\".\""+symbolName+"\"");
    }

    public Object visit(TypeConstructor tc, Object o) {
        writeQualifiedId(tc.name);
        return null;
    }

    public Object visit(TypeVariable tv, Object o) {
        write(tv.name);
        return null;
    }

    public Object visit(FunctionType t, Object o) {
        // test with  >>, head, tail, +
        // from the command line with :symbol <operationname>
        // This also test the TypeVariable
        write("->(");
        t.domain.accept(this, o);
        write(",");
        t.range.accept(this, o);
        write(")");
        return null;
    }

    public Object visit(TypeConstructorApplication t, Object o) {
        // test with  head, tail, fst, snd
        // from the command line with :symbol <operationname>
        // This also test the TypeVariable
	writeQualifiedId(t.typeConstructor);
        write("(");
        for (int i = 0; i < t.arguments.length; ++i) {
            t.arguments[i].accept(this, o);
            if (i < t.arguments.length - 1) 
		// there are some more arguments so print a comma
                write(",");
         }
        write(")");
        return null;
    }

    /**
     * A utility function that prints the textual representation on the supplied writer.
     *
     * @param type
     * @param out
     */
    public static void print (TypeExpression type, Writer out) {
        PrintAsTxtLoadable ptv = new PrintAsTxtLoadable ( out);
        type.accept(ptv,null);
    }

    /**
     * A utility function that returns a String that contains the textual representation of the type.
     *
     * @param type
     * @return
     */
    public static String getString (TypeExpression type) {
        StringWriter sw = new StringWriter() ;
        print(type,sw);
        return sw.toString();
    }
}

