package code.symbols;

import code.type.visitor.NormalizeType;
import code.type.TypeExpression;
import code.type.visitor.NormalizeType;

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

/**
 * when PrintAsTxtLoadable visits a symbol,
 * it creates a textual representation
 * that can be supplied to the TxtParser and it will load the symbol correctly.
 *
 * @author jimeng
 * @since November 26, 2002
 */
public class PrintAsTxtLoadable implements SymbolVisitor {

    Writer out;
    code.type.visitor.PrintAsTxtLoadable ptv;


    public PrintAsTxtLoadable(Writer out) {
        this.out = out;
        ptv = new code.type.visitor.PrintAsTxtLoadable(out);
    }

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

    private void writeln() {
        write("\n");
    }

    private void writeln(String s) {
        write(s);
        write("\n");
    }

    public Object visit(TypeSymbol ts, Object o) {
        writeln();
        write("TYPE \"");
        write(ts.symbolName);
        write("\" " + ts.arity);
        if (ts.visibility == Symbol.Public) {
            write(" public");
        } else if (ts.visibility == Symbol.Private) {
            write(" private");
        }
        writeln();
        return null;
    }

    public Object visit(ConstructorSymbol cs, Object o) {
        writeln();
        write("CONSTRUCTOR \"");
        write(cs.symbolName);
        write("\" " + cs.staticNestingDepth);
        write(" " + cs.arity);
        write(" " + cs.kind);
        if (cs.associativity == DataSymbol.Left) {
            write(" left " + cs.precedence);
        }
        if (cs.associativity == DataSymbol.Right) {
            write(" right " + cs.precedence);
        }
        if (cs.associativity == DataSymbol.NonAssoc) {
            write(" nonassoc " + cs.precedence);
        }
        if (cs.visibility == Symbol.Public) {
            write(" public");
        } else if (cs.visibility == Symbol.Private) {
            write(" private");
        }
        write(" :: ");
        TypeExpression te = NormalizeType.doit(cs.typeExp);
        te.accept(ptv, o);
        writeln();
        return null;
    }

    public Object visit(OperationSymbol os, Object o) {
        writeln();
        write("OPERATION \"");
        write(os.symbolName);
        write("\" " + os.staticNestingDepth);
        write(" " + os.arity);
        if (os.associativity == DataSymbol.Left) {
            write(" left " + os.precedence);
        }
        if (os.associativity == DataSymbol.Right) {
            write(" right " + os.precedence);
        }
        if (os.associativity == DataSymbol.NonAssoc) {
            write(" nonassoc " + os.precedence);
        }
        if (os.visibility == Symbol.Public) {
            write(" public");
        } else if (os.visibility == Symbol.Private) {
            write(" private");
        }
        write(" :: ");
        TypeExpression te = NormalizeType.doit(os.typeExp);
        te.accept(ptv, o);
        writeln();
        writeln("{");
        //for indent
        for (int i = 0; i < os.code.length; ++i) {
            writeln(" " + os.code[i].printAsTxtLoadable());
        }
        writeln("}");
        //for indent
        return null;
    }

}
