var tbsEditor, jsEditor, methodEditor;
var servicePath;
var curTBS;
var curMethod;
var TBSStatements;
//用来缓存系统语句索引信息，以便查找，以“语句分类_名称”为标识
var StatementTypes = {};
var curSMIndex = 1;  //当前语句索引值
//语句索引集合，用来存储当前正在设计的方法的所有语句的索引信息
//包括语句的编号，父语句的编号等，以便查找使用
//这些信息只是在设计时有用，不需要保存到TBS文件内
var smIndexs = {};  
var notSaveMethods = [];
var mouseInfo = {
  downX: 0,
  downY: 0,
  isDrag: false,
  input: null
};

function showBaseInfo() {
  $("#divBaseInfo").show();
  $("#divDesigner").hide();
  $("#divTBSCode").hide();
  $("#divJSCode").hide();
  $("#divBottom").find("div").css("color", "#AAAAAA");
  $("#divBottom").find("div").css("background-color", "#333333");
  $("#divNavBaseInfo").css("color", "#FFFFFF");
  $("#divNavBaseInfo").css("background-color", "#444444");
}

function showDesigner() {
  $("#divBaseInfo").hide();
  $("#divDesigner").show();
  $("#divTBSCode").hide();
  $("#divJSCode").hide();
  $("#divBottom").find("div").css("color", "#AAAAAA");
  $("#divBottom").find("div").css("background-color", "#333333");
  $("#divNavDesigner").css("color", "#FFFFFF");
  $("#divNavDesigner").css("background-color", "#444444");

  if(!TBSStatements) {
    TBSStatements = JSON.parse(top.taskBuilder.readFileSync('/node_modules/taskbuilder-tbs-designer/TBSStatements.json'));
    let htmlLib = "";
    for(var i=0;i<TBSStatements.length;i++) {
      //暂时仅支持基本语句和数据库操作
      let category = TBSStatements[i];
      htmlLib += "<div class=\"category-title\"";
      if(i==0) htmlLib += " style=\"border-top:0;\"";
      htmlLib += " onclick=\"toggleCategoryItems('divLib_"+category.name+"', this)\">\r\n";
      htmlLib += "<img src=\"../taskbuilder-renderer/images/arrow/"+(i==0 ? "down" : "right")+".png\" />\r\n";
      htmlLib += "<label>"+category.comment+"</label>\r\n";
      htmlLib += "</div>\r\n";
      htmlLib += "<div class=\"ToolBarHorizontalSplitLine\"></div>\r\n";
      htmlLib += "<div id=\"divLib_"+category.name+"\" class=\"category-items statements-lib\"";
      if(i>0) htmlLib += " style=\"display:none;\"";
      htmlLib += ">\r\n";
      for(var j=0;j<category.statements.length;j++) {
        let stype = category.statements[j];
        stype.category = category.name;
        let color = stype.color;
        if(!color) color = category.color;
        htmlLib += "<div stype=\""+category.name+"_"+stype.name+"\" "
          +"style=\"background-color:"+color+";\" draggable=\"false\">"
          +"<img src=\""+stype.icon+"\" /><label>"+stype.comment+"</label></div>";
        StatementTypes[category.name+"_"+stype.name] = stype;
      }
      htmlLib += "</div>";
    }
    $("#divDesignerLib").append(htmlLib);

    for(var i=0;i<curTBS.methods.length;i++) {
      let method = curTBS.methods[i];
      if(method.name=="process") {
        selectMethod(method);
        break;
      }
    }

    $(".statements-lib").find("div").mousedown(function() {
      let stype = StatementTypes[$(this).attr("stype")];
      if(!stype) return;
      var e = window.event;
      mouseInfo.downX = e.clientX;
      mouseInfo.downY = e.clientY;
      mouseInfo.stype = stype;
      mouseInfo.isDrag = true;
      $("#divDragging").find("img").attr("src", $(this).find("img").attr("src"));
      $("#divDragging").find("label").text($(this).find("label").text());
    });

    document.onmousemove = function() {
      if(!mouseInfo.isDrag) return;
      var e = window.event;
      if(e.clientX-mouseInfo.downX>5||e.clientX-mouseInfo.downX<-5
        ||e.clientY-mouseInfo.downY>5||e.clientY-mouseInfo.downY<-5) {
        var x = e.clientX+2;
        var y = e.clientY;
        $("#divDragging").css("left", x+"px");
        $("#divDragging").css("top", y+"px");
        $("#divDragging").show();
      }
    };

    document.onmouseup = function() {
      if(!mouseInfo.isDrag) return;
      mouseInfo.isDrag = false;
    
      $("#divDragging").css("left", "0");
      $("#divDragging").css("top", "62px");
      $("#divDragging").hide();
      $("#divDragging").find("img").attr("src", "");
      $("#divDragging").find("img").text("");
      mouseInfo.downX = 0;
      mouseInfo.downY = 0;
      
      var e = window.event;
      var srcEl = e.srcElement;
      let parentEl = $(srcEl);
      let beforeEl = null;
      if(!parentEl.hasClass("statement_container")) {
        if(parentEl.parents(".statement-item").length>0) {
          beforeEl = parentEl.parents(".statement-item").eq(0);
          parentEl = beforeEl.parent();
        } else {
          mouseInfo.stype = null;
          return;
        }
      }
      addStatement(parentEl, mouseInfo.stype, null, beforeEl);
      mouseInfo.stype = null;
    };
  }
}

