fcf.module({
  name: "fcf:NServer/NControllers/Route.js",
  dependencies: ["fcf:NServer/NControllers/Controller.js"],
  module: function(Controller){
    var Namespace = fcf.prepareObject(fcf, "packages/fcf/NServer/NControllers");

    class Route  extends Controller{
      constructor(a_options){
        super(a_options);
        this.userImportance = true;
      }

      async action(a_request) {
        if (!a_request.getRouteData().args.url){
          a_request.sendError(new fcf.Exception("ERROR_HTTP_ARG_NOT_SET", {"arg": "url"}));
          return;
        }

        let routeInfo = new fcf.RouteInfo({url: a_request.getRouteData().args.url});
        let node = await fcf.application.getRouter().getNode(a_request.getRouteData().args.url)
        fcf.append(routeInfo.args, node.args);
        routeInfo.subUri = node.subUri;

        if (!node)
          throw new fcf.Exception("ERROR_404", {"address": routeInfo.url});

        do {
          if (!node.node || !node.node.endpoint || !node.node.endpoint.controller)
            break;
          let [Class] = await fcf.require([node.node.endpoint.controller]);
          if (!Class)
            break;
          let controller = new Class(node.node.endpoint);
          if (!controller.redirect)
            break;

          try {
            let originRouteData = a_request._routeData;
            a_request.enableRedirect = false;
            a_request._routeData = routeInfo;
            await fcf.actions()
            .then(async (a_res, a_act)=>{
              controller.action(a_request);
              a_request.setPreNext(()=>{
                a_act.complete();
              })
            });
            a_request.enableRedirect = true;
            a_request._routeData = originRouteData;
            let newNode = await fcf.application.getRouter().getNode(a_request.getRedirect())
            if (!newNode)
              break;
            node = newNode;
            routeInfo = new fcf.RouteInfo({url: a_request.getRedirect()});
          } catch(e){
            a_request.enableRedirect = true;
            a_request._routeData = originRouteData;
            break;
          }
        } while(false);

        fcf.append(routeInfo.args, node.args);
        routeInfo.subUri = node.subUri;
        routeInfo.title  = node.node.title;
        routeInfo.description  = node.node.endpoint && node.node.endpoint.description ? node.node.endpoint.description : "";
        a_request.send({route: routeInfo});

      }
    };

    Namespace.Route = Route;

    return Namespace.Route;
  }
});
