// Render an AST.
"use strict";

var ast = require('./ast');

ast.RenderT.defineVisitor("tex_part", {
    TEX_ONLY: function(t) { return t; }
});


var render = module.exports = function render(e) {
    if (Array.isArray(e)) {
        return e.map(render).join('');
    }
    return e.render_tex();
};

var curlies = function(t) {
    switch (t.constructor) {
    // constructs which are surrounded by curlies
    case ast.Tex.FUN1:
    case ast.Tex.FUN1hl:
    case ast.Tex.FUN1hf:
    case ast.Tex.DECLh:
    case ast.Tex.FUN2:
    case ast.Tex.FUN2h:
    case ast.Tex.FUN2sq:
    case ast.Tex.CURLY:
    case ast.Tex.INFIX:
    case ast.Tex.INFIXh:
    case ast.Tex.BOX:
    case ast.Tex.BIG:
    case ast.Tex.MATRIX:
        return t.render_tex();
    case String:
        break;
    default:
        t = t.render_tex();
    }
    return "{" + t + "}";
};

var render_curlies = function(a) {
    if (a.length === 1) {
        return curlies(a[0]);
    }
    return curlies(render(a));
};

var dollar = function(t) {
    switch (t.constructor) {
        case String:
            break;
        default:
            t = t.render_tex();
    }
    return "$" + t + "$";
};

var render_dollar = function(a) {
    if (a.length === 1) {
        return dollar(a[0]);
    }
    return dollar(render(a));
};

ast.Tex.defineVisitor("render_tex", {
    FQ: function(base, down, up) {
        return base.render_tex() + "_" + curlies(down) + "^" + curlies(up);
    },
    DQ: function(base, down) {
        return base.render_tex() + "_" + curlies(down);
    },
    UQ: function(base, up) {
        return base.render_tex() + "^" + curlies(up);
    },
    FQN: function(down, up) {
        return "_" + curlies(down) + "^" + curlies(up);
    },
    DQN: function(down) {
        return "_" + curlies(down);
    },
    UQN: function(up) {
        return "^" + curlies(up);
    },
    LITERAL: function(r) {
        return r.tex_part();
    },
    FUN1: function(f, a) {
        return curlies(f + " " + curlies(a));
    },
    MHCHEM: function(f, a) {
        return curlies(f + " " + curlies(a));
    },
    CHEM_WORD: function(l, w) {
        return l.render_tex() + w.render_tex();
    },
    CHEM_FUN2u: function(f, a, b) {
        return f + curlies(a) + "_" + curlies(b);
    },
    FUN1nb: function(f, a) {
        return f + " " + curlies(a) + " ";
    },
    DECLh: function(f, _, a) {
        return curlies(f + " " + render_curlies(a));
    },
    FUN2: function(f, a, b) {
        return curlies(f + " " + curlies(a) + curlies(b));
    },
    FUN2nb: function(f, a, b) {
        return f + " " + curlies(a) + curlies(b);
    },
    FUN2sq: function(f, a, b) {
        return curlies(f + "[" + a.render_tex() + "]" + curlies(b));
    },
    CURLY: function(tl) {
        return render_curlies(tl);
    },
    DOLLAR: function(tl) {
        return render_dollar(tl);
    },
    INFIX: function(s, ll, rl) {
        return curlies(render(ll) + " " + s + " " + render(rl));
    },
    BOX: function(bt, s) {
        //CJK spacing - by libattery
        var cjk = new RegExp(
        "(["
        +"\u1100-\u11FF\u3130-\u318F\uAC00-\uD7AF" //Korean
        +"\u2E80-\u2EFF\u31C0-\u31EF\u3200-\u32FF" //Chinese
        +"\u3400-\u4DBF\u4E00-\u9FBF\uF900-\uFAFF" //Chinese
        +"\u3000-\u303f\u3040-\u30FF\u31F0-\u31FF\uff00-\uff9f" //Japanese
        +"])(\u2005?)"
        ,"ug");
        s = s.replace(cjk, "$1\u2005");

        return curlies(bt + curlies(s));
    },
    BIG: function(bt, d) {
        return curlies(bt + " " + d.tex_part());
    },
    MATRIX: function(t, m) {
        var render_line = function(l) { return l.map(render).join('&'); };
        var render_matrix = function(m) { return m.map(render_line).join('\\\\'); };
        return curlies("\\begin{"+t+"}" + render_matrix(m) + "\\end{"+t+"}");
    },
    LR: function(l, r, tl) {
        return "\\left" + l.tex_part() + render(tl) + "\\right" + r.tex_part();
    }
});