function addStatement(parentEl, stype, statement, beforeEl) {
  let bgColor = "#CCCCCC";
  if(stype.color) {
    bgColor = stype.color;
  } else {
    for(var i=0;i<TBSStatements.length;i++) {
      let category = TBSStatements[i];
      if(category.name==stype.category) {
        bgColor = category.color;
        break;
      }
    }
  }
  //获得父语句
  var pid = parseInt(parentEl.attr("sid"));
  var parent = (pid==0) ? curMethod : smIndexs[pid].statement;
  if(!parent) return;
  //如果是新添加的语句
  if(!statement) {
    //初始化语句
    statement = {
      category: stype.category,
      type: stype.name
    };
    //设置默认值
    if(stype.inputs) {
      for(var i=0;i<stype.inputs.length;i++) {
        let ipt = stype.inputs[i];
        if(ipt.default) statement[ipt.name] = ipt.default;
      }
    }
    if(!parent.statements) parent.statements = [];
    if(beforeEl) {
      let beforeSMId = beforeEl.attr("sid");
      let beforeSM = smIndexs[beforeSMId].statement;
      for(var i=0;i<parent.statements.length;i++) {
        if(parent.statements[i]==beforeSM) {
          parent.statements.splice(i+1, 0, statement);
          break;
        }
      }
    } else {
      parent.statements.push(statement);
    }
    if(!notSaveMethods.contains(curMethod.name)) notSaveMethods.push(curMethod.name);
  }
  //定义一个虚拟映射对象，为每条语句设置一个唯一的编号和父语句编号，以便后续查找使用
  let smIndex = {
    id: curSMIndex,
    pid: pid,
    statement: statement
  };
  curSMIndex++;
  smIndexs[smIndex.id] = smIndex;
  let html = "<table sid=\""+smIndex.id+"\" border=\"0\" "
    +"cellpadding=\"0\" cellspacing=\"0\" class=\"statement-item statement-item-"+stype.category+"\">\r\n"
    +"<tr><td colspan=\"2\">\r\n<div class=\"statement-header\" "
    +"style=\"background-color:"+bgColor+";";
  if(stype.haveStatements) {
    html += "border-radius:6px 6px 6px 0;";
  }
  html += "\">\r\n";
  if(stype.icon) html += "<img src=\""+stype.icon+"\" />\r\n";
  html += "<label>"+stype.comment+"</label>\r\n";
  if(stype.inputs) {
    for(var i=0;i<stype.inputs.length;i++) {
      html += getSMInputHtml(stype.inputs[i], statement);
    }
  }
  html += "<div style=\"width:5px;\"></div><img src=\"images/del.png\" class=\"del-img\" style=\"margin-left: auto;\" "
    +"onclick=\"deleteStatement(this)\" title=\"删除\" />";
  html += "</div></td></tr>\r\n";
  if(stype.haveStatements) {
    html += "<tr><td width=\"10\" bgColor=\""+bgColor+"\" height=\"50\"></td>\r\n"
      +"<td sid=\""+smIndex.id+"\" class=\"statement_container\"></td></tr>\r\n"
      +"<tr><td colspan=\"2\" style=\"height:20px;\">\r\n<div class=\"statement-footer\" "
      +"style=\"background-color:"+bgColor+";\"></div>\r\n</td></tr>\r\n";
  }
  html += "</table>";
  //console.log(html);
  if(beforeEl) {
    $(html).insertAfter(beforeEl);
  } else {
    parentEl.append(html);
  }

  let newItem = parentEl.find("table[sid="+smIndex.id+"]");

  newItem.click(function() {
    var e = window.event;
    e.stopPropagation();

    unSelectStatement();

    $(this).css("outline", "1px dotted #ffcc00");
  });

  newItem.find("input").change(function() {
    setStatementProp(this);
  });

  newItem.find("select").change(function() {
    setStatementProp(this);
  });

  if(stype.inputs) {
    for(var i=0;i<stype.inputs.length;i++) {
      let value = getStatementInputValue(statement, stype.inputs[i].name);
      let iptName = stype.inputs[i].name.replace(/\./g, "_");
      $("[sid=\""+smIndex.id+"\"]").find("[ipt-name=\""+iptName+"\"]").val(value);
      //if(value || value==0) str += " value=\""+value+"\"";
    }
  }
  
  if(statement.statements) {
    for(var i=0;i<statement.statements.length;i++) {
      let childSM = statement.statements[i];
      let childSMType = StatementTypes[childSM.category+"_"+childSM.type];
      let childContainer = $("[sid="+smIndex.id+"]").find(".statement_container").first();
      addStatement(childContainer, childSMType, childSM);
    }
  }
}

