let libFS   = require("fs");
let libUtil = require("util");

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

    class WrapperBuilder {
      constructor(){
      }

      async getFile(a_uri){
        let suffix = a_uri.substr(a_uri.length - ".wrapper.js".length);
        if (suffix != ".wrapper.js")
          return;

        let filePath = "cache/wrappers/" + encodeURIComponent(a_uri);

        let templatePath = a_uri.substr(0, a_uri.length - ".wrapper.js".length).split("+")[0] + ".tmpl";
        let block        = a_uri.substr(0, a_uri.length - ".wrapper.js".length).split("+")[1];
        let templateBlockPath = templatePath + (block ? "+"+block : "");

        let fullPath = block ? templatePath + "+" + block
                             : templatePath;
        let loader       = fcf.application.getRender().getLoader();
        let template     = await loader.loadInfo(fullPath, {theme: fcf.application.getThemes().getTheme()}, "");

        let wrapperPath = templatePath.substr(0, templatePath.length-".tmpl".length);
          if (block)
            wrapperPath += "+" + block;
        wrapperPath += ".wrapper.js";
        wrapperPath = fcf.getPath(wrapperPath);

        let templateTime = template.lastModifyTime;
        let wrapperTime  = undefined;
        try {
          let stat = await libUtil.promisify(libFS.stat)(wrapperPath);
          wrapperTime  = stat.mtime;
          templateTime = fcf.max(templateTime, stat.mtime);
        } catch(e) {
        }

        try {
          let stat = await libUtil.promisify(libFS.stat)(filePath);
          if (stat.mtime > templateTime)
            return filePath;

          if (!wrapperTime) {
            let isNotExist = await libUtil.promisify(libFS.exists)(filePath + "-empty");
            if (isNotExist) {
              return filePath;
            }
          }
        } catch(e) {
        }

        let superWrapper;
        let superTemplate = template.options.extends;
        if (typeof superTemplate === "string" && superTemplate[0] == "@") {
          let alias = superTemplate.substr(1);
          alias = fcf.application.getConfiguration().aliases[alias];
          if (alias)
            superTemplate = alias;
        }
        if (superTemplate){
          let path = superTemplate.substr(0, superTemplate.length-".tmpl".length);
          if (block)
            path += "+" + block;
          superWrapper = path;
          superWrapper += ".wrapper.js";
        } else {
          superWrapper = "fcf:NClient/Wrapper.js";
        }

        let templateCode   = !block ? (template.templates[""] ? template.templates[""].template.template : "") : 
                                      (template.templates[block] ? template.templates[block].template.template : "");
        let renderFunction = "function(render, args, decor, route) {" + templateCode + "}";


        let wrapperCode  = false;
        let wrapperExist = false;
        try {
          wrapperCode = await libUtil.promisify(libFS.readFile)(wrapperPath, {encoding: 'utf-8'});
          wrapperExist = true;
        } catch(e){
          wrapperCode = '';
          wrapperCode += 'fcf.module({\n';
          wrapperCode += '  name: "' + a_uri + '",\n';
          wrapperCode += '  dependencies: ["' + superWrapper + '"],\n';
          wrapperCode += '  module: function(Wrapper){\n';
          wrapperCode += '    return class WrapperEx extends Wrapper {\n';
          wrapperCode += '      constructor(a_initializeOptions){\n';
          wrapperCode += '        super(a_initializeOptions);\n';
          wrapperCode += '      }\n';
          wrapperCode += '    }\n';
          wrapperCode += '  }\n';
          wrapperCode += '});\n';
        }

        let fileCode = "";
        fileCode += wrapperCode;
        fileCode += "\n";
        fileCode += "if (!fcf) fcf = {};\n";
        fileCode += "if (!fcf.NDetails) fcf.NDetails = {};\n";
        fileCode += "if (!fcf.NDetails.renderInstructions) fcf.NDetails.renderInstructions = {};\n";
        if (template.options.clientRendering){
          let code = JSON.stringify(renderFunction);
          code = code.substr(1, code.length-2);
          fileCode += "fcf.NDetails.renderInstructions[\"" + templateBlockPath + "\"]={renderFunction: eval(\"(" + code + ")\")};\n";
        }

        await libUtil.promisify(libFS.writeFile)(filePath, fileCode);
        if (!wrapperExist){
          await libUtil.promisify(libFS.writeFile)(filePath + "-empty", "");
        } else {
          try {
            await libUtil.promisify(libFS.unlink)(filePath + "-empty");
          } catch(e){ }
        }

        return filePath;
      }
    };

    Namespace.wrapperBuilder = new WrapperBuilder();

    return Namespace.wrapperBuilder;
  }
});
