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

fcf.module({
  name: "fcf:NServer/NControllers/File.js",
  dependencies: [
                  "fcf:NServer/NServer.js", 
                  "fcf:NServer/NControllers/Controller.js", 
                  "fcf:NTools/babel.js", 
                  "fcf:NTools/fileBuilder.js",
                  "fcf:NServer/NControllers/NDetails/wrapperBuilder.js"
                  ],
  module: function(NServer, Controller, babel, fileBuilder, wrapperBuilder) {
    fcf.prepareObject(fcf, "NServer.NControllers");

    let stSuperWrappers = {};

    NServer.NControllers.File = class File extends Controller {

      constructor(a_options) {
        super(a_options);
        this.memoryLeakProtection = false;
        this.maxResponseTimeout   = 12*60*60;
      }

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

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

      _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 isWrapper = a_path.substr(a_path.length - "wrapper.js".length) == "wrapper.js";
          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";
          var template     = a_path.substr(0, a_path.length - ".wrapper.js".length).split("+")[0] + ".tmpl";
          var subpart      = a_path.substr(0, a_path.length - ".wrapper.js".length).split("+")[1];

          try {
            if (isWrapper){
              let filePath = await wrapperBuilder.getFile(a_uri);
              a_request.sendFile(filePath);
            } else if (isReceive || isHooks) {
              a_request.sendErrorPage(new fcf.Exception("ERROR_404", {address: a_path}));
            } else {
              if (!a_error){
                self.sendSimpleJSFile(a_request, a_path, a_uri);
              } else {
                var content = 'fcf.module({"name": "' + a_uri + '", "module":function(){} });';
                a_request.send(content);
              }
            }
          } catch (e) {
            a_request.sendErrorPage(new fcf.Exception("ERROR", {error: e}));
          }
        });
      }

      sendSimpleJSFile(a_request, a_path, a_uri){
        let self = this;
        fcf.actions()
        .then(()=>{
          if (fileBuilder.isBuildExists(a_uri))
            return;
          return fileBuilder.build(a_uri);
        })
        .then(()=>{
          let needBabel = fcf.getContext().get("needBabel");
          let debug     = fcf.getContext().get("debug");
          let file      = !needBabel && debug ? a_path :
                          !needBabel          ? fileBuilder.getGroupFilePath(a_uri) :
                                                fileBuilder.getGroupFilePathES5(a_uri);
          a_request.sendFile(file);
        });
      }

      _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 NServer.NControllers.File;
  }
});