function getStatementInputValue(statement, inputName) {
  if(inputName.indexOf(".")<0) return statement[inputName];
  let arr = inputName.split(".");
  let value = statement;
  for(var i=0;i<arr.length;i++) {
    value = value[arr[i]];
    if(!value) break;
  }
  return value;
}

function getSMInputHtml(ipt, statement) {
  let str = "";
  if(ipt.comment) str += "<label>"+ipt.comment+"：</label>";
  let iptName = ipt.name.replace(/\./g, "_");
  if(ipt.type=="text") {
    str += "<input ipt-name=\""+iptName+"\" type=\"text\" class=\"statement-input\" style=\"width:";
    str += ipt.width ? ipt.width : "80px";
    str += ";";
    //if(ipt.required) str += "background-color:#ffcc99;";
    str += "\" ";
    if(ipt.maxLength) str += " maxlength=\""+ipt.maxLength+"\"";
    //if(value || value==0) str += " value=\""+value+"\"";
    if(ipt.readonly) str += " readonly";
    str += " />\r\n"; 
  } else if(ipt.type == "select") {
    str += "<select ipt-name=\""+iptName+"\" class=\"style-item-input\"";
    //if(ipt.required) str += "style=\"background-color:#ffcc99;\"";
    str += ">";
    if(!ipt.required) str += "<option></option>";
    if(ipt.options) {
      for(var i=0;i<ipt.options.length;i++) {
        let val = "",txt= "";
        if( typeof(ipt.options[i]) == "string" ) {
          val = ipt.options[i];
          txt = val;
        } else if(ipt.options[i] instanceof Array) {
          if(ipt.options[i].length>0) val = ipt.options[i][0];
          if(ipt.options[i].length>1) txt = ipt.options[i][1];
          if(ipt.options[i].length==1) txt = val;
        } else if(typeof ipt.options[i] == 'object') {
          if(ipt.options[i].value) val = ipt.options[i].value;
          if(ipt.options[i].text) {
            txt = ipt.options[i].text;
          } else {
            txt = val;
          }
        }
        str += "<option value=\""+val+"\"";
        //if(val==value) str += " selected";
        str += ">"+txt+"</option>";
      }
    }
    str += "</select>";
  } else if(ipt.type == "dialog") {
    let smType = StatementTypes[statement.category+"_"+statement.type];
    str += "<div class=\"setting-button\" onclick=\"openSettingDialog(this, '"
      +smType.comment+"', '"+ipt.url+"', '"+ipt.width+"', '"+ipt.height+"')\">设置</div>";
  }
  return str;
}

function openSettingDialog(btn, title, url, width, height) {
  let smTable = $(btn).parents("table").first();
  let sid = smTable.attr("sid");
  let args = {
    sid: sid,
    statement: {}
  };
  let srcSM = smIndexs[sid].statement;
  for(p in srcSM) {
    if(p=="statements") continue;
    args.statement[p] = srcSM[p];
  }
  if(args.statement.type=="func") {
    args.curTBSMethods = [];
    for(var i=0;i<curTBS.methods.length;i++) {
      let method = curTBS.methods[i];
      if(method.name=="process") continue;
      args.curTBSMethods.push({
        name: method.name,
        comment: method.comment,
        args: method.args
      });
    }
  } else if(args.statement.category=="db" || args.statement.category=="import-export") {
    args.reqArgs = curTBS.reqArgs;
    args.servicePath = servicePath;
    args.projName = servicePath.substring(5, servicePath.indexOf("/service/"));
  }
  openDialog(title, url, width, height, JSON.stringify(args), function(ret) {
    //console.log(ret);
    smTable.find(".statement-header").first().find("input").each(function(){
      let iptName = $(this).attr("ipt-name");
      let iptVal = ret[iptName];
      if(iptName=="model_name") iptVal = ret.model.name;
      if(!iptVal) iptVal = "";
      $(this).val(iptVal);
    }); 
    for(p in ret) {
      if(p=="category" || p=="type" || p=="_sid") continue;
      srcSM[p] = ret[p];
    }
    //console.log(srcSM);
  });
}

function setStatementProp(ipt) {
  let val = $(ipt).val();
  let sTable = $(ipt).parents("table").eq(0);
  let sid = sTable.attr("sid");
  let statement = smIndexs[sid].statement;
  statement[$(ipt).attr("ipt-name")] = val;
  if(!notSaveMethods.contains(curMethod.name)) notSaveMethods.push(curMethod.name);
  //console.log(statement);
}

function deleteStatement(imgDel) {
  var e = window.event;
  e.stopPropagation();
  let table = $(imgDel).parents("table").eq(0);
  let sid = table.attr("sid");
  table.remove();
  let smIndex = smIndexs[sid];
  let statement = smIndex.statement;
  if(!statement) return;
  let parent = (smIndex.pid==0) ? curMethod : smIndexs[smIndex.pid].statement;
  if(!parent) return;
  if(parent.statements) {
    for(var i=0;i<parent.statements.length;i++) {
      let sm = parent.statements[i];
      if(sm==statement) {
        parent.statements.splice(i, 1);
        break;
      }
    }
  }
  if(!notSaveMethods.contains(curMethod.name)) notSaveMethods.push(curMethod.name);
  deleteSMIndex(sid);
  //console.log(smIndexs);
}

