/**
 * @file 编译源码的 helper 方法集合
 * @author errorrik(errorrik@gmail.com)
 */

var each = require('../util/each');
var ExprType = require('../parser/expr-type');

// #[begin] ssr

/**
 * 编译源码的 helper 方法集合对象
 */
var compileExprSource = {

    /**
     * 字符串字面化
     *
     * @param {string} source 需要字面化的字符串
     * @return {string} 字符串字面化结果
     */
    stringLiteralize: function (source) {
        return '"'
            + source
                .replace(/\x5C/g, '\\\\')
                .replace(/"/g, '\\"')
                .replace(/\x0A/g, '\\n')
                .replace(/\x09/g, '\\t')
                .replace(/\x0D/g, '\\r')
                // .replace( /\x08/g, '\\b' )
                // .replace( /\x0C/g, '\\f' )
            + '"';
    },

    /**
     * 生成数据访问表达式代码
     *
     * @param {Object?} accessorExpr accessor表达式对象
     * @return {string}
     */
    dataAccess: function (accessorExpr) {
        var code = 'componentCtx.data';
        if (accessorExpr) {
            each(accessorExpr.paths, function (path) {
                if (path.type === ExprType.ACCESSOR) {
                    code += '[' + compileExprSource.dataAccess(path) + ']';
                    return;
                }

                switch (typeof path.value) {
                    case 'string':
                        code += '.' + path.value;
                        break;

                    case 'number':
                        code += '[' + path.value + ']';
                        break;
                }
            });
        }

        return code;
    },

    /**
     * 生成插值代码
     *
     * @param {Object} interpExpr 插值表达式对象
     * @return {string}
     */
    interp: function (interpExpr) {
        var code = compileExprSource.expr(interpExpr.expr);


        each(interpExpr.filters, function (filter) {
            code = 'componentCtx.callFilter("' + filter.name.paths[0].value + '", [' + code;
            each(filter.args, function (arg) {
                code += ', ' + compileExprSource.expr(arg);
            });
            code += '])';
        });

        if (!interpExpr.original) {
            return 'escapeHTML(' + code + ')';
        }

        return code;
    },

    /**
     * 生成文本片段代码
     *
     * @param {Object} textExpr 文本片段表达式对象
     * @return {string}
     */
    text: function (textExpr) {
        if (textExpr.segs.length === 0) {
            return '""';
        }

        var code = '';

        each(textExpr.segs, function (seg) {
            var segCode = compileExprSource.expr(seg);
            code += code ? ' + ' + segCode : segCode;
        });

        return code;
    },

    /**
     * 生成数组字面量代码
     *
     * @param {Object} arrayExpr 数组字面量表达式对象
     * @return {string}
     */
    array: function (arrayExpr) {
        var code = [];

        each(arrayExpr.items, function (item) {
            code.push((item.spread ? '...' : '') + compileExprSource.expr(item.expr));
        });

        return '[\n' + code.join(',\n') + '\n]';
    },

    /**
     * 生成对象字面量代码
     *
     * @param {Object} objExpr 对象字面量表达式对象
     * @return {string}
     */
    object: function (objExpr) {
        var code = [];

        each(objExpr.items, function (item) {
            if (item.spread) {
                code.push('...' + compileExprSource.expr(item.expr));
            }
            else {
                code.push(compileExprSource.expr(item.name) + ':' + compileExprSource.expr(item.expr));
            }
        });

        return '{\n' + code.join(',\n') + '\n}';
    },

    /**
     * 二元表达式操作符映射表
     *
     * @type {Object}
     */
    binaryOp: {
        /* eslint-disable */
        43: '+',
        45: '-',
        42: '*',
        47: '/',
        60: '<',
        62: '>',
        76: '&&',
        94: '!=',
        121: '<=',
        122: '==',
        123: '>=',
        155: '!==',
        183: '===',
        248: '||'
        /* eslint-enable */
    },

    /**
     * 生成表达式代码
     *
     * @param {Object} expr 表达式对象
     * @return {string}
     */
    expr: function (expr) {
        switch (expr.type) {
            case ExprType.UNARY:
                return '!' + compileExprSource.expr(expr.expr);

            case ExprType.BINARY:
                return compileExprSource.expr(expr.segs[0])
                    + compileExprSource.binaryOp[expr.operator]
                    + compileExprSource.expr(expr.segs[1]);

            case ExprType.TERTIARY:
                return compileExprSource.expr(expr.segs[0])
                    + '?' + compileExprSource.expr(expr.segs[1])
                    + ':' + compileExprSource.expr(expr.segs[2]);

            case ExprType.STRING:
                return compileExprSource.stringLiteralize(expr.literal || expr.value);

            case ExprType.NUMBER:
                return expr.value;

            case ExprType.BOOL:
                return expr.value ? 'true' : 'false';

            case ExprType.ACCESSOR:
                return compileExprSource.dataAccess(expr);

            case ExprType.INTERP:
                return compileExprSource.interp(expr);

            case ExprType.TEXT:
                return compileExprSource.text(expr);

            case ExprType.ARRAY:
                return compileExprSource.array(expr);

            case ExprType.OBJECT:
                return compileExprSource.object(expr);
        }
    }
};
// #[end]

exports = module.exports = compileExprSource;

@@ -4133,55 +4133,246 @@
     
-return '!' + compileExprSource.expr(expr.expr);
+switch (expr.op) %7B%0A                    case 33:%0A                        return '!' + compileExprSource.expr(expr.expr);%0A                    case 45:%0A                        return '-' + compileExprSource.expr(expr.expr);%0A                %7D
 %0A%0A  

support unary expr - for ssr