var libFS       = require("fs");
var libPath     = require("path");

fcf.module({
  name: "fcf:NTools/fileBuilder.js",
  dependencies: ["fcf:NTools/babel.js", "fcf:NTools/fs.js"],
  module: function(babel, fs){
    var Namespace = fcf.prepareObject(fcf, "packages/fcf/NTools");

    function minify(a_content){
      let result = "";
      // state:
      //       0 - code
      //       1 - quotes
      //       2 - double quotes
      //       3 - //
      //       4 - /*
      let state = 0;
      let spaceCounter = 0;
      let slashCounter = 0;
      for(let i = 0; i < a_content.length; ++i) {
        let c = a_content.charCodeAt(i);
        if (state == 0){
          if (c <= 32){
            if (spaceCounter == 0)
              result += a_content[i];  
            else if (a_content[i] == "\n")
              result += a_content[i];
            ++spaceCounter;
          } else {
            spaceCounter = 0;
            if (a_content[i]=="/" && a_content[i+1]=="/"){
              state = 3
            } else if (a_content[i]=="/" && a_content[i+1]=="*"){
              state = 4
            } else {
              result += a_content[i];
            }
          }
          if (a_content[i] == "\"")
            state = 1;
          else if (a_content[i] == "'")
            state = 2;
        } else if (state == 1) {
          result += a_content[i];
          if (slashCounter%2 == 0 && a_content[i] == "\"")
            state = 0;
          if (a_content[i] == "\\")
            ++slashCounter;
          else
            slashCounter = 0;
        } else if (state == 2) {
          result += a_content[i];
          if (slashCounter%2 == 0 && a_content[i] == "'")
            state = 0;
          if (a_content[i] == "\\")
            ++slashCounter;
          else
            slashCounter = 0;
        } else if (state == 3) {
          if (a_content[i] == "\n")
            state = 0;
        } else if (state == 4) {
          if (a_content[i] == "*" && a_content[i+1] == "/"){
            ++i;
            state = 0;
          }
        }
      }
      return result;
    }

    class FileBuilder {
      constructor(){
        this._groups = {};
      }

      build(a_groupName, a_files) {
        if (!this._groups[a_groupName]){
          if (!a_files)
            a_files = [fcf.getPath(a_groupName)];

          this._groups[a_groupName] = {
            files:    a_files,
            actions:  undefined,
            initialization: true,
          };
          this._watch(a_groupName);
        }

        if (this._groups[a_groupName].actions){
          return this._groups[a_groupName].actions;
        }

        if (this._groups[a_groupName].initialization){
          if (this._checkNeedUpdate(a_groupName)){
            return this._update(a_groupName);
          }
        }

        return fcf.actions();
      }

      isBuildExists(a_groupName){
        return this._groups[a_groupName] && !this._groups[a_groupName].initialization;
      }


      getGroupFilePath(a_groupName) {
        let groupNameArr = a_groupName.split(":");
        if (groupNameArr[0] == "")
          groupNameArr[0] = "_"
        return (groupNameArr.length == 1)
                ? fcf.getPath(libPath.join(fcf.application.getConfiguration().cacheDirectory, "fileBuilder", groupNameArr[0])) :
               groupNameArr.length == 2
                ? fcf.getPath(libPath.join(fcf.application.getConfiguration().cacheDirectory, "fileBuilder", groupNameArr[0] , groupNameArr[1])) :
                  undefined;
      }

      getGroupFilePathES5(a_groupName) {
        let groupNameArr = a_groupName.split(":");
        if (groupNameArr[0] == "")
          groupNameArr[0] = "_"
        return (groupNameArr.length == 1)
                ? fcf.getPath(libPath.join(fcf.application.getConfiguration().cacheDirectory, "fileBuilderES5", groupNameArr[0])) :
               groupNameArr.length == 2
                ? fcf.getPath(libPath.join(fcf.application.getConfiguration().cacheDirectory, "fileBuilderES5", groupNameArr[0] , groupNameArr[1])) :
                  undefined;
      }

      _checkNeedUpdate(a_groupName){
        try {
          let filePath          = this.getGroupFilePath(a_groupName);
          let fileRealPath      = fcf.getPath(filePath);
          let filePathES5       = this.getGroupFilePath(a_groupName);
          let fileRealPathES5   = fcf.getPath(filePathES5);
          let groupLastTime     = libFS.statSync(fileRealPath).mtime;
          let groupLastTimeES5  = libFS.statSync(fileRealPathES5).mtime;
          let files             = this._groups[a_groupName].files;
            
          for(let i = 0; i < files.length; ++i){
            let file = files[i];
            let ft = libFS.statSync(fcf.getPath(file)).mtime;
            if (ft >= groupLastTime)
              return true;
            if (ft >= groupLastTimeES5)
              return true;
          }
        } catch(e){
          return true;
        }
        return false;
      }

      _watch(a_groupName){
        let self = this;
        let files = this._groups[a_groupName].files;
        fcf.each(files, (a_key, a_file)=>{
          libFS.watchFile(fcf.getPath(a_file), {interval: 1000}, (a_eventType, a_filename)=>{
            if (!a_eventType.mode)
              return;
            self._update(a_groupName);
          })
        })
      }

      _update(a_groupName){
        fcf.log.log("FCF", "Build files [", a_groupName,"]");
        let self = this;
        let content    = "";
        let contentES5 = "";
        let files      = this._groups[a_groupName].files;

        if (!self._groups[a_groupName].actions)
          self._groups[a_groupName].actions = fcf.actions();

        return self._groups[a_groupName].actions
        .each(files, (a_key, a_file, a_res, a_act) => {
          libFS.readFile(fcf.getPath(a_file), 'utf8', function(a_error, a_content) {
            if (a_error) {
              a_act.error(a_error);
              return;
            }
            content += a_content;
            a_act.complete();
          });
        })
        .then(()=>{
          return babel.transform(content)
          .then((a_content)=>{
            contentES5 = a_content;
          })
        })
        .then(()=>{
          content = minify(content);
        })
        .then(()=>{
          let filePath = fcf.getPath(self.getGroupFilePath(a_groupName));
          fs.prepareDirectorySync(libPath.dirname(filePath))
          libFS.writeFileSync(filePath+"___", content);
          libFS.rename(filePath+"___", filePath, ()=>{});
        })
        .then(()=>{
          let filePath = fcf.getPath(self.getGroupFilePathES5(a_groupName));
          fs.prepareDirectorySync(libPath.dirname(filePath))
          libFS.writeFileSync(filePath+"___", contentES5);
          libFS.rename(filePath+"___", filePath, ()=>{});

          self._groups[a_groupName].initialization = false;
          self._groups[a_groupName].actions = undefined;
        })
        .catch((a_error)=>{
          self._groups[a_groupName].actions = undefined;
          fcf.log.err("FCF:BUILDER", a_error);
        })

      }
    };

    Namespace.fileBuilder = new FileBuilder();

    return Namespace.fileBuilder;
  }
});