/**
 * 删除语句索引
 * @param  {[type]} pid [description]
 * @return {[type]}     [description]
 */
function deleteSMIndex(pid) {
  let parent = smIndexs[pid];
  if(parent.statement.statements) {
    for(sid in smIndexs) {
      let smIndex = smIndexs[sid];
      if(smIndex.pid==pid) {
        deleteSMIndex(smIndex.id);
      }
    }
  }
  delete smIndexs[pid];
}

function deleteSelectedStatement() {
  $("#divDesignerContainer").find(".del-img:visible").each(function() {
    deleteStatement($(this).prev());
  });
}

function unSelectStatement() {
  //$("#divDesignerContainer").find(".del-img").hide();
  $("#divDesignerContainer").find(".statement-item").css("outline", "");
}

function showTBSCode() {
  $("#divTBSCode").show();
  if(!tbsEditor) {
    let options = {
      mode: "javascript",
      lineNumbers: true,
      styleActiveLine: true,
      matchBrackets: true,
      selectionPointer: true,
      keyMap: "sublime",
      foldGutter: true,
      autoCloseBrackets: true,
      autofocus: true,
      gutters: ["CodeMirror-lint-markers", "CodeMirror-linenumbers", "CodeMirror-foldgutter"],
      hintOptions: {completeSingle: false},
      readOnly: true
    };
    tbsEditor = CodeMirror(document.getElementById("divTBSCode"), options);
    tbsEditor.setOption("theme", "monokai");
    $("#divTBSCode").find(".CodeMirror").css("width", "100%");
    $("#divTBSCode").find(".CodeMirror").css("height", $("#divTBSCode").height()+"px");
  }
  $("#divBaseInfo").hide();
  $("#divDesigner").hide();
  $("#divJSCode").hide();
  $("#divBottom").find("div").css("color", "#AAAAAA");
  $("#divBottom").find("div").css("background-color", "#333333");
  $("#divNavTBSCode").css("color", "#FFFFFF");
  $("#divNavTBSCode").css("background-color", "#444444");
  tbsEditor.setValue(JSON.stringify(curTBS, null, "\t"));
}

function showJSCode() {
  if(!jsEditor) {
    let options = {
      mode: "javascript",
      lineNumbers: true,
      styleActiveLine: true,
      matchBrackets: true,
      selectionPointer: true,
      keyMap: "sublime",
      foldGutter: true,
      autoCloseBrackets: true,
      autofocus: true,
      gutters: ["CodeMirror-lint-markers", "CodeMirror-linenumbers", "CodeMirror-foldgutter"],
      hintOptions: {completeSingle: false},
      readOnly: true
    };
    jsEditor = CodeMirror(document.getElementById("divJSCode"), options);
    jsEditor.setOption("theme", "monokai");
    $("#divJSCode").find(".CodeMirror").css("width", "100%");
    $("#divJSCode").find(".CodeMirror").css("height", $("#divJSCode").height()+"px");
  }
  $("#divBaseInfo").hide();
  $("#divDesigner").hide();
  $("#divTBSCode").hide();
  $("#divBottom").find("div").css("color", "#AAAAAA");
  $("#divBottom").find("div").css("background-color", "#333333");
  $("#divNavJSCode").css("color", "#FFFFFF");
  $("#divNavJSCode").css("background-color", "#444444");
  $("#divJSCode").show();  
  
  top.taskBuilder.requestByIPC("dev/service/tbs/compile", {tbs: curTBS}, function(req, res) {
    if(res.code!=0) {
      showMsg(res.message);
      return;
    }
    jsEditor.setValue(res.jsCode);
  });
}

function toggleCategoryItems(categoryId, ele) {
  $("#"+categoryId).toggle("fast");
  let imgIcon = $(ele).find("img").eq(0);
  if(imgIcon.attr("src")=="../taskbuilder-renderer/images/arrow/down.png") {
    imgIcon.attr("src", "../taskbuilder-renderer/images/arrow/right.png");
  } else {
    imgIcon.attr("src", "../taskbuilder-renderer/images/arrow/down.png");
  }
}

function addRequire(moduleInfo) {
  $("#divRequires").append("<div module-name=\""+moduleInfo.name
    +"\"><div style=\"color:#0099FF;\">·&nbsp;"+moduleInfo.name+"</div>"
    +"<img src=\"images/del.png\" style=\"float:right;margin-left:0;"
    +"margin-top:4px;display:none;\" title=\"删除\" onclick=\""
    +"deleteRequire($(this).parent())\"></div>");

  let newDiv = $("#divRequires").find("[module-name]").last();

  newDiv.mouseover(function() {
    $(this).find("img").show();
  });

  newDiv.mouseout(function() {
    $(this).find("img").hide();
  });
}

