let libFS = require("fs");
let libUtil = require("util");
let libMime = require("mime-types");

fcf.module({
  name: "fcf:NServer/NControllers/File.js",
  dependencies: ["fcf:NServer/NControllers/Controller.js",
                 "fcf:NSystem/babel.js",
                 "fcf:NSystem/builder.js"
                ],
  module: function(Controller, babel, builder) {
    fcf.prepareObject(fcf, "NServer.NControllers");

    let stSuperWrappers = {};

    fcf.NServer.NControllers.File = class File extends Controller {

      constructor(a_options) {
        super(a_options);
        this.memoryLeakProtection = false;
        this.maxResponseTimeout   = fcf.application.getConfiguration().maxFileSendTime;
      }

      action(a_request) {
        var subUri  = a_request.getRoute().subUri;
        var uri     = fcf.NPath.concat(this._options.source, subUri);
            uri     = uri.indexOf("/") == 0 ? fcf.settings.innerRoot + "/" + fcf.ltrim(uri, "/") : uri;
            uri     = decodeURIComponent(uri);
            uri     = fcf.trim(fcf.replaceAll(uri.replace(":/", ":")));
            uri     = fcf.replaceAll(uri, "..", "");
        var path    = fcf.getPath(uri);
        var ext     = fcf.getExtension(path).toLowerCase();
        var theme   = fcf.application.getTheme();

        if (ext == "js")
          this._processJSFile(a_request, path, uri, theme);
        else
          this._processSimpleFile(a_request, path, uri, theme);
      }

      async _processJSFile(a_request, a_path, a_uri, a_theme){
        let self = this;
        let context = fcf.getContext();
        libFS.lstat(a_path, async function(a_error, a_stat) {
          fcf.setContext(context);
          a_request.setHeader("Content-Type", "application/javascript");
          if (!a_error && !a_stat.isFile()){
            a_request.sendErrorPage(new fcf.Exception("ERROR_READ_NOT_FILE", [a_uri]));
            return;
          }

          var isReceive = a_path.substr(a_path.length - ".receive.js".length) == ".receive.js";
          var isHooks = a_path.substr(a_path.length - ".hooks.js".length) == ".hooks.js";

          try {
            if (isReceive || isHooks) {
              a_request.sendErrorPage(new fcf.Exception("ERROR_404", {address: a_path}));
              return;
            }

            let info = await builder.get("js", a_uri);
            if (!info) {
              a_request.sendErrorPage(new fcf.Exception("ERROR_404", {address: a_path}));
              return
            }
            let filePath = fcf.getContext().needBabel ? info.es5 :
                           fcf.getContext().debug     ? info.basic :
                                                        info.compress;
            a_request.sendFile(filePath);
          } catch (e) {
            a_request.sendErrorPage(new fcf.Exception("ERROR", {error: e}));
          }
        });
      }

      _processSimpleFile(a_request, a_path, a_uri, a_theme){
        let self = this;
        let context = fcf.getContext();
        libFS.lstat(a_path, function(a_error, a_stat) {
          fcf.setContext(context);

          if (a_error){
            a_request.sendErrorPage(new fcf.Exception("ERROR_READ_FILE", [a_uri, a_error]));
            return;
          }

          if (!a_stat.isFile()){
            a_request.sendErrorPage(new fcf.Exception("ERROR_READ_NOT_FILE", [a_uri]));
            return;
          }

          let mimeType = libMime.lookup(a_uri);
          if (!mimeType)
            mimeType = libMime.lookup(a_path);
          if (!mimeType)
            mimeType = "text/plain"
          a_request.setHeader("Content-Type", mimeType);
          a_request.sendFile(a_path);
        });
      }


    }

    return fcf.NServer.NControllers.File;
  }
});
