fcf.module({
  name: "fcfManagement:templates/pages/translations/files-tab.wrapper.js",
  dependencies: ["fcf:NClient/Wrapper.js", "fcf:NTools/languages.js"],
  module: function(Wrapper, toolsLanguages){

    
    fcf.addException("FCF_MANAGEMENT_INVALID_FORAMT_FILE", "Invalid file format");
    fcf.addException("FCF_MANAGEMENT_FAILD_READ_FILE", "Сouldn't read the file");
    fcf.addException("FCF_MANAGEMENT_FILE_UNSUPPORTED_LANGUAGE", "The file has an unsupported language installed");

    return class WrapperEx extends Wrapper{
      
      constructor(a_initializeOptions){
        super(a_initializeOptions);

        this._fileContainer = document.createElement("div");
        this._fileContainer.style.display = "none";
        document.body.appendChild(this._fileContainer);

        this._editable = {};
        this._fillEditable(this._editable);

        this._deleteFiles = {};

        this._skeepOnArg = false;
        this._skeepOnArgFiles = false;

      }

      attach() {
        this._fillEditable(this._editable);        
        return super.attach();
      }


      onArg(a_argName, a_value, a_editor, a_isInnerCall, a_suffix) {
        if (this._skeepOnArg)
          return;
        this.getChild("save").setArg("enable", true);
        this.getChild("cancel").setArg("enable", true);
        this.getChild("save").update();
        this.getChild("cancel").update();
      }

      onArgFiles(a_files, a_editor, a_isInnerCall, a_suffix){
        if (this._skeepOnArgFiles)
          return;
        let newEditable = {};
        this._fillEditable(newEditable);
        let editablePaths = {};
        let langs = fcf.append({}, newEditable, this._editable);
        for(let lang in langs){
          if (!newEditable[lang])
            newEditable[lang] = {};
          if (!this._editable[lang])
            this._editable[lang] = {};
          let count = fcf.count(newEditable[lang]);
          if (!count){
            newEditable[lang] = {};
            let path = fcf.firstKey(this._editable[lang]);
            if (path !== undefined)
              newEditable[lang][path] = true;
          } else if(count > 1){
            for(let path in this._editable[lang]){
              delete newEditable[lang][path];
              if (fcf.count(newEditable[lang]) == 1)
                break;
            }
          }
          let once = {};
          if (fcf.firstKey(newEditable[lang]) !== undefined){
            once[fcf.firstKey(newEditable[lang])] = true;
            editablePaths[fcf.firstKey(newEditable[lang])] = true;
          }
          newEditable[lang] = once;
        }

        this._editable = newEditable;
        for(let i = 0; i < a_files.length; ++i)
          a_files[i].editable = !!editablePaths[a_files[i].path];

        this._skeepOnArgFiles = true;
        this.setArg("files", a_files);
        this._skeepOnArgFiles = false;
      }

      onRemoveFile(a_path){
        let files = this.getArg("files");
        let newFiles = [];
        fcf.each(files, (k, file)=>{
          if (file.path != a_path) {
            newFiles.push(file);
          } else if (!file.newFile && !file.fileUUID){
            this._deleteFiles[file.path] = true;
          }
        })
        this._normalizeFiles(newFiles);
        this.setArg("files", newFiles);
      }

      onNew(a_button) {
        a_button.setArg("enable", false);
        fcf.application.render({
          template: "@controls:dialog",
          parent:    this,
          args: {
            fcfStyle: "max-width: 400px; width: 100%",
            title:    fcf.argVal("!{{New file}}!"),
            content:  fcf.argTmpl("@controls:form", {
                        fcfAlias: "form",
                        fields: [
                          { alias: "language", title: "!{{Language}}!",  type: "enum",   items: this.getArg("languages"), notEmpty: true },
                          { alias: "fileName", title: "!{{File name}}!", type: "string", notEmpty: true},
                        ]
                      }),
            buttons: fcf.argVal([
              fcf.argTmpl("@controls:button", {title: "!{{Ok}}!",     fcfEventClick: "parent.close('ok')"}),
              fcf.argTmpl("@controls:button", {title: "!{{Cancel}}!", fcfEventClick: "parent.close('cancel')"})
            ]),
            fcfEventClose: "parent.onNewCloseDialog(event)",
          }
        })
        .finally(()=>{
          a_button.setArg("enable", true);
        });
      }

      onNewCloseDialog(a_event){
        if (a_event.reason != "ok")
          return;
        let form   = a_event.wrapper.getChild("form");
        let errors = form.check();
        if (!fcf.empty(errors)){
          form.setArg("errors", errors);
          a_event.preventDefault();
          return;
        }

        let files = this.getArg("files");
        let fileNameCounter = 0;
        let fileName = ":translations/" + form.getArg("value").fileName;
        while(true){
          let exist = false;
          for(let i = 0; i  < files.length; ++i){
            if (files[i].path == fileName){
              exist = true;
              break;
            }
          }
          if (exist){
            ++fileNameCounter;
            fileName = ":translations/" + form.getArg("value").fileName + fileNameCounter;
          } else {
            break;
          }
        }

        files.push({
          editable: false,
          enable: true,
          language: form.getArg("value").language,
          path: fileName,
          system: false,
          newFile: true,
        })
        delete this._deleteFiles[fileName];
        this.setArg("files", files);
      }

      onAppend(a_button){
        fcf.application.render({
          template: "@controls:dialog",
          parent:   this,
          args: {
            fcfStyle: "max-width: 400px; width: 100%",
            title:  fcf.t("Append file"),
            content: fcf.argTmpl("@controls:form",{
              fcfAlias: "form",
              fields: [
                  { alias:    "button", 
                    type:     "text", 
                    template: "@controls:button", 
                    args: {
                      fcfClass:      "fcf-translations-files-tab-button-append-file", 
                      title:         fcf.t("File selection"),
                      fcfEventClick: "parent.getParent().getParent().onAppendDialogSelectButton(parent)"
                    }
                  },
                  { alias:    "name", 
                    title:    "!{{File name}}!",  
                    type:     "string",
                    notEmpty: true,
                  },
              ],
            }),
            buttons: fcf.argVal([
              fcf.argTmpl("@controls:button", { title: fcf.t("Ok"), fcfEventClick: "parent.close('ok')"}),
              fcf.argTmpl("@controls:button", { title: fcf.t("Cancel"), fcfEventClick: "parent.close('cancel')"}),
            ]),
            fcfEventClose: "parent.onAppendDialogClose(event)"
          },
        })
      }

      onAppendDialogSelectButton(a_form){
        a_form.getChild("button").setArg("enable", false);

        let self = this;
        let fileInput = document.createElement("input");
        let fileUUID   = fcf.uuid();
        fileInput.setAttribute("id", fileUUID);
        fileInput.setAttribute("type", "file");
        fileInput.setAttribute("name", "file");
        fileInput.setAttribute("display", "none");
        this._fileContainer.appendChild(fileInput);

        let skeep = false;
        window.addEventListener("focus", (a_event)=>{
          if (skeep)
            return;
          a_form.getChild("button").setArg("enable", true);
        }, {once: true});
        fileInput.addEventListener("change", (a_event)=>{
          skeep = true;
          let formValue = a_form.getArg("value");
          if (!formValue)
            formValue = {};
          formValue.fileUUID = fileUUID;
          formValue.name = fcf.getFileName(fileInput.value);
          a_form.setArg("value", formValue);
          a_form.getChild("button").setArg("enable", true);
        });

        fileInput.click();
      }

      onAppendDialogClose(a_event){
        let self = this;

        if (a_event.reason != "ok")
          return;

        let form      = a_event.wrapper.getChild("form");
        let formValue = form.getArg("value");
        let errors    = form.check();
        if (!formValue.fileUUID)
          errors.push({alias: "button", error: new fcf.Exception("ERROR_FIELD_VALIDATION_NOT_EMPTY")});
        if (!fcf.empty(errors)) {
          form.setArg("errors", errors);
          a_event.preventDefault();
          return;
        }

        return fcf.actions()
        .then((a_res, a_act)=>{
          let fileObject;
          let fileReader = new FileReader();
          fileReader.onload = ()=>{
            try{
              fileObject = JSON.parse(fileReader.result);
              if (typeof fileObject !== "object" || 
                  typeof fileObject.language !== "string" || 
                  typeof fileObject.translations !== "object")
                throw new Error("");
            } catch(e){
              fcf.application.getEventChannel().send("error", {error: new fcf.Exception("FCF_MANAGEMENT_INVALID_FORAMT_FILE")});
              a_event.preventDefault();
              a_act.complete();
              return;
            }

            if (!(fileObject.language in toolsLanguages.getLanguages())){
              fcf.application.getEventChannel().send("error", {error: new fcf.Exception("FCF_MANAGEMENT_FILE_UNSUPPORTED_LANGUAGE")});
              a_event.preventDefault();
              a_act.complete();
              return;
            }

            let files = self.getArg("files");
            let fileNameCounter = 0;
            let fileName = ":translations/" + formValue.name;
            while(true){
              let exist = false;
              for(let i = 0; i  < files.length; ++i){
                if (files[i].path == fileName){
                  exist = true;
                  break;
                }
              }
              if (exist){
                ++fileNameCounter;
                fileName = ":translations/" + formValue.name + fileNameCounter;
              } else {
                break;
              }
            }

            files.push({
              editable: false,
              enable:   true,
              language: fileObject.language,
              path:     fileName,
              system:   false,
              fileUUID: formValue.fileUUID,
            });
            delete self._deleteFiles[":translations/" + formValue.name];
            self.setArg("files", files);
            
            a_act.complete();
          }
          fileReader.onerror = ()=>{
            fcf.application.getEventChannel().send("error", {error: new fcf.Exception("FCF_MANAGEMENT_FAILD_READ_FILE")});
            a_act.complete();
          }
          fileReader.readAsText(fcf.select("[id='" + formValue.fileUUID+"']")[0].files[0]);
        })
      }

      onSave(){
        let self = this;
        this.getChild("save").setArg("enable", false);
        this.getChild("cancel").setArg("enable", false);

        let files = this.getArg("files");
        let sendFilesInfo = {
          files: [],
          newFiles:    {},
          appendFiles: {},
          deleteFiles: {},
        };
        let sendFiles = [];

        fcf.each(files, (a_k, a_fileInfo) => {
          sendFilesInfo.files.push(a_fileInfo);
          if (a_fileInfo.newFile) {
            sendFilesInfo.newFiles[a_fileInfo.path] = true;
          } else if (a_fileInfo.fileUUID) {
            sendFiles.push(fcf.select("[id='"+a_fileInfo.fileUUID+"']")[0].files[0]);
            sendFilesInfo.appendFiles[a_fileInfo.path] = sendFiles.length - 1;
          }
        });
        sendFilesInfo.deleteFiles = this._deleteFiles;

        this.send(sendFilesInfo, sendFiles)
        .then(()=>{
          self._editable = {};
          self._deleteFiles = {};
          fcf.each(files, (a_k, a_fileInfo) => {
            delete a_fileInfo.newFile;
            delete a_fileInfo.fileUUID;
          });
          self._skeepOnArg = true;
          self.setArg("files", files);
          self._skeepOnArg = false;
        })
        .catch((a_error)=>{
          self.getChild("save").setArg("enable", true);
          self.getChild("cancel").setArg("enable", true);
          fcf.application.getEventChannel().send("error", {error: a_error});
        })


      }

      onCancel(){
        let self = this;
        this._editable = {};
        this._deleteFiles = {};
        this.reload();
      }

      _normalizeFiles(a_files){
        let languages = fcf.getSystemVariable("fcf:languages");
        for(let language in languages){
          let exists = false;
          for(let i = 0; i < a_files.length; ++i){
            let fileInfo = a_files[i];
            if (fileInfo.language != language)
              continue;
            if (!exists){
              if (fileInfo.editable)
                exists = true;
            } else {
              fileInfo.editable = false;
            }
          }

          if (exists)
            continue;

          for(let i = 0; i < a_files.length; ++i){
            let fileInfo = a_files[i];
            if (fileInfo.language != language)
              continue;
            if (fileInfo.system)
              continue;
            fileInfo.editable = true;
            exists = true;
            break;
          }

          if (exists)
            continue;

          for(let i = 0; i < a_files.length; ++i){
            let fileInfo = a_files[i];
            if (fileInfo.language != language)
              continue;
            fileInfo.editable = true;
            exists = true;
            break;
          }
        }
      }

      _fillEditable(a_dst) {
        let langs = toolsLanguages.getLanguages();
        let files = this.getArg("files");
        for(let i = 0; i < files.length; ++i) {
          if (files[i].editable){
            if (!a_dst[files[i].language])
              a_dst[files[i].language] = {};
            a_dst[files[i].language][files[i].path] = true;
          }
        }
      }

    };
  }
});