function addNewRequire() {
  var e = window.event;
  e.stopPropagation();

  let args = {
    fileTypes: ["service"]
  };

  openDialog("添加模块引用", "taskbuilder-tbs-designer/ModulePicker.html", "500px", "485px", 
    JSON.stringify(args), function(moduleInfo) {

    if(curTBS.requires) {
      for(var i=0;i<curTBS.requires.length;i++) {
        let r = curTBS.requires[i];
        if(r.name==moduleInfo.name) {
          showMsg("该模块已添加！");
          return;
        }
      }
    }

    if(!curTBS.requires) curTBS.requires = [];
    curTBS.requires.push(moduleInfo);
    
    addRequire(moduleInfo);
  });
}

function deleteRequire(divRequire) {
  let moduleName = divRequire.attr("module-name");
  divRequire.remove();
  if(curTBS.requires) {
    for(var i=0;i<curTBS.requires.length;i++) {
      let r = curTBS.requires[i];
      if(r.name==moduleName) {
        curTBS.requires.splice(i, 1);
        return;
      }
    }
  }
}

function addProp(prop) {
  $("#divProps").append("<div prop-name=\""+prop.name
    +"\"><div style=\"color:#0099FF;\">·&nbsp;"+prop.name+"</div>"
    +"<img src=\"images/del.png\" style=\"float:right;margin-left:0;"
    +"margin-top:4px;display:none;\" title=\"删除\" onclick=\""
    +"deleteProp($(this).parent())\"></div>");

  let newDiv = $("#divProps").find("[prop-name]").last();

  newDiv.click(function() {
    let propName = $(this).attr("prop-name");

    if(curTBS.props) {
      for(var i=0;i<curTBS.props.length;i++) {
        let p = curTBS.props[i];
        if(p.name==propName) {
          updateProp(p);
          return;
        }
      }
    }
  });

  newDiv.mouseover(function() {
    $(this).find("img").show();
  });

  newDiv.mouseout(function() {
    $(this).find("img").hide();
  });
}

function addNewProp() {
  var e = window.event;
  e.stopPropagation();

  openDialog("添加属性", "taskbuilder-tbs-designer/addProp.html", "360px", "220px", null, function(ret) {
    if(curTBS.props) {
      for(var i=0;i<curTBS.props.length;i++) {
        let p = curTBS.props[i];
        if(p.name==ret.name) {
          showMsg("该属性已添加！");
          return;
        }
      }
    }

    if(!curTBS.props) curTBS.props = [];
    curTBS.props.push(ret);

    addProp(ret);
  });
}

function updateProp(propInfo) {
  openDialog("修改属性", "taskbuilder-tbs-designer/addProp.html", "360px", "220px", 
    JSON.stringify(propInfo), function(ret) {
    let oldName = propInfo.name;
    if(curTBS.props) {
      for(var i=0;i<curTBS.props.length;i++) {
        let p = curTBS.props[i];
        if(p.name==ret.name && ret.name!=oldName) {
          showMsg("该属性已添加！");
          return;
        }
      }
      for(var i=0;i<curTBS.props.length;i++) {
        let p = curTBS.props[i];
        if(p.name==oldName) {
          p.name = ret.name;
          p.type = ret.type;
          p.value = ret.value;
          break;
        }
      }
    }
    let divVar = $("#divProps").find("[prop-name='"+oldName+"']");
    divVar.attr("prop-name", ret.name);
    divVar.find("div").html("·&nbsp;"+ret.name);
  });
}

function deleteProp(divProp) {
  let propName = divProp.attr("var-name");
  divProp.remove();
  if(curTBS.props) {
    for(var i=0;i<curTBS.props.length;i++) {
      let p = curTBS.props[i];
      if(p.name==propName) {
        curTBS.props.splice(i, 1);
        return;
      }
    }
  }
}

function addMethod(method) {
  $("#divMethods").append("<div method-name=\""+method.name+"\">"
    +"<div style=\"color:#0099FF;\">·&nbsp;"+method.name+"</div></div>");
  let newDiv = $("#divMethods").find("[method-name]").last();
  if(method.name!="process") {
    newDiv.append("<img src=\"images/del.png\" style=\"float:right;margin-left:0;"
    +"margin-top:4px;display:none;\" title=\"删除\" onclick=\""
    +"deleteMethod($(this).parent())\"><img src=\"images/edit.png\" "
    +"style=\"float:right;margin-left:0;margin-right:3px;margin-top:4px;display:none;\" "
    +"title=\"修改\" onclick=\"updateMethod($(this).parent())\">");
  }

  newDiv.click(function() {
    selectMethod(method);
  });

  newDiv.mouseover(function() {
    $(this).find("img").show();
  });

  newDiv.mouseout(function() {
    $(this).find("img").hide();
  });
}

