fcf.module({
  name: "fcf:NServer/NControllers/Render.js",
  dependencies: ["fcf:NServer/NServer.js",
                 "fcf:NServer/NControllers/Controller.js",
                 "fcf:NEvent/PreprocessControllerTmpl.js",
                 "fcf:NTools/json.js",
                 ],
  module: function(NServer, Controller, EventPreprocessControllerTmpl, json) {
    fcf.prepareObject(fcf, "NServer.NControllers");

    fcf.addException("ERROR_CONTROLLER_RENDER_FSQL_DENIED", "FSQL queries are not allowed for on-demand rendering");

    NServer.NControllers.Render = class Render extends Controller {

      constructor(a_options){
        super(a_options);
        this.packagesArg = {};
        this._options = fcf.append(
                          {
                            args: {},
                            controller: "fcf:NServer/NControllers/Render.js",
                            source: "",
                          },
                          this._options,
                          a_options
                        );
        this.userImportance = true;
      }

      action(a_request) {
        let self = this;
        let actions = fcf.actions();
        let preprocessControllerTmpl = new EventPreprocessControllerTmpl({
              owner: self,
              actions: actions,
              packagesArg: self.packagesArg,
              request: a_request,
        });

        fcf.application.getEventChannel().send(preprocessControllerTmpl);
        actions.then(()=>{
          self._action(a_request);
        })
        actions.catch((a_error)=>{
          self._action(a_request, a_error);
        })
      }

      _action(a_request, a_errorAction){
        let self = this;
        if (a_errorAction){
          a_request.sendErrorPage(a_errorAction);
          return;
        }

        let render = fcf.application.getRender();

        let modules = {};
        for(let k in fcf.settings.libraries) {
          let uri = fcf.getPath(k+":", false);
          modules[k] = uri.substr(0, 1) != "/" ? "/" + uri : uri;
        }

        let args     = typeof a_request.getRouteData().args.args == "object" ? a_request.getRouteData().args.args : {};
        let template = a_request.getRouteData().args.template;
        let url      = a_request.getRouteData().args.url;
        let routeInfo = new fcf.RouteInfo(url);
        let externalArgs = a_request.getRouteData().args.externalArgs;
        let needProcessPostRemove = false;

        fcf.application.getRouter().getNode(routeInfo.uri)
        .then((a_nodeInfo)=>{
          if (!a_nodeInfo)
            throw new fcf.Exception("ERROR_404", {"address": url});
          fcf.append(routeInfo.args, a_nodeInfo.args);
          delete routeInfo.args.externalArgs;
          fcf.getContext().route       = routeInfo;
          fcf.getContext().route.title = a_nodeInfo.title;
          fcf.append(fcf.getContext().route.args, a_nodeInfo.args);

          fcf.application.getRender().render( {
                                              template: template,
                                              args:     args,
                                              external: true,
                                              route:    routeInfo,
                                              context:  fcf.getContext(),
                                              request:  a_request,
                                              externalArgs: externalArgs,
                                              onResult: function(a_error, a_template) {
                                                  if (a_error) {
                                                    a_request.sendError(a_error);
                                                    return;
                                                  }

                                                  try {
                                                    a_request.send(JSON.stringify(a_template));
                                                  } catch(e){
                                                    a_request.sendError(e);
                                                  }
                                                }
                                              } );

        })
        .catch((a_error)=>{
          a_request.sendError(a_error);
        })

        
      }
    }

    return NServer.NControllers.Render;
  }
});
