fcf.module({
  name: "fcf:NFSQL/NFunction/Title.js",
  dependencies: ["fcf:NFSQL/NFunction/Function.js"],
  module: function(Function) {
    var NFunction = fcf.prepareObject(fcf, "NFSQL.NFunction");

    NFunction.Title = function() {
      Function.call(this);

      this.processFunction = function(a_taskInfo, a_info){
        let from = a_info.function.from ? a_info.function.from : a_taskInfo.query.from;
        let projection = a_taskInfo.getProjection(from);
        let template = projection.singleTitle;

        function clFindReplacement(a_str, a_startPos){
          let result = {
            startPos: -1,
            endPos: -1,
          }

          let pos1 = a_str.indexOf("${", a_startPos);
          let pos2 = a_str.indexOf("#{", a_startPos);
          let pos3 = a_str.indexOf("@{", a_startPos);
          let pos  = pos1 != -1 && (pos1 < pos2 || pos2 == -1) && (pos1 < pos3 || pos3 == -1) ? pos1 :
                     pos2 != -1 && (pos2 < pos1 || pos1 == -1) && (pos2 < pos3 || pos3 == -1) ? pos2 :
                                                                                                pos3;
          if (pos == -1)
            return result;

          let endstr = pos1 == pos ? "}$" :
                       pos2 == pos ? "}#" :
                                     "}@";
          let endpos = a_str.indexOf(endstr, pos);
          if (endpos == -1)
            return result;

          result.startPos = pos;
          result.endPos   = endpos+2;
          return result;
        }

        let arr = [];
        let pos = 0;
        let endpos = template.length-1;
        let text = true;
        while(pos != -1) {
          let replacementPositions = clFindReplacement(template, pos);
          if (replacementPositions.startPos == -1)
            break;

          let text = template.substr(pos, replacementPositions.startPos  - pos);
          if (!fcf.empty(text))
            arr.push({ text: text });
          arr.push({ value: template.substr(replacementPositions.startPos  + 2, replacementPositions.endPos - replacementPositions.startPos  - 4) });

          pos = replacementPositions.endPos;
        }

        if (endpos != template.length)
          arr.push({ text: template.substr(pos, template.length - pos)});

        if (arr.length == 0)
          arr.push({ value: "" });

        a_info.function.function = "concat";
        a_info.function.args = [];
        fcf.each(arr, (a_key, a_item) => {
          if ("text" in a_item) {
            a_info.function.args.push({value: a_item.text});
          } else {
            let fieldAlias = fcf.parseObjectAddress(a_item.value)[1];
            let fieldDesc  = projection.fieldsMap[fieldAlias];
            if (!fieldDesc)
              return;
            let fieldInfo = { part: "where", field: {field: fieldAlias, from: from} };
            let filter = fcf.getFilter(fieldDesc.type);
            filter.processWhereField(a_taskInfo, fieldInfo);
            a_info.function.args.push(fieldInfo.field);
          }
        })

        a_info.function.recommendedAs = "title()";
      }

    }

    return NFunction.Title;
  }
});