function addNewMethod() {
  var e = window.event;
  e.stopPropagation();

  openDialog("添加函数", "taskbuilder-tbs-designer/addMethod.html?isAdd=true", "430px", "480px", null, function(method) {
    if(curTBS.methods) {
      for(var i=0;i<curTBS.methods.length;i++) {
        let m = curTBS.methods[i];
        if(m.name==method.name) {
          showMsg("该函数已存在！");
          return;
        }
      }
    }
    if(!curTBS.methods) curTBS.methods = [];
    curTBS.methods.push(method);

    addMethod(method);
    selectMethod(method);
  });
}

function showFuncCode(method) {
  if(!methodEditor) {
    let options = {
      mode: "javascript",
      lineNumbers: true,
      styleActiveLine: true,
      matchBrackets: true,
      selectionPointer: true,
      keyMap: "sublime",
      foldGutter: true,
      autoCloseBrackets: true,
      autofocus: true,
      gutters: ["CodeMirror-lint-markers", "CodeMirror-linenumbers", "CodeMirror-foldgutter"],
      hintOptions: {completeSingle: false}
    };
    methodEditor = CodeMirror(document.getElementById("divMethodCodeEditor"), options);
    methodEditor.setOption("theme", "monokai");
  }
  methodEditor.on("blur", function(cm) { 
    let code = methodEditor.getValue();
    code = code.substring(code.indexOf("{")+2, code.lastIndexOf("}"));
    curMethod.code = code;
  });
  $("#divDesignerLib").hide();
  $("#divDesignerContainer").hide();
  $("#divMethodCode").show();
  $("#divMethodCodeEditor").find(".CodeMirror").css("width", "100%");
  $("#divMethodCodeEditor").find(".CodeMirror").css("height", $("#divMethodCodeEditor").height()+"px");
  setMethodCode(method);
}

function commentFuncCode() {
  var slt = methodEditor.doc.listSelections()[0];
  if(slt.anchor.ch==0&&slt.anchor.line==0&&
    slt.head.ch==0&&slt.head.line==0) return;
  if(slt.anchor.line==slt.head.line) {
    methodEditor.lineComment(slt.head, slt.anchor);
  } else {
    slt.head.ch = 1;
    slt.anchor.ch = methodEditor.doc.getLine(slt.anchor.line).length;
    methodEditor.blockComment(slt.head, slt.anchor);
  }
};

function insertSysFunc() {
  let args = {};
  args.curTBSMethods = [];
  for(var i=0;i<curTBS.methods.length;i++) {
    let method = curTBS.methods[i];
    if(method.name=="process") continue;
    args.curTBSMethods.push({
      name: method.name,
      comment: method.comment,
      args: method.args
    });
  }
  openDialog("修改方法", "taskbuilder-tbs-designer/FuncSetting.html", "640px", "560px", 
    JSON.stringify(args), function(ret) {
    if (ret && ret.statement) {
      var slt = methodEditor.doc.listSelections()[0];
      if(slt.anchor.line==0 || slt.head.line==0) {
        methodEditor.setSelection({line:1, ch: 2}, {line:1, ch: 2});
      }
      methodEditor.replaceSelection(ret.statement);
      methodEditor.focus();
    }
  });
}

function uncommentFuncCode() {
  var slt = methodEditor.doc.listSelections()[0];
  if(slt.anchor.ch==0&&slt.anchor.line==0&&
    slt.head.ch==0&&slt.head.line==0) return;
  methodEditor.uncomment(slt.head, slt.anchor);
};

function toggleWrapFuncCode(div) {
  var lineWrapping = methodEditor.getOption("lineWrapping");
  if(lineWrapping) {
    methodEditor.setOption("lineWrapping", false);
    $(div).css("background-color", "");
    $(div).css("margin", "3px");
    $(div).css("border", "0");
  } else {
    methodEditor.setOption("lineWrapping", true);
    $(div).css("background-color", "#333");
    $(div).css("margin", "2px");
    $(div).css("border", "1px solid #999999");
  }
};

function setMethodCode(method) {
  let funcCode = "function "+method.name+"(";
  for(var i=0;i<method.args.length;i++) {
    if(i>0) funcCode += " , ";
    funcCode += method.args[i].name;
  }
  funcCode += ") {\r\n";
  if(method.code) {
    funcCode += method.code;
  } else {
    funcCode += "\r\n";
  }
  funcCode += "}";
  methodEditor.setValue(funcCode);
}

function selectMethod(method) {
  if(curMethod && curMethod.name == method.name) return;

  if(curMethod) {
    $("#divMethods").find("[method-name='"
      +curMethod.name+"']").css("background-color", "");
    $("#divMethods").find("[method-name='"
      +curMethod.name+"']").find("div").css("background-color", "");
  }
  curMethod = method; 
  $("#divMethods").find("[method-name='"
    +curMethod.name+"']").css("background-color", "#555555");
  $("#divMethods").find("[method-name='"
    +curMethod.name+"']").find("div").css("background-color", "#555555");

  if(method.editType=="code") {
    showFuncCode(method);
  } else {
    $("#divMethodCode").hide();
    $("#divDesignerLib").show();
    $("#divDesignerContainer").show();

    curSMIndex = 1;
    smIndexs = {};
    $("#divDesignerContainer").empty();
    if(method.statements) {
      for(var i=0;i<method.statements.length;i++) {
        let statement = method.statements[i];
        let stype = StatementTypes[statement.category+"_"+statement.type];
        addStatement($("#divDesignerContainer"), stype, statement);
      }
    }
  }
}

