fcf.module({
  name: "fcfDBControls:templates/form.hooks.js",
  dependencies: ["fcfControls:templates/form.hooks.js"],
  module: function(baseHooks){
    return {
      /**
      * void async hookSubtemplateRender(a_options)
      * @brief Called when rendering from the current template
      * @param a_options
      *           object args arguments of current template
      *           object renderedArgs [modify] initial parameters of template arguments
      *           object renderedOptions template options
      *           string renderedPath path to the template being rendered
      **/
      hookSubtemplateRender: (a_options) => {
        if (!a_options.renderedOptions.multilingual)
          return;
        let alias = a_options.renderedArgs.fcfAlias;
        if (fcf.empty(alias))
          return;
        let languages = fcf.application.getSystemVariable("fcf:languages");
        for(let lang in languages)
          a_options.renderedArgs[`value@${lang}`] = fcf.argRef(`value@${lang}["${alias}"]`);
        a_options.renderedArgs[`@language`]  = fcf.argRef("language");
        a_options.renderedArgs[`@languages`] = languages;
      },

      //
      // void hookBeforeBuild(a_taskInfo)
      // The hook is executed before assembling the template arguments
      //
      // hookBeforeBuild: function(a_taskInfo) {
      // },

      //
      // void hookAfterBuild(a_taskInfo)
      // The hook is executed after assembling the template arguments
      //
      // hookAfterBuild: function(a_taskInfo) {
      // },

      //
      // void hookAfterBuild(a_taskInfo)
      // The hook is executed after building the template's system arguments
      //
      // hookAfterSystemBuild: function(a_taskInfo) {
      // },

      //
      // Object of hooks for programmatically populated arguments
      //
      hooksProgrammableArgument: {
        language: (a_taskInfo)=>{
          return fcf.application.getSystemVariable("fcf:defaultLanguage");
        },
        languages: (a_taskInfo)=>{
          return fcf.application.getSystemVariable("fcf:languages");
        },
      },

      hooksBeforeArgument: {
        value: async (a_taskInfo) => {
          if (`value@${a_taskInfo.args.language}` in a_taskInfo.fullSrcArgs)
            return;

          let realValue = undefined;

          if (!fcf.isArg(a_taskInfo.srcArgs.value) ||
              a_taskInfo.srcArgs.value.type != "reference" ||
              a_taskInfo.srcArgs.value.object.id != a_taskInfo.args.fcfId) {
            realValue = await a_taskInfo.buildArg(a_taskInfo.srcArgs.value);
            a_taskInfo.srcArgs.value = fcf.argRef("value@@{{args.language}}@", { dependencies:["languages", "mode"] });
            a_taskInfo.fullSrcArgs.value = a_taskInfo.srcArgs.value;
          }

          let projection = fcf.application.getProjections().get(a_taskInfo.args.projection);

          for(let lang in a_taskInfo.args.languages) {
            if (a_taskInfo.srcArgs[`value@${lang}`]){
              continue;
            }
            if (a_taskInfo.args.projection && a_taskInfo.args.key) {
              let records = await fcf.application.getStorage().query({
                              query: {
                                type:     "select",
                                language: lang,
                                from:     a_taskInfo.args.projection,
                                fields:   [{field: "*"}],
                                where:    [{ logic: "and", type: "=", args: [{field: projection.key}, {value: a_taskInfo.args.key}]}],
                              }
                            });

              await a_taskInfo.setArg(`value@${lang}`, fcf.append(records[0][0], realValue));
            } else {
              await a_taskInfo.setArg(`value@${lang}`, fcf.append({}, realValue));
            }
          }
        }
      },

      hooksAfterArgument: {
        fields: (a_taskInfo)=>{
          let fields = [];
          let projection = fcf.application.getProjections().get(a_taskInfo.args.projection);
          if (fcf.empty(a_taskInfo.args.fields)){
            fcf.append(true, fields, projection.fields);
          } else {
            let result = [];
            fcf.each(a_taskInfo.args.fields, (k, a_field)=>{
              let resField;

              if (typeof a_field === "string") {
                resField = projection.fields[fcf.find(projection.fields, (k,v)=>{ return v.alias === a_field})];
              } else {
                resField = projection.fields[fcf.find(projection.fields, (k,v)=>{ return v.alias === a_field.alias})];
                resField = fcf.append(true, {}, resField, a_field);
              }

              if (!resField) {
                resField = {
                  alias: a_field,
                  title: a_field,
                  field: a_field,
                  type:  "text",
                };
              }

              if (resField.inner)
                return;

              fields.push(fcf.append(true, {}, resField));
            })
          }

          fcf.each(fields, (a_key, a_field)=>{
            fields[a_key] = fcf.buildView(a_field, a_taskInfo.args.mode);
          })

          // remove fields
          let resultFields = [];
          let modPart = a_taskInfo.args.mode.split(".")[0];
          fcf.each(fields, (a_key, a_field)=>{
            if ( !(modPart === "edit" && a_field.notEdit)  &&
                 !(modPart === "add" && a_field.notAdd) ){
              resultFields.push(a_field);
            }
          })


          a_taskInfo.args.fields = resultFields;
          baseHooks.hooksAfterArgument.fields(a_taskInfo);
        },

        _enableTranslations: (a_taskInfo)=>{
          return fcf.application.getProjections().get(a_taskInfo.args.projection).translate &&
                 a_taskInfo.args.enableTranslations &&
                 fcf.count(fcf.application.getSystemVariable("fcf:languages"))>1;
        },

        defaultLanguage: (a_taskInfo)=>{
          return fcf.application.getSystemVariable("fcf:defaultLanguage");
        }
      },
    };
  }
});
