fcf.module({
  name: "fcfControls:templates/step-navigator.hooks.js",
  dependencies: [],
  module: function(){
    return {
      //
      // 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
      //
      hooksProgramableArgument: {
        backLink: async (a_taskInfo)=>{
          let root = fcf.rtrim(a_taskInfo.args.root, "/");
          let froot = root+"/";
          let node = await fcf.application.getRouter().getNode(a_taskInfo.args.current);
          if (!node || !node.node)
            return;
          let currentUri = node.node.uri;
          let parentUri = node.node.parent;
          let parentNode = await fcf.application.getRouter().getNode(parentUri, 1);
          if (!parentNode || !parentNode.node)
            return;
          let lastUri    = undefined;
          let foundBottomUri = undefined;
          for(let key in parentNode.node.parts){
            if (parentNode.node.parts[key].uri == currentUri) {
              if (lastUri === undefined)
                break;
              foundBottomUri = lastUri.indexOf(froot) == 0 && (!a_taskInfo.args.excludeRootNode || fcf.rtrim(lastUri,"/") != root) ? lastUri : undefined;
              break;
            }
            lastUri = parentNode.node.parts[key].uri;
          }

          if (foundBottomUri){
            let protectedCounter = 0;
            while(protectedCounter < 100){
              let node = await fcf.application.getRouter().getNode(foundBottomUri, 1);
              if (!node || !node.node)
                return;
              if (fcf.empty(node.node.parts))
                return foundBottomUri.indexOf(froot) == 0 && (!a_taskInfo.args.excludeRootNode || fcf.rtrim(foundBottomUri,"/") != root) ? foundBottomUri : undefined;
              foundBottomUri = fcf.last(node.node.parts).uri;
              ++protectedCounter;
            }
          }

          return node.node.parent.indexOf(froot) == 0 && (!a_taskInfo.args.excludeRootNode || fcf.rtrim(node.node.parent,"/") != root) ? node.node.parent : undefined;
        },
        nextLink: async (a_taskInfo)=>{
          let node = await fcf.application.getRouter().getNode(a_taskInfo.args.current, 1);
          if (!node || !node.node)
            return;
          let subNode = fcf.first(node.node.parts);
          if (subNode){
            return subNode.uri.indexOf(a_taskInfo.args.root) == 0 ? subNode.uri : undefined;
          } else {
            let parentUri = node.node.parent;
            let currentUri = node.node.uri;
            let protectedCounter = 0;
            while(protectedCounter < 100) {
              let parentNode = await fcf.application.getRouter().getNode(parentUri, 1);
              if (!parentNode || !parentNode.node)
                return;
              let eq = false;
              for(let key in parentNode.node.parts){
                if (parentNode.node.parts[key].uri == currentUri){
                  eq = true;
                  continue;
                }
                if (eq)
                  return parentNode.node.parts[key].uri.indexOf(a_taskInfo.args.root) == 0 ? parentNode.node.parts[key].uri : undefined;
              }

              currentUri = parentUri;
              parentUri = parentNode.node.parent;

              ++protectedCounter;
            }
          }
        }
      },

      //
      // Object of the hooks preprocessing of the template arguments
      //
      // hooksBeforeArgument: {
      //   //
      //   // @result Can return the value of an argument or Promise or undefined
      //   //
      //   ARG_NAME: (a_taskInfo)=>{
      //   }
      // },

      //
      // Object of the hooks postprocessing of the template arguments
      // hooksAfterArgument: {
      //   //
      //   // @result Can return the value of an argument or Promise or undefined
      //   //
      //   ARG_NAME: (a_taskInfo)=>{
      //   }
      // },
    };
  }
});
