backupApp.controller('EditBackupController', function ($rootScope, $scope, $routeParams, $location, $timeout, AppService, AppUtils, SystemInfo, DialogService, EditBackupService, gettext, gettextCatalog) {

    var SMART_RETENTION = '1W:1D,4W:1W,12M:1M';

    $scope.SystemInfo = SystemInfo.watch($scope);
    $scope.AppUtils = AppUtils;

    $scope.isEditMode = $routeParams.backupid > 0
    $scope.step2IsValid = $scope.isEditMode;

    $scope.RepeatPasshrase = '';
    $scope.PasswordStrength = 'unknown';
    $scope.CurrentStep = 0;
    $scope.showhiddenfolders = false;
    $scope.EditSourceAdvanced = false;
    $scope.EditFilterAdvanced = false;

    $scope.ExcludeAttributes = [];
    $scope.ExcludeLargeFiles = false;

    $scope.notificationConfig = {
        Recipient: [ '' ],
        Levels: []
    }

    $scope.fileAttributes = [
        {'name': gettextCatalog.getString('Hidden files'), 'value': 'hidden'},
        {'name': gettextCatalog.getString('System files'), 'value': 'system'},
        {'name': gettextCatalog.getString('Temporary files'), 'value': 'temporary'}
    ];

    const scope = $scope;

    function computePassPhraseStrength() {

        const strengthMap = {
            'x': gettextCatalog.getString("Passphrases do not match"),
            0: gettextCatalog.getString("Useless"),
            1: gettextCatalog.getString("Very weak"),
            2: gettextCatalog.getString("Weak"),
            3: gettextCatalog.getString("Strong"),
            4: gettextCatalog.getString("Very strong")
        };

        const passphrase = scope.Options == null ? '' : scope.Options['passphrase'] ?? '';

        if (scope.RepeatPasshrase != passphrase)
            scope.PassphraseScore = 'x';
        else if ((passphrase || '') == '')
            scope.PassphraseScore = '';
        else
            scope.PassphraseScore = (zxcvbn(passphrase.substring(0, 100)) || {'score': -1}).score;

        scope.PassphraseScoreString = strengthMap[scope.PassphraseScore];
        isStep1Valid();
    }

    function isStep1Valid() {
        scope.step1IsValid = scope.Backup?.Name != undefined && scope.Backup?.Name != '' && scope.Options && scope.RepeatPasshrase == (scope.Options['passphrase'] ?? '');
    }

    $scope.$watch('Options["passphrase"]', computePassPhraseStrength);
    $scope.$watch('RepeatPasshrase', computePassPhraseStrength);
    $scope.$watch('Backup.Name', isStep1Valid);

    $scope.checkGpgAsymmetric = function() {
        if (!this.Options) {
            return false;
        }

        if (!('encryption-module' in this.Options)) {
            return false;
        }

        if (!this.Options['encryption-module']) {
            return false;
        }

        if (this.Options['encryption-module'].indexOf('gpg') < 0) {
            return false;
        }

        return this.ExtendedOptions.includes('--gpg-encryption-command=--encrypt');
    }

    $scope.generatePassphrase = function() {
        this.Options["passphrase"] = this.RepeatPasshrase = AppUtils.generatePassphrase();
        this.ShowPassphrase = true;
        this.HasGeneratedPassphrase = true;
    };

    $scope.togglePassphraseVisibility = function() {
        this.ShowPassphrase = !this.ShowPassphrase;
    };

    function warnPassphraseUsed () {
        DialogService.dialog(
            gettextCatalog.getString('Warning passphrase used'),
            gettextCatalog.getString('Make sure to remember your passphrase to be able to restore you data from another computer or installation. By using a passphrase, Eukless won\'t be able to get your data back in case you forget your passphrase.'),
            [gettextCatalog.getString('Cancel'), gettextCatalog.getString('Ok')],
            (idx) => {
                if (idx == 1) $scope.CurrentStep = 1;
            }
        );
    }

    $scope.nextPage = function() {
        if ($scope.CurrentStep == 0 && !$scope.isEditMode) {
            if ($scope.PassphraseScore == 'x') {
                DialogService.dialog(gettextCatalog.getString('Non-matching passphrase'), gettextCatalog.getString('Passphrases are not matching'));
                $scope.CurrentStep = 0;
                return;
            }
            if ($scope.Options['passphrase'] ?? '' != ''){
                warnWeakPassphrase(warnPassphraseUsed);
                return;
            }
            
        }
        $scope.CurrentStep = Math.min(5, $scope.CurrentStep + 1);
    };

    $scope.prevPage = function() {
        $scope.CurrentStep = Math.max(0, $scope.CurrentStep - 1);
    };

    $scope.setBuilduriFn = function(builduriFn) {
        $scope.builduri = builduriFn;
    };

    $scope.importUrl = function () {
        DialogService.textareaDialog('Import URL', 'Enter a Backup destination URL:', null, gettextCatalog.getString('Enter URL'), [gettextCatalog.getString('Cancel'), gettextCatalog.getString('OK')], null, function(btn, input) {
            if (btn == 1)
                scope.Backup.TargetURL = input;
        });
    };

    $scope.copyUrlToClipboard = function () {
        $scope.builduri(function(res) {
            DialogService.textareaDialog('Copy URL', null, null, res, [gettextCatalog.getString('OK')], 'templates/copy_clipboard_buttons.html');
        });
    };

    var oldSchedule = null;

    $scope.toggleSchedule = function() {
        if (scope.Schedule == null) {
            if (oldSchedule == null) {
                oldSchedule = {
                    Tags: [],
                    Repeat: '1D',
                    AllowedDays: []
                };
            }

            scope.Schedule = oldSchedule;
            oldSchedule = null;
        } else {
            oldSchedule = scope.Schedule;
            scope.Schedule = null;
        }
    };

    $scope.addManualSourcePath = function() {
        if (scope.validatingSourcePath)
            return;

        if (scope.manualSourcePath == null || scope.manualSourcePath == '')
            return;

        var dirsep = scope.SystemInfo.DirectorySeparator || '/';

        if (dirsep == '/') {
            if (scope.manualSourcePath.substr(0, 1) != '/' && scope.manualSourcePath.substr(0, 1) != '%') {
                DialogService.dialog(gettextCatalog.getString('Relative paths not allowed'), gettextCatalog.getString("The path must be an absolute path, i.e. it must start with a forward slash '/' "));
                return;
            }
        }

        function continuation() {
            scope.validatingSourcePath = true;

            AppService.post('/filesystem/validate', {path: scope.manualSourcePath}).then(function() {
                scope.validatingSourcePath = false;
                scope.Backup.Sources.push(scope.manualSourcePath);
                scope.manualSourcePath = null;
            }, function() {
                scope.validatingSourcePath = false;

                DialogService.dialog(gettextCatalog.getString('Path not found'), gettextCatalog.getString('The path does not appear to exist, do you want to add it anyway?'), [gettextCatalog.getString('No'), gettextCatalog.getString('Yes')], function(ix) {
                    if (ix == 1) {
                        scope.Backup.Sources.push(scope.manualSourcePath);
                        scope.manualSourcePath = null;
                    }
                });
            });
        }

        if (scope.manualSourcePath.substr(scope.manualSourcePath.length - 1, 1) != dirsep) {
            DialogService.dialog(gettextCatalog.getString('Include a file?'), gettextCatalog.getString("The path does not end with a '{{dirsep}}' character, which means that you include a file, not a folder.\n\nDo you want to include the specified file?", {dirsep: dirsep}), [gettextCatalog.getString('No'), gettextCatalog.getString('Yes')], function(ix) {
                if (ix == 1)
                    continuation();
            });
        } else {
            continuation();
        }
    };

    function toggleArraySelection(lst, value) {
        var ix = lst.indexOf(value);

        if (ix > -1)
            lst.splice(ix, 1);
        else
            lst.push(value);
    };

    $scope.toggleAllowedDays = function(value) {
        if ($scope.Schedule.AllowedDays == null)
            $scope.Schedule.AllowedDays = [];
        toggleArraySelection($scope.Schedule.AllowedDays, value);
    };

    $scope.toggleExcludeAttributes = function(value) {
        if ($scope.ExcludeAttributes == null)
            $scope.ExcludeAttributes = [];
        toggleArraySelection($scope.ExcludeAttributes, value);
    };

    function warnWeakPassphrase(continuation) {
        if (($scope.PassphraseScore == 0 || $scope.PassphraseScore == 1 || $scope.PassphraseScore == 2)) {
            DialogService.dialog(gettextCatalog.getString('Weak passphrase'), gettextCatalog.getString('Your passphrase is easy to guess. Consider changing passphrase.'), [gettextCatalog.getString('Cancel'), gettextCatalog.getString('Use weak passphrase')], function(ix) {
                if (ix == 0)
                    $scope.CurrentStep = 0;
                else
                    continuation();
            });
        }
        else
            continuation();
    };

    $scope.save = function() {

        if (!EditBackupService.preValidate($scope))
            return false;

        var result = {
            Backup: angular.copy($scope.Backup),
            Schedule: angular.copy($scope.Schedule)
        };

        var opts = angular.copy($scope.Options, opts);

        if (!$scope.ExcludeLargeFiles)
            delete opts['--skip-files-larger-than'];

        var encryptionEnabled = true;
        if ((opts['encryption-module'] || '').length == 0) {
            opts['--no-encryption'] = 'true';
            encryptionEnabled = false;
        }

        if (!AppUtils.parse_extra_options(scope.ExtendedOptions, opts))
            return false;

        for (var n in $scope.servermodulesettings)
            opts['--' + n] = $scope.servermodulesettings[n];

        var exclattr = ($scope.ExcludeAttributes || []).concat((opts['--exclude-files-attributes'] || '').split(','));
        var exclmap = { '': true };

        // Remove duplicates
        for (var i = exclattr.length - 1; i >= 0; i--) {
            exclattr[i] = (exclattr[i] || '').trim();
            var cmp = exclattr[i].toLowerCase();
            if (exclmap[cmp])
                exclattr.splice(i, 1);
            else
                exclmap[cmp] = true;
        }

        if (exclattr.length == 0)
            delete opts['--exclude-files-attributes'];
        else
            opts['--exclude-files-attributes'] = exclattr.join(',');

        if (($scope.Backup.Name || '').trim().length == 0) {
            DialogService.dialog(gettextCatalog.getString('Missing name'), gettextCatalog.getString('You must enter a name for the backup'));
            $scope.CurrentStep = 0;
            return;
        }

        // if (encryptionEnabled && !$scope.checkGpgAsymmetric()) {
            // if ($scope.PassphraseScore === '') {
            //     DialogService.dialog(gettextCatalog.getString('Missing passphrase'), gettextCatalog.getString('You must enter a passphrase or disable encryption'));
            //     $scope.CurrentStep = 0;
            //     return;
            // }

            // if ($scope.PassphraseScore == 'x') {
            //     DialogService.dialog(gettextCatalog.getString('Non-matching passphrase'), gettextCatalog.getString('Passphrases are not matching'));
            //     $scope.CurrentStep = 0;
            //     return;
            // }
        // }

        if ($scope.Backup.Sources == null || $scope.Backup.Sources.length == 0) {
            DialogService.dialog(gettextCatalog.getString('Missing sources'), gettextCatalog.getString('You must choose at least one source folder'));
            $scope.CurrentStep = 2;
            return;
        }

        // Retention options are mutual exclusive -> allow only one to be selected at a time
        function resetAllRetentionOptionsExcept(optionToKeep) {
            ['keep-versions', 'keep-time', 'retention-policy'].forEach(function(entry) {
                if (entry != optionToKeep) {
                    delete opts[entry];
                }
            });
        }

        if ($scope.KeepType == 'time') {
            resetAllRetentionOptionsExcept('keep-time');

        } else if ($scope.KeepType == 'versions') {
            resetAllRetentionOptionsExcept('keep-versions');

        } else if ($scope.KeepType == 'smart' || $scope.KeepType == 'custom') {
            resetAllRetentionOptionsExcept('retention-policy');

        } else {
            resetAllRetentionOptionsExcept(); // keep none
        }

        if ($scope.KeepType == 'time' && (opts['keep-time'] || '').trim().length == 0)
        {
            DialogService.dialog(gettextCatalog.getString('Invalid retention time'), gettextCatalog.getString('You must enter a valid duration for the time to keep backups'));
            $scope.CurrentStep = 4;
            return;
        }

        if ($scope.KeepType == 'versions' && (parseInt(opts['keep-versions']) <= 0 || isNaN(parseInt(opts['keep-versions']))))
        {
            DialogService.dialog(gettextCatalog.getString('Invalid retention time'), gettextCatalog.getString('You must enter a positive number of backups to keep'));
            $scope.CurrentStep = 4;
            return;
        }

        var retentionPolicy = (opts['retention-policy'] || '');
        var valid_chars = /^((\d+[smhDWMY]|U):(\d+[smhDWMY]|U),?)+$/;
        var valid_commas = /^(\d*\w:\d*\w,)*\d*\w:\d*\w$/;
        if ($scope.KeepType == 'custom' && (retentionPolicy.indexOf(':') <= 0 || valid_chars.test(retentionPolicy) === false || valid_commas.test(retentionPolicy) === false))
        {
            DialogService.dialog(gettextCatalog.getString('Invalid retention time'), gettextCatalog.getString('You must enter a valid retention policy string'));
            $scope.CurrentStep = 4;
            return;
        }

        if ($scope.KeepType == 'smart')
            opts['retention-policy'] = SMART_RETENTION;

        // Notification settings
        // for(const conf in $scope.notificationConfig) {
        //     opts[conf] = $scope.notificationConfig[conf]
        // }

        const selectedLevel = $scope.notificationConfig.Levels.filter(l => l.checked === true).map(l => l.label)
        if ($scope.notificationConfig.Recipient.length > 0 && selectedLevel.length > 0) {
            opts["--send-mail-to"] = $scope.notificationConfig.Recipient.join(',');
            opts["--send-mail-level"] = selectedLevel.join(',');
        } else {
            delete opts["--send-mail-to"]
            delete opts["--send-mail-level"]
        }

        result.Backup.Settings = [];
        for(var k in opts) {
            var origfilter = "";
            var origarg = null;
            for(var i in $scope.rawddata.Backup.Settings)
                if ($scope.rawddata.Backup.Settings[i].Name == k) {
                    origfilter = $scope.rawddata.Backup.Settings[i].Filter;
                    origarg = $scope.rawddata.Backup.Settings[i].Argument;
                    break;
                }

            result.Backup.Settings.push({
                Name: k,
                Value: opts[k],
                Filter: origfilter,
                Argument: origarg
            });
        }

        var filterstrings = result.Backup.Filters || [];
        result.Backup.Filters = [];
        for(var f in filterstrings)
            result.Backup.Filters.push({
                Order: result.Backup.Filters.length,
                Include: filterstrings[f].substr(0, 1) == '+',
                Expression: filterstrings[f].substr(1)
            });

        function checkForGeneratedPassphrase(continuation) {
            if (!$scope.HasGeneratedPassphrase || !encryptionEnabled)
                continuation();
            else
                DialogService.dialog(gettextCatalog.getString('Autogenerated passphrase'), gettextCatalog.getString('You have generated a strong passphrase. Make sure you have made a safe copy of the passphrase, as the data cannot be recovered if you lose the passphrase.'), [gettextCatalog.getString('Cancel'), gettextCatalog.getString('Yes, I have stored the passphrase safely')], function(ix) {
                    if (ix == 0)
                        $scope.CurrentStep = 0;
                    else
                    {
                        // Don't ask again
                        $scope.HasGeneratedPassphrase = false;
                        continuation();
                    }
                });
        };

        function checkForChangedPassphrase(continuation) {
            function findPrevOpt(key) {
                var sets = $scope.rawddata.Backup.Settings;
                for(var k in sets)
                    if (sets[k].Name == key)
                        return sets[k];

                return null;
            };

            var previousEncryptionOpt = findPrevOpt('--no-encryption');
            var prevPassphraseOpt = findPrevOpt('passphrase');
            var previousEncryptionModuleOpt = findPrevOpt('encryption-module');

            var prevPassphrase = prevPassphraseOpt == null ? null : prevPassphraseOpt.Value;
            var previousEncryptionEnabled = previousEncryptionOpt == null ? true : !AppUtils.parseBoolString(previousEncryptionOpt.Value, true);
            var previousEncryptionModule = (!previousEncryptionEnabled || previousEncryptionModuleOpt == null) ? '' : (previousEncryptionModuleOpt.Value || '');

            var encryptionModule = opts['encryption-module'] || '';

            if (encryptionEnabled && previousEncryptionEnabled && prevPassphrase != opts['passphrase'])
            {
                DialogService.dialog(gettextCatalog.getString('Passphrase changed'), gettextCatalog.getString('You have changed the passphrase, which is not supported. You are encouraged to create a new backup instead.'), [gettextCatalog.getString('Cancel'), gettextCatalog.getString('Yes, please break my backup!')], function(ix) {
                    if (ix == 0)
                        $scope.CurrentStep = 0;
                    else
                        continuation();
                });
            }
            else if (encryptionEnabled != previousEncryptionEnabled || encryptionModule != previousEncryptionModule)
            {
                DialogService.dialog(gettextCatalog.getString('Encryption changed'), gettextCatalog.getString('You have changed the encryption mode. This may break stuff. You are encouraged to create a new backup instead'), [gettextCatalog.getString('Cancel'), gettextCatalog.getString('Yes, I\'m brave!')], function(ix) {
                    if (ix == 1)
                        continuation();
                });
            }
            else
                continuation();

        };

        function checkForValidBackupDestination(continuation) {
            var success = false;
            $scope.builduri(function(res) {
                result.Backup.TargetURL = res;
                $scope.Backup.TargetURL = res;
                success = true;
                continuation();
            });

            if (!success)
                $scope.CurrentStep = 1;
        }

        function checkForDisabledEncryption(continuation) {
            if (encryptionEnabled || $scope.Backup.TargetURL.indexOf('file://') == 0 || $scope.SystemInfo.EncryptionModules.length == 0)
                continuation();
            else
                DialogService.dialog(gettextCatalog.getString('No encryption'), gettextCatalog.getString('You have chosen not to encrypt the backup. Encryption is recommended for all data stored on a remote server.'), [gettextCatalog.getString('Cancel'), gettextCatalog.getString('Continue without encryption')], function(ix) {
                    if (ix == 0)
                        $scope.CurrentStep = 0;
                    else
                        continuation();
                });
        };


        if ($routeParams.backupid == null) {

            function postDb() {
                AppService.post('/backups', result, {'headers': {'Content-Type': 'application/json'}}).then(function() {
                    $location.path('/');
                }, AppUtils.connectionError);
            };

            function checkForExistingDb(continuation) {
                AppService.post('/remoteoperation/dbpath', $scope.Backup.TargetURL, {'headers': {'Content-Type': 'application/text'}}).then(
                    function(resp) {
                        if (resp.data.Exists) {
                            DialogService.dialog(gettextCatalog.getString('Use existing database?'), gettextCatalog.getString('An existing local database for the storage has been found.\nRe-using the database will allow the command-line and server instances to work on the same remote storage.\n\n Do you wish to use the existing database?'), [gettextCatalog.getString('Cancel'), gettextCatalog.getString('Yes'), gettextCatalog.getString('No')], function(ix) {
                                if (ix == 2)
                                    result.Backup.DBPath = resp.data.Path;

                                if (ix == 1 || ix == 2)
                                    continuation();
                            });
                        }
                        else
                            continuation();

                    }, AppUtils.connectionError
                );
            };

            // Chain calls
            checkForGeneratedPassphrase(function() {
                checkForValidBackupDestination(function() {
                    checkForDisabledEncryption(function() {
                        // warnWeakPassphrase(function() {
                            checkForExistingDb(function () {
                                EditBackupService.postValidate($scope, postDb);
                            });
                        // });
                    });
                });
            });


        } else {

            function putDb() {
                AppService.put('/backup/' + $routeParams.backupid, result, {'headers': {'Content-Type': 'application/json'}}).then(function() {
                    $location.path('/');
                }, AppUtils.connectionError);
            }

            checkForChangedPassphrase(function() {
                checkForValidBackupDestination(putDb);
            });
        }
    };


    function setupScope(data) {
        $scope.Backup = angular.copy(data.Backup);
        $scope.Schedule = angular.copy(data.Schedule);        

        $scope.Options = {};
        var extopts = {};

        for(var n in $scope.Backup.Settings) {
            var e = $scope.Backup.Settings[n];
            if (e.Name.indexOf('--') == 0)
                extopts[e.Name] = e.Value;
            else
                $scope.Options[e.Name] = e.Value;
        }

        var filters = $scope.Backup.Filters;
        $scope.Backup.Filters = [];

        // If Description is anything other than a string, we are either creating a new
        // backup or something went wrong when retrieving an existing one
        // Either way we should set it to an empty string
        if (typeof $scope.Backup.Description !== 'string') {
            $scope.Backup.Description = '';
        }

        $scope.Backup.Sources = $scope.Backup.Sources || [];

        for(var ix in filters)
            $scope.Backup.Filters.push((filters[ix].Include ? '+' : '-') + filters[ix].Expression);

        $scope.ExcludeLargeFiles = (extopts['--skip-files-larger-than'] || '').trim().length > 0;
        if ($scope.ExcludeLargeFiles)
            $scope.Options['--skip-files-larger-than'] = extopts['--skip-files-larger-than'];

        var exclattr = (extopts['--exclude-files-attributes'] || '').split(',');
        var dispattr = $routeParams.backupid == null ? ['hidden', 'system', 'temporary'] : [];
        var dispmap = {};

        for (var i = exclattr.length - 1; i >= 0; i--) {
            var cmp = (exclattr[i] || '').trim().toLowerCase();

            // Remove empty entries
            if (cmp.length == 0) {
                exclattr.splice(i, 1);
                continue;
            }

            for (var j = scope.fileAttributes.length - 1; j >= 0; j--) {
                if (scope.fileAttributes[j].value == cmp) {
                    // Remote duplicates
                    if (dispmap[cmp] == null) {
                        dispattr.push(scope.fileAttributes[j].value);
                        dispmap[cmp] = true;
                    }
                    exclattr.splice(i, 1);
                    break;
                }
            }
        }

        $scope.ExcludeAttributes = dispattr;
        if (exclattr.length == 0)
            delete extopts['--exclude-files-attributes'];
        else
            extopts['--exclude-files-attributes'] = exclattr.join(',');

        $scope.RepeatPasshrase = $scope.Options['passphrase'] ?? '';

        $scope.KeepType = '';
        if (($scope.Options['keep-time'] || '').trim().length != 0)
        {
            $scope.KeepType = 'time';
        }
        else if (($scope.Options['keep-versions'] || '').trim().length != 0)
        {
            $scope.Options['keep-versions'] = parseInt($scope.Options['keep-versions']);
            $scope.KeepType = 'versions';
        }
        else if (($scope.Options['retention-policy'] || '').trim().length != 0)
        {
            if (($scope.Options['retention-policy'] || '').trim() == SMART_RETENTION)
                $scope.KeepType = 'smart';
            else
                $scope.KeepType = 'custom';
        }
        else if ($routeParams.backupid == null) {
            // for new job we set smart as the default type
            $scope.KeepType = 'smart';
        }

        var delopts = ['--skip-files-larger-than', '--no-encryption'];
        for(var n in delopts)
            delete extopts[delopts[n]];

        $scope.ExtendedOptions = AppUtils.serializeAdvancedOptionsToArray(extopts);

        $scope.servermodulesettings = {};
        AppUtils.extractServerModuleOptions($scope.ExtendedOptions, $scope.ServerModules, $scope.servermodulesettings, 'SupportedLocalCommands');

        $scope.showAdvanced = $scope.ExtendedOptions.length > 0;

        var now = new Date();
        if ($scope.Schedule != null) {
            var time = AppUtils.parseDate($scope.Schedule.Time);
            if (isNaN(time)) {
                time = AppUtils.parseDate("1970-01-01T" + $scope.Schedule.Time);
                if (!isNaN(time))
                    time = new Date(now.getFullYear(), now.getMonth(), now.getDate(), time.getHours(), time.getMinutes(), time.getSeconds());

                if (time < now)
                    time = new Date(time.setDate(time.getDate() + 1));
            }

            if (isNaN(time)) {
                time = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 13, 0, 0);
                if (time < now)
                    time = new Date(time.setDate(time.getDate() + 1));
            }

            $scope.Schedule.Time = time;
        } else {
            time = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 13, 0, 0);
            if (time < now)
                time = new Date(time.setDate(time.getDate() + 1));

            oldSchedule = {
                Repeat: '1D',
                Time: time
            };
        }

        // Notif scope   
        if (extopts['--send-mail-to']) $scope.notificationConfig.Recipient = extopts['--send-mail-to'].split(',')

        const initialLevels = [ {label:'Success'}, {label:'Warning'}, {label:'Error'}, {label:'Fatal'} ]
        if (extopts["--send-mail-level"]) {
            const selectedLevels = extopts["--send-mail-level"].split(',')
            for (const level of initialLevels) {
              level.checked = selectedLevels.find(l => l == level.label) !== undefined
            }
        }
        $scope.notificationConfig.Levels = initialLevels
    }

    function setupServerModules()
    {
        var mods = [];
        if ($scope.SystemInfo.ServerModules != null)
            for(var ix in $scope.SystemInfo.ServerModules)
            {
                var m = $scope.SystemInfo.ServerModules[ix];
                if (m.SupportedLocalCommands != null && m.SupportedLocalCommands.length > 0)
                    mods.push(m);
            }

        $scope.ServerModules = mods;
    };

    function reloadOptionsList()
    {
        if ($scope.Options == null)
            return;

        var encmodule = $scope.Options['encryption-module'] || '';
        var compmodule = $scope.Options['compression-module'] || $scope.Options['--compression-module'] || 'zip';
        var backmodule = $scope.Backup.TargetURL || '';
        var ix = backmodule.indexOf(':');
        if (ix > 0)
            backmodule = backmodule.substr(0, ix);

        $scope.ExtendedOptionList = AppUtils.buildOptionList($scope.SystemInfo, encmodule, compmodule, backmodule);
        setupServerModules();

        AppUtils.extractServerModuleOptions($scope.ExtendedOptions, $scope.ServerModules, $scope.servermodulesettings, 'SupportedLocalCommands');
    };

    function checkAllowedDaysConfig()
    {
        if ($scope.Schedule == null || $scope.Schedule.AllowedDays == null)
            return;

        // Remove invalid values
        var alldays = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'];
        for (var i = $scope.Schedule.AllowedDays.length - 1; i >= 0; i--)
            if (alldays.indexOf($scope.Schedule.AllowedDays[i]) < 0)
                $scope.Schedule.AllowedDays.splice(i, 1);

        // Empty and all are the same, but the UI confuses if no days are selected
        if ($scope.Schedule.AllowedDays.length == 0)
            $timeout(function() {
                $scope.Schedule.AllowedDays = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'];
            });
    };

    setupServerModules();

    $scope.$watch("Options['encryption-module']", reloadOptionsList);
    $scope.$watch("Options['compression-module']", reloadOptionsList);
    $scope.$watch("Options['--compression-module']", reloadOptionsList);
    $scope.$watch("Backup.TargetURL", reloadOptionsList);
    $scope.$on('systeminfochanged', reloadOptionsList);
    $scope.$watch('ExcludeLargeFiles', function() {
        if ($scope.Options != null && $scope.Options['--skip-files-larger-than'] == null)
            $scope.Options['--skip-files-larger-than'] = '100MB';
    });
    $scope.$watch("Schedule.AllowedDays", checkAllowedDaysConfig, true);

    if ($routeParams.backupid == null) {

        AppService.get('/backupdefaults').then(function(data) {

            $scope.rawddata = data.data.data;

            if ($location.$$path.indexOf('/add-import') == 0 && $rootScope.importConfig != null)
                angular.merge($scope.rawddata, $rootScope.importConfig);

            setupScope($scope.rawddata);

        }, function(data) {
            AppUtils.connectionError(gettextCatalog.getString('Failed to read backup defaults:') + ' ', data);
            $location.path('/');
        });
    } else {

        AppService.get('/backup/' + $routeParams.backupid).then(function(data) {

            $scope.rawddata = data.data.data;
            setupScope($scope.rawddata);

        }, function() {
            AppUtils.connectionError.apply(AppUtils, arguments);
            $location.path('/');
        });
    }
});