function updateMethod(divMethod) {
  var e = window.event;
  e.stopPropagation();

  let methodName = divMethod.attr("method-name");
  let method = null;
  
  if(curTBS.methods) {
    for(var i=0;i<curTBS.methods.length;i++) {
      let m = curTBS.methods[i];
      if(m.name==methodName) {
        method = m;
        break;
      }
    }
  }

  if(!method) return;

  let methodTmp = {
    name: method.name,
    args: method.args
  };

  if(method.comment) methodTmp.comment = method.comment;
  if(method.retType) methodTmp.retType = method.retType;

  openDialog("修改方法", "taskbuilder-tbs-designer/addMethod.html?isUpdate=true", "430px", "430px", 
    JSON.stringify(methodTmp), function(methodNew) {
    if(curTBS.methods) {
      for(var i=0;i<curTBS.methods.length;i++) {
        let m = curTBS.methods[i];
        if(m.name==methodNew.name && methodNew.name!=method.name) {
          showMsg("该方法已存在！");
          return;
        }
      }
      for(var i=0;i<curTBS.methods.length;i++) {
        let m = curTBS.methods[i];
        if(m.name==method.name) {
          m.name = methodNew.name;
          m.comment = methodNew.comment;
          m.args = methodNew.args;
          m.retType = methodNew.retType;
          break;
        }
      }
    }
    
    if(methodTmp.name!=methodNew.name) {
      let funcDiv = $("#divMethods").find("[method-name='"+methodTmp.name+"']");
      funcDiv.attr("method-name", methodNew.name);
      funcDiv.find("div").html("·&nbsp;"+methodNew.name);
    }

    if(curMethod.name==method.name) setMethodCode(curMethod);
  });
}

/**
 * [deleteMethod description]
 * @param  {[type]} divMethod [description]
 * @return {[type]}           [description]
 */
function deleteMethod(divMethod) {
  let methodName = divMethod.attr("method-name");
  divMethod.remove();
  if(curTBS.methods) {
    for(var i=0;i<curTBS.methods.length;i++) {
      let m = curTBS.methods[i];
      if(m.name==methodName) {
        curTBS.methods.splice(i, 1);
        break;
      }
    }
  }
  if(curMethod && curMethod.name==methodName) {
    curMethod = null;
    selectMethod(curTBS.methods[0]);
  }
}

function checkSMInput(method, sm) {
  let smType = StatementTypes[sm.category+"_"+sm.type];
  if(smType.inputs) {
    for(var i=0;i<smType.inputs.length;i++) {
      let ipt = smType.inputs[i];
      let iptVal = sm[ipt.name];
      if(ipt.name=="model.name") iptVal = sm.model.name;
      if(ipt.required && !iptVal && iptVal!=0) {
        alert("["+method.name+"]方法的["+smType.comment+"]语句的["+ipt.comment+"]参数不能为空！");
        return false;
      }
    }
  }
  if(sm.statements && sm.statements.length>0) {
    for(var i=0;i<sm.statements.length;i++) {
      let ret = checkSMInput(method, sm.statements[i]);
      if(!ret) return false;
    }
  }
  return true;
}

function getMethod(name) {
  for(var i=0;i<curTBS.methods.length;i++) {
    let method = curTBS.methods[i];
    if(method.name==name) return method;
  }
  return null;
}

function setCurTBS(cb) {
  let serviceNameStr = serviceName.val();
  if(serviceNameStr.trim()=="") {
    showMsg("请输入服务名称！");
    if($("#divBaseInfo").is(":visible")) serviceName.focus();
    return;
  }
  if(serviceNameStr.match(/[^\w]/g)) {
    showMsg("服务名称只能包含字母、数字或下划线！");
    if($("#divBaseInfo").is(":visible")) serviceName.focus();
    return;
  }
  if(serviceNameStr.length<3) {
    showMsg("服务名称不能少于3个字符！");
    if($("#divBaseInfo").is(":visible")) serviceName.focus();
    return;
  }
  curTBS.name = serviceNameStr.substr(0,1).toUpperCase()+serviceNameStr.substr(1);
  if(serviceComment.val()) curTBS.comment = serviceComment.val();
  let secSetting = cbSecSetting.val()+"";
  curTBS.notCheckLogin = secSetting.indexOf("notCheckLogin")>=0 ? true : false;
  curTBS.notCheckAuthority = secSetting.indexOf("notCheckAuthority")>=0 ? true : false;
  curTBS.notCheckSQLInject = secSetting.indexOf("notCheckSQLInject")>=0 ? true : false;

  dataset1.getRows(null, function(reqArgs){
    curTBS.reqArgs = reqArgs;
    dataset2.getRows(null, function(resArgs){
      curTBS.resArgs = resArgs;

      if(notSaveMethods.length>0) {
        for(var i=0;i<notSaveMethods.length;i++) {
          let method = getMethod(notSaveMethods[i]);
          if(method.statements && method.statements.length>0) {
            for(var j=0;j<method.statements.length;j++) {
              if(!checkSMInput(method, method.statements[j])) return;
            }
          }
        }
      }

      if(cb) cb();
    });
  });
};

