fcf.module({
  name: "fcf:NRender/TaskInfo.js",
  dependencies: ["fcf:NRender/NDetails/Helper.js"],
  module: function(helper) {
    var NRender = fcf.prepareObject(fcf, "NRender");

    /**
    * @class fcf::NRender::TaskInfo
    * @brief Класс задачи рендеринга шаблона
    **/
    NRender.TaskInfo = function(a_options) {
      var self = this;
      fcf.append(this, a_options);

      this._callMap = {};


      /**
      * @var object args;
      *lng_en @brief The resulting template arguments
      *lng_ru @brief Результирующие аргументы шаблона
      **/

      /**
      * @var fcf::NRender::Render render
      *lng_en @brief Render object
      *lng_ru @brief Объект рендера
      **/


      /**
      * @var object srcArgs
      *lng_en @brief Description of template arguments waiting to be build
      *lng_ru @brief Описание аргументов шаблона ожидающие сборки
      **/

      /**
      * @var fcf::Actions actions
      *lng_ru @brief Объект отложенных вызовов функций
      **/

      /**
      * @var fcf::RouteInfo route
      *lng_en @brief The object of the description of the current route
      *lng_ru @brief Объект описания текущего маршрута
      **/

      /**
      * @var string templatePath
      *lng_en @brief Template address
      *lng_ru @brief Адрес шаблона
      **/

      /**
      * @fn void setArg(string a_path, mixed a_value)
      *
      *lng_en @brief To set a variable of the template used in the hooks.
      *lng_en @brief After calling this method, the a_path argument will not be automatically assembled
      *lng_en @param string a_path The path/filename argument
      *lng_en @param mixed a_value New value
      *
      *lng_ru @brief Установить переменную шаблона, используется в хуках.
      *lng_ru @brief После вызова данного метода автоматическая сборка аргумента a_path выполняться не будет
      *lng_ru @param string a_path Путь/имя аргумента
      *lng_ru @param mixed a_value Устанавливаемое значение
      **/
      this.setArg = function(a_path, a_value){
        this.owner._callHookBeforeArgument(this, a_path);
        this.args[a_path] = a_value;
        delete this.srcArgs[a_path];
        if (!(a_path in this.fullSrcArgs))
          this.fullSrcArgs[a_path] = a_value;
        this.processedArgs[a_path] = true;
        this.owner._callHookAfterArgument(this, a_path);
      }


      /**
      * void render(object a_options)
      *lng_en @brief performs rendering of the template
      *lng_en   - string template Path to the template
      *lng_en   - string args     Template arguments
      *lng_en   - function onResult(a_error, a_template)
      *
      *lng_ru @brief выполняет рендер шаблона
      *lng_ru   - string template Путь к шаблону
      *lng_ru   - string args     Аргументы шаблона
      *lng_ru   - function onResult(a_error, a_template)
      **/
      this.render = function(a_options){
        let self = this;
        var fcfCP = this._getCallPosition();
        var inheritArgs = {};

        helper.appendChildInfo(inheritArgs, {fcfCP: fcfCP}, this.args.fcfChildsArgs);
        var args = fcf.append({}, a_options.args, inheritArgs, { fcfParent: this.args.fcfId, fcfCP: fcfCP});

        return fcf.actions()
        .then(()=>{
          return self.loader.loadInfo(a_options.template)
        })
        .then((a_template)=>{
          let block = a_options.template.split("+")[1];
          if (!block)
            block = "";
          if (!a_template.templates[block])
            return;
          if (!a_template.templates[block].hooks.hookRender)
            return;
          return a_template.templates[block].hooks.hookRender({
              args:            self.args,
              renderedOptions: a_template.options,
              renderedArgs:    args,
              renderedPath:    a_options.template,
            });
        })
        .then(()=>{
          return this._render.render({
            theme:      this.state.theme,
            template:   a_options.template,
            args:       args,
            state:      this.state,
            request:    this.request,
            reqursion:  true,
            onResult:   a_options.onResult
          })
        });

          // if (!a_template)
          //   return;
          // let block = template.split("+")[1];
          // if (!block)
          //   block = "";
          // if (!a_template.templates[block])
          //   return;
          // if (!a_template.templates[block].hooks.hookBeforeView)
          //   return;
          // let hookOptions = {
          //   record: a_templateInfo.options.record,
          //   view:   a_templateInfo.options.view,
          //   mode:   a_templateInfo.options.mode,
          //   args:   options.args,
          // }
          // if (fcf.isArg(hookOptions.record)){
          //   if (hookOptions.record.type === "reference") {
          //     hookOptions.record = fcf.resolve(a_options.state.args[hookOptions.record.object.id], hookOptions.record.arg);
          //   } else if (hookOptions.record.type === "value") {
          //     hookOptions.record = fcf.tokenizeObject(hookOptions.record.value, {}, true);
          //   }
          // }
          // return a_template.templates[block].hooks.hookBeforeView(hookOptions);
          //})
      }


      this._getCallPosition = function(){
        var stackArr = (new Error).stack.split("\n");
        var strInfo  = fcf.trim(stackArr[0].indexOf(":") == -1 ? stackArr[3] : stackArr[2], [" ", ")"]);
        var callPostition = "";
        var dc = 0;
        if (strInfo.length) {this._callMap
          var charCode0 = "0".charCodeAt(0);
          var charCode9 = "9".charCodeAt(0);
          for (var i = strInfo.length-1; i >= 0; --i) {
            var charCode = strInfo.charCodeAt(i);
            if (charCode >= charCode0 && charCode <= charCode9)
              continue;
            ++dc;
            if (dc >= 2){
              callPostition = strInfo.substr(i+1);
              break;
            }
          }
        }

        var cp = "hook:"+callPostition;
        if (!(cp in this._callMap))
          this._callMap[cp] = 0;
        cp += "-" + (++this._callMap[cp]);
        return cp;
      }

    }

    return NRender.TaskInfo;
  }
});
