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.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;



    $scope.validateStep6 = function () {
        if (!$scope.Backup) return;
        if (!$scope.Backup.Alerts) return;

        $scope.step6IsValid = $scope.Backup.Alerts && $scope.Backup.Alerts.every(a => a.isValid);
    };

    $scope.validateRepeat = function() {
        const unit = scope.Schedule.Repeat.slice(-1);
        const number = parseInt(scope.Schedule.Repeat.slice(0, -1));
        if (number > 99)
        {
            scope.Schedule.Repeat = '99'+unit;
        }
        else if (number <= 0) {
            scope.Schedule.Repeat = '1'+unit;

        }
    }

    $scope.validateKeepversion = function () {
        let keepversions = $scope.Options['keep-versions'];
        if(isNaN(keepversions)) {
            keepversions = 1;
        }
        else if (keepversions > 9999)
        {
            keepversions = 9999;
        }
        else if (keepversions <= 0) {
            keepversions = 1;
        }
        $scope.Options['keep-versions'] = keepversions;
    }

    $scope.validateKeeptime = function() {
        let keeptime = $scope.Options['keep-time'];
        if (!keeptime) return;
        

        const unit = keeptime.slice(-1);
        const number = parseInt(keeptime.slice(0, -1));
        if(isNaN(number)) {
            keeptime = undefined;
        }
        else if (number > 99)
        {
            keeptime = '99'+unit;
        }
        else if (number <= 0) {
            keeptime = '1'+unit;
        }

        $scope.Options['keep-time'] = keeptime;
    }

    
    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.maxNumberOfRecipients = 10;
    $scope.AddRecipient = function () {

        if ($scope.Backup.Alerts == null) {
            $scope.Backup.Alerts = [];
        }

        if ($scope.Backup.Alerts.length < $scope.maxNumberOfRecipients) {
            $scope.Backup.Alerts.push({ Recipient: '', TriggerLevels: ['Error', 'Fatal'] });
        }
    }

    $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;
            }

            // if (!scope.step1IsValid) {
            //     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 (response) {
                    $location.path('/saved/'+response.data.ID);
                }, 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('/saved/' + $routeParams.backupid);
                }, AppUtils.connectionError);
            }

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


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

        if (data.ApplicationOptions)
        {
            let sshKeyFileOptions = data.ApplicationOptions.filter(o => o.Name == 'ssh-keyfile')
            if (sshKeyFileOptions.length > 0 && sshKeyFileOptions[0].Value)
            {
                $scope.sshKeyFile = sshKeyFileOptions[0].Value
            }
        }

        $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('/');
        });
    }

    $scope.sendingTestEmail = false;
    $scope.sendTestEmail = function () {
        if ($scope.sendingTestEmail) return;

        $scope.sendingTestEmail = true;
        dlg = DialogService.dialog(gettextCatalog.getString('Testing ...'), gettextCatalog.getString('Test sending emails...'), [], null, function () {
            const recipients = $scope.Backup.Alerts.map(a => a.Recipient)
            AppService.post('/test/sendMail', { Recipients: recipients }, { 'headers': { 'Content-Type': 'application/json' } })
                .then(() => {
                    dlg.dismiss();

                    DialogService.dialog(gettextCatalog.getString('Email test sent') , gettextCatalog.getString('An email has been sent to the recipients. If it appear in the SPAM folder think to mark the sender email as trusted one.'))
                    $scope.sendingTestEmail = false;
                })
        }, (data) => {
            DialogService.dialog(gettextCatalog.getString('Error') , gettextCatalog.getString('We encountered an error while sending the email.'))
        $scope.sendingTestEmail = false;
        })
    }

    function RelativeDate() {
        if(!scope.Schedule) return;
        scope.Schedule.NextTime = AppUtils.RelativeDate(scope.Schedule.Time);
    }
    $scope.$watch("Schedule.Time", RelativeDate);
});
