package com.owent.xresloader.data.dst;
import com.owent.xresloader.ProgramOptions;
import com.owent.xresloader.data.err.ConvException;
import com.owent.xresloader.scheme.SchemeConf;
import org.json.JSONObject;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by owentou on 2016/04/07.
*/
public class DataDstJavascript extends DataDstJava {
private String endl = "\n";
private String ident = " ";
private enum EXPORT_MODE { GLOBAL, NODEJS, AMD }
@Override
public boolean init() {
if (ProgramOptions.getInstance().prettyIndent <= 0) {
endl = " ";
ident = "";
} else {
endl = getSystemEndl();
ident = "";
for (int i = 0; i < ProgramOptions.getInstance().prettyIndent; ++ i) {
ident += " ";
}
}
return true;
}
/**
* @return 协议处理器名字
*/
public String name() {
return "javascript";
}
@Override
public final byte[] build(DataDstImpl compiler) throws ConvException {
DataDstObject data_obj = build_data(compiler);
StringBuffer sb = new StringBuffer();
HashMap<String, Object> conv_type = new HashMap<String, Object>();
String header_name = "";
for(Map.Entry<String, List<Object> > data_item: data_obj.body.entrySet()) {
conv_type.put(data_item.getKey(), data_item.getValue());
}
for(Map.Entry<String, List<Object> > data_item: data_obj.body.entrySet()) {
header_name = String.format("%s_header", data_item.getKey());
if (!conv_type.containsKey(header_name)) {
conv_type.put(header_name, data_obj.header);
break;
}
}
writeExport(sb, conv_type, 0);
// 带编码的输出
String encoding = SchemeConf.getInstance().getKey().getEncoding();
if (null == encoding || encoding.isEmpty())
return sb.toString().getBytes();
return sb.toString().getBytes(Charset.forName(encoding));
}
@Override
public final DataDstWriterNode compile() {
ProgramOptions.getLoger().error("lua can not be protocol description.");
return null;
}
private void writeIdent(StringBuffer sb, int ident_num) {
for(; ident_num > 0; -- ident_num) {
sb.append(ident);
}
}
private void writeExport(StringBuffer sb, HashMap<String, Object> export_items, int ident_num) {
sb.append("// this file is generated by xresloader, please don't edit it.").append(getSystemEndl()).append(endl);
String export_mode_name = ProgramOptions.getInstance().javascriptExport;
EXPORT_MODE export_mode = EXPORT_MODE.GLOBAL;
if (null != export_mode_name) {
// nodejs mode
if (export_mode_name.equalsIgnoreCase("nodejs")) {
export_mode = EXPORT_MODE.NODEJS;
} else if (export_mode_name.equalsIgnoreCase("amd")) {
export_mode = EXPORT_MODE.AMD;
}
}
// export mode header
switch(export_mode) {
case AMD: {
sb.append("define({");
break;
}
default: {
break;
}
}
// export mode content
boolean is_first = true;
for(Map.Entry<String, Object> item: export_items.entrySet()) {
// export mode header
switch(export_mode) {
case AMD: {
if (is_first) {
sb.append(endl);
} else {
sb.append(",").append(endl);
}
writeIdent(sb, ident_num + 1);
sb.append(item.getKey()).append(": ");
writeData(sb, item.getValue(), 1);
break;
}
case NODEJS: {
sb.append(String.format("exports.%s = ", item.getKey()));
writeData(sb, item.getValue(), 0);
sb.append(";").append(endl);
break;
}
default: {
sb.append(String.format("(function(){%s%svar %s = ", endl, ident, item.getKey()));
writeData(sb, item.getValue(), 1);
sb.append(";").append(endl);
// extend function
sb.append(ident).append("var extend = function (dst, src) {").append(endl);
sb.append(ident).append(ident).append("for (var k in src) {").append(endl);
sb.append(ident).append(ident).append(ident).append("var v = src[k];").append(endl);
sb.append(ident).append(ident).append(ident).append("if (undefined === dst[k] || 'object' != typeof(v)) {").append(endl);
sb.append(ident).append(ident).append(ident).append(ident).append("dst[k] = v;").append(endl);
sb.append(ident).append(ident).append(ident).append("} else {").append(endl);
sb.append(ident).append(ident).append(ident).append(ident).append("if ('object' != typeof(dst[k])) {").append(endl);
sb.append(ident).append(ident).append(ident).append(ident).append(ident).append("dst[k] = {};").append(endl);
sb.append(ident).append(ident).append(ident).append(ident).append("}").append(endl);
sb.append(ident).append(ident).append(ident).append(ident).append("extend(dst[k], v)").append(endl);
sb.append(ident).append(ident).append(ident).append("}").append(endl);
sb.append(ident).append(ident).append("}").append(endl);
sb.append(ident).append("};").append(endl);
if (ProgramOptions.getInstance().javascriptGlobalVar.isEmpty()) {
sb.append(ident).append(String.format("try { extend(window, { %s : %s }); }", item.getKey(), item.getKey())).append(endl);
sb.append(ident).append(String.format("catch(e) { extend(global, { %s : %s }); }", item.getKey(), item.getKey())).append(endl);
} else {
sb.append(ident).append(String.format("try { extend(window, { \"%s\" : { %s : %s } }); }",
ProgramOptions.getInstance().javascriptGlobalVar, item.getKey(), item.getKey())).append(endl);
sb.append(ident).append(String.format("catch(e) { extend(global, { \"%s\" : { %s : %s } }); }",
ProgramOptions.getInstance().javascriptGlobalVar, item.getKey(), item.getKey())).append(endl);
}
sb.append("})();").append(endl);
break;
}
}
is_first = false;
}
// export mode footer
switch(export_mode) {
case AMD: {
writeIdent(sb, ident_num);
sb.append(endl).append("});").append(endl);
break;
}
default: {
break;
}
}
}
private void writeData(StringBuffer sb, Object data, int ident_num) {
// null
if (null == data) {
sb.append("undefined");
return;
}
// 数字
// 枚举值已被转为Java Long,会在这里执行
if (data instanceof Number) {
sb.append(data.toString());
return;
}
// 布尔
if (data instanceof Boolean) {
sb.append(((Boolean) data)? "true": "false");
return;
}
// 字符串&二进制
if (data instanceof String) {
// 利用json的字符串格式,和javascript一样的没必要再引入一个库
sb.append(JSONObject.quote((String)data));
return;
}
// 列表
if (data instanceof List) {
List<Object> ls = (List<Object>)data;
sb.append("[");
boolean is_first = true;
for(Object obj: ls) {
if (is_first) {
sb.append(endl);
} else {
sb.append(",").append(endl);
}
writeIdent(sb, ident_num + 1);
writeData(sb, obj, ident_num + 1);
is_first = false;
}
if (!is_first) {
sb.append(endl);
writeIdent(sb, ident_num);
}
sb.append("]");
return;
}
// Hashmap
if (data instanceof Map) {
Map<String, Object> mp = (Map<String, Object>)data;
sb.append("{");
boolean is_first = true;
for(Map.Entry<String, Object> item: mp.entrySet()) {
if (is_first) {
sb.append(endl);
} else {
sb.append(",").append(endl);
}
writeIdent(sb, ident_num + 1);
sb.append(item.getKey()).append(" : ");
writeData(sb, item.getValue(), ident_num + 1);
is_first = false;
}
if (!is_first) {
sb.append(endl);
writeIdent(sb, ident_num);
}
sb.append("}");
return;
}
ProgramOptions.getLoger().error("rewrite %s as null, should not called here.", data.toString());
sb.append("nil");
}
/**
* 转储常量数据
* @return 常量数据,不支持的时候返回空
*/
public final byte[] dumpConst(HashMap<String, Object> data) {
init();
StringBuffer sb = new StringBuffer();
writeExport(sb, data, 0);
sb.append(endl);
// 带编码的输出
String encoding = SchemeConf.getInstance().getKey().getEncoding();
if (null == encoding || encoding.isEmpty())
return sb.toString().getBytes();
return sb.toString().getBytes(Charset.forName(encoding));
}
}