text: import kdbxweb from 'kdbxweb';
  import { View } from 'framework/views/view';
  import { Storage } from 'storage';
  import { Shortcuts } from 'comp/app/shortcuts';
  import { Launcher } from 'comp/launcher';
  import { Alerts } from 'comp/ui/alerts';
  import { Links } from 'const/links';
  import { AppSettingsModel } from 'models/app-settings-model';
  import { DateFormat } from 'util/formatting/date-format';
  import { UrlFormat } from 'util/formatting/url-format';
  import { PasswordPresenter } from 'util/formatting/password-presenter';
  import { Locale } from 'util/locale';
  import { FileSaver } from 'util/ui/file-saver';
  import { OpenConfigView } from 'views/open-config-view';
  import { escape, omit } from 'util/fn';
  import template from 'templates/settings/settings-file.hbs';
  
  const DefaultBackupPath = 'Backups/{name}.{date}.bak';
  const DefaultBackupSchedule = '1w';
  
  class SettingsFileView extends View {
      template = template;
  
      events = {
          'click .settings__file-button-save-default': 'saveDefault',
          'click .settings__file-button-save-choose': 'toggleChooser',
          'click .settings__file-button-close': 'closeFile',
          'click .settings__file-save-to-file': 'saveToFile',
          'click .settings__file-save-to-xml': 'saveToXml',
          'click .settings__file-save-to-html': 'saveToHtml',
          'click .settings__file-save-to-storage': 'saveToStorage',
          'change #settings__file-key-file': 'keyFileChange',
          'click #settings__file-file-select-link': 'triggerSelectFile',
          'change #settings__file-file-select': 'fileSelected',
          'focus #settings__file-master-pass': 'focusMasterPass',
          'input #settings__file-master-pass': 'changeMasterPass',
          'blur #settings__file-master-pass': 'blurMasterPass',
          'focus #settings__file-confirm-master-pass': 'focusConfirmMasterPass',
          'blur #settings__file-confirm-master-pass': 'blurConfirmMasterPass',
          'input #settings__file-name': 'changeName',
          'input #settings__file-def-user': 'changeDefUser',
          'change #settings__file-backup-enabled': 'changeBackupEnabled',
          'input #settings__file-backup-path': 'changeBackupPath',
          'change #settings__file-backup-storage': 'changeBackupStorage',
          'change #settings__file-backup-schedule': 'changeBackupSchedule',
          'click .settings__file-button-backup': 'backupFile',
          'change #settings__file-trash': 'changeTrash',
          'input #settings__file-hist-len': 'changeHistoryLength',
          'input #settings__file-hist-size': 'changeHistorySize',
          'change #settings__file-format-version': 'changeFormatVersion',
          'change #settings__file-kdf': 'changeKdf',
          'input #settings__file-key-rounds': 'changeKeyRounds',
          'input #settings__file-key-change-force': 'changeKeyChangeForce',
          'input .settings__input-kdf': 'changeKdfParameter'
      };
  
      constructor(model, options) {
          super(model, options);
          const watchedProps = ['syncing', 'syncError', 'syncDate'];
          for (const prop of watchedProps) {
              this.listenTo(this.model, 'change:' + prop, () => {
                  setTimeout(() => this.render(), 0);
              });
          }
      }
  
      render() {
          const storageProviders = [];
          const fileStorage = this.model.storage;
          let canBackup = false;
          Object.keys(Storage).forEach(name => {
              const prv = Storage[name];
              if (!canBackup && prv.backup && prv.enabled) {
                  canBackup = true;
              }
              if (!prv.system && prv.enabled) {
                  storageProviders.push({
                      name: prv.name,
                      icon: prv.icon,
                      iconSvg: prv.iconSvg,
                      own: name === fileStorage,
                      backup: prv.backup
                  });
              }
          });
          storageProviders.sort((x, y) => (x.uipos || Infinity) - (y.uipos || Infinity));
          const backup = this.model.backup;
          super.render({
              cmd: Shortcuts.actionShortcutSymbol(true),
              supportFiles: !!Launcher,
              desktopLink: Links.Desktop,
              name: this.model.name,
              path: this.model.path,
              storage: this.model.storage,
              syncing: this.model.syncing,
              syncError: this.model.syncError,
              syncDate: DateFormat.dtStr(this.model.syncDate),
              password: PasswordPresenter.present(this.model.passwordLength),
              defaultUser: this.model.defaultUser,
              recycleBinEnabled: this.model.recycleBinEnabled,
              backupEnabled: backup && backup.enabled,
              backupStorage: backup && backup.storage,
              backupPath:
                  (backup && backup.path) || DefaultBackupPath.replace('{name}', this.model.name),
              backupSchedule: backup ? backup.schedule : DefaultBackupSchedule,
              historyMaxItems: this.model.historyMaxItems,
              historyMaxSize: Math.round(this.model.historyMaxSize / 1024 / 1024),
              formatVersion: this.model.formatVersion,
              kdfName: this.model.kdfName,
              keyEncryptionRounds: this.model.keyEncryptionRounds,
              keyChangeForce: this.model.keyChangeForce > 0 ? this.model.keyChangeForce : null,
              kdfParameters: this.kdfParametersToUi(this.model.kdfParameters),
              storageProviders,
              canBackup,
              canExportXml: AppSettingsModel.canExportXml,
              canExportHtml: AppSettingsModel.canExportHtml
          });
          if (!this.model.created) {
              this.$el.find('.settings__file-master-pass-warning').toggle(this.model.passwordChanged);
              this.$el
                  .find('#settings__file-master-pass-warning-text')
                  .text(Locale.setFilePassChanged);
          }
          this.renderKeyFileSelect();
      }
  
      kdfParametersToUi(kdfParameters) {
          return kdfParameters
              ? { ...kdfParameters, memory: Math.round(kdfParameters.memory / 1024) }
              : null;
      }
  
      renderKeyFileSelect() {
          const keyFileName = this.model.keyFileName;
          const oldKeyFileName = this.model.oldKeyFileName;
          const keyFileChanged = this.model.keyFileChanged;
          const sel = this.$el.find('#settings__file-key-file');
          sel.html('');
          if (keyFileName && keyFileChanged) {
              const text =
                  keyFileName !== 'Generated'
                      ? Locale.setFileUseKeyFile + ' ' + keyFileName
                      : Locale.setFileUseGenKeyFile;
              $('<option/>')
                  .val('ex')
                  .text(text)
                  .appendTo(sel);
          }
          if (oldKeyFileName) {
              const useText = keyFileChanged
                  ? Locale.setFileUseOldKeyFile
                  : Locale.setFileUseKeyFile + ' ' + oldKeyFileName;
              $('<option/>')
                  .val('old')
                  .text(useText)
                  .appendTo(sel);
          }
          $('<option/>')
              .val('gen')
              .text(Locale.setFileGenKeyFile)
              .appendTo(sel);
          $('<option/>')
              .val('none')
              .text(Locale.setFileDontUseKeyFile)
              .appendTo(sel);
          if (keyFileName && keyFileChanged) {
              sel.val('ex');
          } else if (!keyFileName) {
              sel.val('none');
          } else if (oldKeyFileName && keyFileName === oldKeyFileName && !keyFileChanged) {
              sel.val('old');
          }
      }
  
      validatePassword(continueCallback) {
          if (!this.model.passwordLength) {
              Alerts.yesno({
                  header: Locale.setFileEmptyPass,
                  body: Locale.setFileEmptyPassBody,
                  success: () => {
                      continueCallback();
                  },
                  cancel: () => {
                      this.$el.find('#settings__file-master-pass').focus();
                  }
              });
              return false;
          }
          return true;
      }
  
      save(arg) {
          if (!arg) {
              arg = {};
          }
          arg.startedByUser = true;
          if (!arg.skipValidation) {
              const isValid = this.validatePassword(() => {
                  arg.skipValidation = true;
                  this.save(arg);
              });
              if (!isValid) {
                  return;
              }
          }
  
          this.appModel.syncFile(this.model, arg);
      }
  
      saveDefault() {
          this.save();
      }
  
      toggleChooser() {
          this.$el.find('.settings__file-save-choose').toggleClass('hide');
      }
  
      saveToFile(skipValidation) {
          if (skipValidation !== true && !this.validatePassword(this.saveToFile.bind(this, true))) {
              return;
          }
          const fileName = this.model.name + '.kdbx';
          if (Launcher && !this.model.storage) {
              Launcher.getSaveFileName(fileName, path => {
                  if (path) {
                      this.save({ storage: 'file', path });
                  }
              });
          } else {
              this.model.getData(data => {
                  if (!data) {
                      return;
                  }
                  if (Launcher) {
                      Launcher.getSaveFileName(fileName, path => {
                          if (path) {
                              Storage.file.save(path, null, data, err => {
                                  if (err) {
                                      Alerts.error({
                                          header: Locale.setFileSaveError,
                                          body:
                                              Locale.setFileSaveErrorBody + ' ' + path + ': \n' + err
                                      });
                                  }
                              });
                          }
                      });
                  } else {
                      const blob = new Blob([data], { type: 'application/octet-stream' });
                      FileSaver.saveAs(blob, fileName);
                  }
              });
          }
      }
  
      saveToXml() {
          this.model.getXml(xml => {
              const blob = new Blob([xml], { type: 'text/xml' });
              FileSaver.saveAs(blob, this.model.name + '.xml');
          });
      }
  
      saveToHtml() {
          this.model.getHtml(html => {
              const blob = new Blob([html], { type: 'text/html' });
              FileSaver.saveAs(blob, this.model.name + '.html');
          });
      }
  
      saveToStorage(e) {
          if (this.model.syncing || this.model.demo) {
              return;
          }
          const storageName = $(e.target)
              .closest('.settings__file-save-to-storage')
              .data('storage');
          const storage = Storage[storageName];
          if (!storage) {
              return;
          }
          if (this.model.storage === storageName) {
              this.save();
          } else {
              if (!storage.list) {
                  if (storage.getOpenConfig) {
                      const config = {
                          id: storage.name,
                          name: Locale[storage.name] || storage.name,
                          icon: storage.icon,
                          buttons: false,
                          ...storage.getOpenConfig()
                      };
                      const openConfigView = new OpenConfigView(config);
                      Alerts.alert({
                          header: '',
                          body: '',
                          icon: storage.icon || 'files-o',
                          buttons: [Alerts.buttons.ok, Alerts.buttons.cancel],
                          esc: '',
                          opaque: true,
                          view: openConfigView,
                          success: () => {
                              const storageConfig = openConfigView.getData();
                              if (!storageConfig) {
                                  return;
                              }
                              const opts = omit(storageConfig, ['path', 'storage']);
                              if (opts && Object.keys(opts).length) {
                                  this.model.opts = opts;
                              }
                              this.save({ storage: storageName, path: storageConfig.path, opts });
                          }
                      });
                  } else {
                      Alerts.notImplemented();
                  }
                  return;
              }
              this.model.syncing = true;
              storage.list('', (err, files) => {
                  this.model.syncing = false;
                  if (err) {
                      return;
                  }
                  const expName = this.model.name.toLowerCase();
                  const existingFile = [...files].find(
                      file =>
                          !file.dir && UrlFormat.getDataFileName(file.name).toLowerCase() === expName
                  );
                  if (existingFile) {
                      Alerts.yesno({
                          header: Locale.setFileAlreadyExists,
                          body: Locale.setFileAlreadyExistsBody.replace(
                              '{}',
                              this.model.escape('name')
                          ),
                          success: () => {
                              this.model.syncing = true;
                              storage.remove(existingFile.path, err => {
                                  this.model.syncing = false;
                                  if (!err) {
                                      this.save({ storage: storageName });
                                  }
                              });
                          }
                      });
                  } else {
                      this.save({ storage: storageName });
                  }
              });
          }
      }
  
      closeFile() {
          if (this.model.modified) {
              Alerts.yesno({
                  header: Locale.setFileUnsaved,
                  body: Locale.setFileUnsavedBody,
                  buttons: [
                      { result: 'close', title: Locale.setFileCloseNoSave, error: true },
                      { result: '', title: Locale.setFileDontClose }
                  ],
                  success: result => {
                      if (result === 'close') {
                          this.closeFileNoCheck();
                      }
                  }
              });
          } else {
              this.closeFileNoCheck();
          }
      }
  
      closeFileNoCheck() {
          this.appModel.closeFile(this.model);
      }
  
      keyFileChange(e) {
          switch (e.target.value) {
              case 'old':
                  this.selectOldKeyFile();
                  break;
              case 'gen':
                  this.generateKeyFile();
                  break;
              case 'none':
                  this.clearKeyFile();
                  break;
          }
      }
  
      selectOldKeyFile() {
          this.model.resetKeyFile();
          this.renderKeyFileSelect();
      }
  
      generateKeyFile() {
          const keyFile = this.model.generateAndSetKeyFile();
          const blob = new Blob([keyFile], { type: 'application/octet-stream' });
          FileSaver.saveAs(blob, this.model.name + '.key');
          this.renderKeyFileSelect();
      }
  
      clearKeyFile() {
          this.model.removeKeyFile();
          this.renderKeyFileSelect();
      }
  
      triggerSelectFile() {
          this.$el.find('#settings__file-file-select').click();
      }
  
      fileSelected(e) {
          const file = e.target.files[0];
          const reader = new FileReader();
          reader.onload = e => {
              const res = e.target.result;
              this.model.setKeyFile(res, file.name);
              this.renderKeyFileSelect();
          };
          reader.readAsArrayBuffer(file);
      }
  
      focusMasterPass(e) {
          e.target.value = '';
          e.target.setAttribute('type', 'text');
          this.model.passwordChanged = false;
      }
  
      changeMasterPass(e) {
          if (!e.target.value) {
              this.model.resetPassword();
              this.$el.find('.settings__file-master-pass-warning').hide();
          } else {
              this.$el.find('#settings__file-confirm-master-pass-group').show();
              this.$el
                  .find('#settings__file-master-pass-warning-text')
                  .text(Locale.setFilePassChange);
              if (!this.model.created) {
                  this.$el.find('.settings__file-master-pass-warning').show();
              }
          }
      }
  
      blurMasterPass(e) {
          if (!e.target.value) {
              this.model.resetPassword();
              this.resetConfirmMasterPass();
              e.target.value = PasswordPresenter.present(this.model.passwordLength);
              this.$el.find('.settings__file-master-pass-warning').hide();
          }
          e.target.setAttribute('type', 'password');
      }
  
      resetConfirmMasterPass() {
          this.$el.find('#settings__file-confirm-master-pass').val('');
          this.$el.find('#settings__file-confirm-master-pass-group').hide();
          this.$el.find('#settings__file-master-pass-warning-text').text(Locale.setFilePassChange);
      }
  
      focusConfirmMasterPass(e) {
          e.target.value = '';
          e.target.setAttribute('type', 'text');
      }
  
      blurConfirmMasterPass(e) {
          e.target.setAttribute('type', 'password');
          const masterPassword = this.$el.find('#settings__file-master-pass').val();
          const confirmPassword = e.target.value;
          if (masterPassword === confirmPassword) {
              this.$el
                  .find('#settings__file-master-pass-warning-text')
                  .text(Locale.setFilePassChanged);
              this.$el.find('.settings__file-confirm-master-pass-warning').hide();
              this.model.setPassword(kdbxweb.ProtectedValue.fromString(confirmPassword));
          } else {
              this.$el
                  .find('#settings__file-master-pass-warning-text')
                  .text(Locale.setFilePassChange);
              this.$el.find('.settings__file-confirm-master-pass-warning').show();
              this.model.resetPassword();
          }
      }
  
      changeName(e) {
          const value = $.trim(e.target.value);
          if (!value) {
              return;
          }
          this.model.setName(value);
      }
  
      changeDefUser(e) {
          const value = $.trim(e.target.value);
          this.model.setDefaultUser(value);
      }
  
      changeBackupEnabled(e) {
          const enabled = e.target.checked;
          let backup = this.model.backup;
          if (!backup) {
              backup = { enabled, schedule: DefaultBackupSchedule };
              const defaultPath = DefaultBackupPath.replace('{name}', this.model.name);
              if (Launcher) {
                  backup.storage = 'file';
                  backup.path = Launcher.getDocumentsPath(defaultPath);
              } else {
                  backup.storage = 'dropbox';
                  backup.path = defaultPath;
              }
              // } else if (this.model.storage === 'webdav') {
              //     backup.storage = 'webdav';
              //     backup.path = this.model.path + '.{date}.bak';
              // } else if (this.model.storage) {
              //     backup.storage = this.model.storage;
              //     backup.path = DefaultBackupPath.replace('{name}', this.model.name);
              // } else {
              //     Object.keys(Storage).forEach(name => {
              //         var prv = Storage[name];
              //         if (!backup.storage && !prv.system && prv.enabled) {
              //             backup.storage = name;
              //         }
              //     });
              //     if (!backup.storage) {
              //         e.target.checked = false;
              //         return;
              //     }
              //     backup.path = DefaultBackupPath.replace('{name}', this.model.name);
              // }
              this.$el.find('#settings__file-backup-storage').val(backup.storage);
              this.$el.find('#settings__file-backup-path').val(backup.path);
          }
          this.$el.find('.settings__file-backups').toggleClass('hide', !enabled);
          backup.enabled = enabled;
          this.setBackup(backup);
      }
  
      changeBackupPath(e) {
          const backup = this.model.backup;
          backup.path = e.target.value.trim();
          this.setBackup(backup);
      }
  
      changeBackupStorage(e) {
          const backup = this.model.backup;
          backup.storage = e.target.value;
          this.setBackup(backup);
      }
  
      changeBackupSchedule(e) {
          const backup = this.model.backup;
          backup.schedule = e.target.value;
          this.setBackup(backup);
      }
  
      setBackup(backup) {
          this.model.backup = backup;
          this.appModel.setFileBackup(this.model.id, backup);
      }
  
      backupFile() {
          if (this.backupInProgress) {
              return;
          }
          const backupButton = this.$el.find('.settings__file-button-backup');
          backupButton.text(Locale.setFileBackupNowWorking);
          this.model.getData(data => {
              if (!data) {
                  this.backupInProgress = false;
                  backupButton.text(Locale.setFileBackupNow);
                  return;
              }
              this.appModel.backupFile(this.model, data, err => {
                  this.backupInProgress = false;
                  backupButton.text(Locale.setFileBackupNow);
                  if (err) {
                      let title = '';
                      let description = '';
                      if (err.isDir) {
                          title = Locale.setFileBackupErrorIsDir;
                          description = Locale.setFileBackupErrorIsDirDescription;
                      } else {
                          title = Locale.setFileBackupError;
                          description = Locale.setFileBackupErrorDescription;
                      }
                      Alerts.error({
                          title,
                          body:
                              description +
                              '<pre class="modal__pre">' +
                              escape(err.toString()) +
                              '</pre>'
                      });
                  }
              });
          });
      }
  
      changeTrash(e) {
          this.model.setRecycleBinEnabled(e.target.checked);
      }
  
      changeHistoryLength(e) {
          if (!e.target.validity.valid) {
              return;
          }
          const value = +e.target.value;
          if (isNaN(value)) {
              e.target.value = this.model.historyMaxItems;
              return;
          }
          this.model.setHistoryMaxItems(value);
      }
  
      changeHistorySize(e) {
          if (!e.target.validity.valid) {
              return;
          }
          const value = +e.target.value;
          if (isNaN(value)) {
              e.target.value = this.model.historyMaxSize / 1024 / 1024;
              return;
          }
          this.model.setHistoryMaxSize(value * 1024 * 1024);
      }
  
      changeFormatVersion(e) {
          const version = +e.target.value;
          this.model.setFormatVersion(version);
          this.render();
      }
  
      changeKdf(e) {
          this.model.setKdf(e.target.value);
          this.render();
      }
  
      changeKeyRounds(e) {
          if (!e.target.validity.valid) {
              return;
          }
          const value = +e.target.value;
          if (isNaN(value)) {
              e.target.value = this.model.keyEncryptionRounds;
              return;
          }
          this.model.setKeyEncryptionRounds(value);
      }
  
      changeKeyChangeForce(e) {
          if (!e.target.validity.valid) {
              return;
          }
          let value = Math.round(e.target.value);
          if (isNaN(value) || value <= 0) {
              value = -1;
          }
          this.model.setKeyChange(true, value);
      }
  
      changeKdfParameter(e) {
          if (!e.target.validity.valid) {
              return;
          }
          const field = $(e.target).data('field');
          const mul = $(e.target).data('mul') || 1;
          const value = e.target.value * mul;
          if (isNaN(value)) {
              e.target.value = Math.round(this.model.kdfParameters[field] / mul);
              return;
          }
          if (value > 0) {
              this.model.setKdfParameter(field, value);
          }
      }
  }
  
  export { SettingsFileView };
  