function saveTBS() {
  setCurTBS(function() {
    top.taskBuilder.requestByIPC("dev/service/proj/saveFileContent", {filePath: servicePath, 
      data: JSON.stringify(curTBS, null, "\t")}, 
      function(req, res) {
      if(res.code!=0) {
        showMsg(res.message);
        return;
      }
      notSaveMethods = [];
      showMsg("保存成功！");
    });
  });
}

function saveAs() {
  /*let args = {
    path: servicePath,
    filename: tb.getFileName(servicePath),
    onlyDir: true,
    listServerFile: true
  };
  openDialog("选择保存路径", "taskbuilder-tfp-designer/PathPicker.html", "480px", "480px",
    JSON.stringify(args), function (ret) {
    console.log(ret);
  });*/
  tb.showSaveFileDialog({
    defaultPath: tb.getFileName(servicePath),
    filters: [
      { name: 'tbs', extensions: ['tbs'] },
      { name: 'js', extensions: ['js'] }
    ]
  }, function (filename) {
    if(!filename) return;
    setCurTBS(function() {
      if(filename.toLowerCase().endsWith(".tbs")) {
        tb.saveFile(filename, JSON.stringify(curTBS, null, "\t"));
      } else {
        top.taskBuilder.requestByIPC("dev/service/tbs/compile", {tbs: curTBS}, function(req, res) {
          if(res.code!=0) {
            showMsg(res.message);
            return;
          }
          tb.saveFile(filename, res.jsCode);
        });
      }
    });
  });
  /*window.parent.showSaveFileDialog({
    filters: [
      { name: 'tbs', extensions: ['tbs'] },
      { name: 'js', extensions: ['js'] }
    ]
  }, function(filename) {
  });*/
};

function test() {
  openPage("测试后台服务", "taskbuilder-tbs-designer/requester.html?path="+servicePath);
}

let cptStyles = [];

function parseCptStyles(dataModel, parent) {
  var cpt = tfp.components[dataModel.id];
  var Render = tfp.renders[dataModel.type];
  var render = new Render(tfp, dataModel, cpt.level);
  let cptStyle = render.getStyleHtml(true);
  if(cptStyle) cptStyles.push({id: cpt.id, style: cptStyle});
  if(dataModel.components) {
    for(var i=0;i<dataModel.components.length;i++) {
      let cdmChild = dataModel.components[i];
      let cptChild = parseCptStyles(cdmChild, cpt);
    }
  }
}

$(function() {
  var pageDM = JSON.parse(top.taskBuilder.readFileSync("/node_modules/taskbuilder-tbs-designer/baseInfo.tfp"));

  tfp.rootPath = "../tfp";
  tfp.loadPage(pageDM, function() {
    tfp.initCptRuntime(tfp.curPage);
    parseCptStyles(pageDM);
    let cssCode = "";

    //添加页面组件的CSS
    if(cptStyles.length>0) {
      for(var i=0;i<cptStyles.length;i++) {
        let ss = cptStyles[i];
        cssCode += "\t\t#"+ss.id+" {"+ss.style+"}\r\n";
      }
    }

    if(cssCode!="") $("head").append("<style>"+cssCode+"</style>");

    //加载TBS
    servicePath = tfp.getUrlArg("path");
    top.taskBuilder.requestByIPC("dev/service/proj/getFileContent",
      {filePath: servicePath}, function(req, res) {
      if(res.code!=0) {
        showMsg(res.message);
        return;
      }
      curTBS = JSON.parse(res.data);
      serviceName.val(curTBS.name);
      if(curTBS.comment) serviceComment.val(curTBS.comment)
      let arrSec = [];
      if(curTBS.notCheckLogin) arrSec.push("notCheckLogin");
      if(curTBS.notCheckAuthority) arrSec.push("notCheckAuthority");
      if(curTBS.notCheckSQLInject) arrSec.push("notCheckSQLInject");
      if(arrSec.length>0) cbSecSetting.val(arrSec.join(","));
      if(curTBS.reqArgs) dataset1.rows = curTBS.reqArgs;
      if(curTBS.resArgs) dataset2.rows = curTBS.resArgs;
      if(curTBS.requires && curTBS.requires.length>0) {
        for(var i=0;i<curTBS.requires.length;i++) {
          addRequire(curTBS.requires[i]);
        }
      }
      if(curTBS.props && curTBS.props.length>0) {
        for(var i=0;i<curTBS.props.length;i++) {
          addProp(curTBS.props[i]);
        }
      }
      if(curTBS.methods && curTBS.methods.length>0) {
        for(var i=0;i<curTBS.methods.length;i++) {
          addMethod(curTBS.methods[i]);
        }
      }

      showDesigner();
    });
  });
});