A top level class that contains reference information to all other data stores in the application. This class is not intended to contain full domain objects rather meta-data that points to the objects. Prefer to use just the domain objects required, rather than over using an object that contains references to everything.
 partial void ToModelPostprocessing(BudgetAnalyserStorageRoot dto, ref ApplicationDatabase model)
 {
     model.BudgetCollectionStorageKey = dto.BudgetCollectionRootDto.Source;
     model.LedgerBookStorageKey = dto.LedgerBookRootDto.Source;
     var taskMapper = new Mapper_ListToDoTaskDto_ToDoCollection();
     model.LedgerReconciliationToDoCollection = taskMapper.ToModel(dto.LedgerReconciliationToDoCollection);
     model.MatchingRulesCollectionStorageKey = dto.MatchingRulesCollectionRootDto.Source;
     model.StatementModelStorageKey = dto.StatementModelRootDto.Source;
 }
 partial void ToDtoPostprocessing(ref BudgetAnalyserStorageRoot dto, ApplicationDatabase model)
 {
     dto.BudgetCollectionRootDto = new StorageBranch { Source = model.BudgetCollectionStorageKey };
     dto.LedgerBookRootDto = new StorageBranch { Source = model.LedgerBookStorageKey };
     var mapper = new Mapper_ListToDoTaskDto_ToDoCollection();
     dto.LedgerReconciliationToDoCollection = mapper.ToDto(model.LedgerReconciliationToDoCollection);
     dto.MatchingRulesCollectionRootDto = new StorageBranch { Source = model.MatchingRulesCollectionStorageKey };
     dto.StatementModelRootDto = new StorageBranch { Source = model.StatementModelStorageKey };
 }
        partial void ToModelPostprocessing(BudgetAnalyserStorageRoot dto, ref ApplicationDatabase model)
        {
            model.BudgetCollectionStorageKey = dto.BudgetCollectionRootDto.Source;
            model.LedgerBookStorageKey       = dto.LedgerBookRootDto.Source;
            var taskMapper = new Mapper_ListToDoTaskDto_ToDoCollection();

            model.LedgerReconciliationToDoCollection = taskMapper.ToModel(dto.LedgerReconciliationToDoCollection);
            model.MatchingRulesCollectionStorageKey  = dto.MatchingRulesCollectionRootDto.Source;
            model.StatementModelStorageKey           = dto.StatementModelRootDto.Source;
        }
        /// <summary>
        ///     Saves the Budget Analyser database graph to persistent storage.
        /// </summary>
        /// <param name="budgetAnalyserDatabase">The budget analyser database.</param>
        /// <exception cref="System.ArgumentNullException"></exception>
        public async Task SaveAsync(ApplicationDatabase budgetAnalyserDatabase)
        {
            if (budgetAnalyserDatabase == null)
            {
                throw new ArgumentNullException(nameof(budgetAnalyserDatabase));
            }

            var serialised = Serialise(this.mapper.ToDto(budgetAnalyserDatabase));

            await WriteToDiskAsync(budgetAnalyserDatabase.FileName, serialised);
        }
        public void TestInitialise()
        {
            this.subject = new XamlOnDiskApplicationDatabaseRepositoryTestHarness(new Mapper_BudgetAnalyserStorageRoot_ApplicationDatabase())
            {
                FileExistsOverride = fileName => true
            };

            Task<ApplicationDatabase> task = this.subject.LoadAsync(TestDataConstants.DemoBudgetAnalyserFileName);
            task.Wait();
            this.result = task.Result;
        }
        public void TestInitialise()
        {
            var todoCollection = new ToDoCollection();
            todoCollection.Add(new ToDoTask("Foo1"));
            todoCollection.Add(new ToDoTask("Foo2", false, false));
            this.testData = new ApplicationDatabase();
            PrivateAccessor.SetProperty(this.testData, "BudgetCollectionStorageKey", "Budget.xml");
            PrivateAccessor.SetProperty(this.testData, "FileName", "C:\\Foo\\TestData.bax");
            PrivateAccessor.SetProperty(this.testData, "LedgerBookStorageKey", "Ledger.xml");
            PrivateAccessor.SetProperty(this.testData, "MatchingRulesCollectionStorageKey", "Rules.xml");
            PrivateAccessor.SetProperty(this.testData, "StatementModelStorageKey", "Statement.xml");
            PrivateAccessor.SetProperty(this.testData, "LedgerReconciliationToDoCollection", todoCollection);

            var subject = new Mapper_BudgetAnalyserStorageRoot_ApplicationDatabase();
            this.result = subject.ToDto(this.testData);
        }
        partial void ToDtoPostprocessing(ref BudgetAnalyserStorageRoot dto, ApplicationDatabase model)
        {
            dto.BudgetCollectionRootDto = new StorageBranch {
                Source = model.BudgetCollectionStorageKey
            };
            dto.LedgerBookRootDto = new StorageBranch {
                Source = model.LedgerBookStorageKey
            };
            var mapper = new Mapper_ListToDoTaskDto_ToDoCollection();

            dto.LedgerReconciliationToDoCollection = mapper.ToDto(model.LedgerReconciliationToDoCollection);
            dto.MatchingRulesCollectionRootDto     = new StorageBranch {
                Source = model.MatchingRulesCollectionStorageKey
            };
            dto.StatementModelRootDto = new StorageBranch {
                Source = model.StatementModelStorageKey
            };
        }
        public void TestInitialise()
        {
            this.testData = new BudgetAnalyserStorageRoot
            {
                BudgetCollectionRootDto = new StorageBranch { Source = "Budget.xml" },
                LedgerBookRootDto = new StorageBranch { Source = "Ledger.xml" },
                MatchingRulesCollectionRootDto = new StorageBranch { Source = "Rules.xml" },
                StatementModelRootDto = new StorageBranch { Source = "Statement.xml" },
                LedgerReconciliationToDoCollection = new List<ToDoTaskDto>
                {
                    new ToDoTaskDto { CanDelete = true, Description = "Foo1", SystemGenerated = false },
                    new ToDoTaskDto { CanDelete = false, Description = "Foo2", SystemGenerated = true }
                }
            };

            var subject = new Mapper_BudgetAnalyserStorageRoot_ApplicationDatabase();
            this.result = subject.ToModel(this.testData);
        }
        /// <summary>
        ///     Updates the widget with new input.
        /// </summary>
        /// <exception cref="System.ArgumentNullException"></exception>
        public override void Update([NotNull] params object[] input)
        {
            if (input == null)
            {
                throw new ArgumentNullException(nameof(input));
            }

            var newAppDb = (ApplicationDatabase) input[0];
            if (newAppDb == null)
            {
                this.appDb = null;
            }
            else
            {
                this.appDb = newAppDb;
            }

            if (this.appDb == null) return;
            WidgetActivated();
        }
        public async Task LoadAsync(ApplicationDatabase applicationDatabase)
        {
            this.matchingRules.Clear();
            this.matchingRulesGroupedByBucket.Clear();
            this.rulesStorageKey = applicationDatabase.FullPath(applicationDatabase.MatchingRulesCollectionStorageKey);
            List<MatchingRule> repoRules;
            try
            {
                repoRules = (await this.ruleRepository.LoadAsync(this.rulesStorageKey, applicationDatabase.IsEncrypted))
                    .OrderBy(r => r.Description)
                    .ToList();
            }
            catch (FileNotFoundException)
            {
                // If file not found occurs here, assume this is the first time the app has run, and create a new one.
                this.rulesStorageKey = await BuildDefaultFileName();
                repoRules = this.ruleRepository.CreateNew().ToList();
            }

            InitialiseTheRulesCollections(repoRules);

            this.monitorableDependencies.NotifyOfDependencyChange<ITransactionRuleService>(this);
            NewDataSourceAvailable?.Invoke(this, EventArgs.Empty);
        }
        /// <summary>
        ///     Create a new <see cref="StatementModel" />.
        /// </summary>
        /// <exception cref="System.ArgumentNullException"></exception>
        public async Task CreateAsync(ApplicationDatabase applicationDatabase)
        {
            if (applicationDatabase.StatementModelStorageKey.IsNothing())
            {
                throw new ArgumentNullException(nameof(applicationDatabase));
            }

            await this.statementRepository.CreateNewAndSaveAsync(applicationDatabase.StatementModelStorageKey);
            await LoadAsync(applicationDatabase);
        }
        /// <summary>
        ///     Saves the Budget Analyser database graph to persistent storage.
        /// </summary>
        /// <param name="budgetAnalyserDatabase">The budget analyser database.</param>
        /// <exception cref="System.ArgumentNullException"></exception>
        public async Task SaveAsync(ApplicationDatabase budgetAnalyserDatabase)
        {
            if (budgetAnalyserDatabase == null)
            {
                throw new ArgumentNullException(nameof(budgetAnalyserDatabase));
            }

            var serialised = Serialise(this.mapper.ToDto(budgetAnalyserDatabase));
            await WriteToDiskAsync(budgetAnalyserDatabase.FileName, serialised);
        }
        public async Task SaveAsync(ApplicationDatabase applicationDatabase)
        {
            EnsureAllBucketsUsedAreInBucketRepo();

            var messages = new StringBuilder();
            if (Budgets.Validate(messages))
            {
                await this.budgetRepository.SaveAsync(applicationDatabase.FullPath(applicationDatabase.BudgetCollectionStorageKey), applicationDatabase.IsEncrypted);
                var savedHandler = Saved;
                savedHandler?.Invoke(this, EventArgs.Empty);
                return;
            }

            this.logger.LogWarning(l => l.Format("BudgetMaintenanceService.Save: unable to save due to validation errors:\n{0}", messages));
            throw new ValidationWarningException("Unable to save Budget:\n" + messages);
        }
        /// <summary>
        ///     Loads a data source with the provided database reference data asynchronously.
        /// </summary>
        /// <exception cref="System.ArgumentNullException"></exception>
        /// <exception cref="DataFormatException">Statement Model data is corrupt and has been tampered with. Unable to load.</exception>
        public async Task LoadAsync(ApplicationDatabase applicationDatabase)
        {
            if (applicationDatabase == null)
            {
                throw new ArgumentNullException(nameof(applicationDatabase));
            }

            StatementModel?.Dispose();
            try
            {
                StatementModel = await this.statementRepository.LoadAsync(applicationDatabase.FullPath(applicationDatabase.StatementModelStorageKey), applicationDatabase.IsEncrypted);
            }
            catch (StatementModelChecksumException ex)
            {
                throw new DataFormatException("Statement Model data is corrupt and has been tampered with. Unable to load.", ex);
            }

            NewDataAvailable();
        }
        public async Task<ApplicationDatabase> LoadAsync(string storageKey)
        {
            if (storageKey.IsNothing())
            {
                throw new ArgumentNullException(nameof(storageKey));
            }

            ClearDirtyDataFlags();
            var encryptionKey = this.credentialStore.RetrievePasskey();
            this.budgetAnalyserDatabase = await this.applicationRepository.LoadAsync(storageKey);
            if (this.budgetAnalyserDatabase.IsEncrypted && encryptionKey == null)
            {
                throw new EncryptionKeyNotProvidedException($"{this.budgetAnalyserDatabase.FileName} is encrypted and no password has been provided.");
            }

            try
            {
                foreach (var service in this.databaseDependents) // Already sorted ascending by sequence number.
                {
                    this.logger.LogInfo(l => $"Loading service: {service}");
                    await service.LoadAsync(this.budgetAnalyserDatabase);
                }
            }
            catch (DataFormatException ex)
            {
                Close();
                throw new DataFormatException("A subordindate data file is invalid or corrupt unable to load " + storageKey, ex);
            }
            catch (KeyNotFoundException ex)
            {
                Close();
                throw new KeyNotFoundException("A subordinate data file cannot be found: " + ex.Message, ex);
            }
            catch (NotSupportedException ex)
            {
                Close();
                throw new DataFormatException("A subordinate data file contains unsupported data.", ex);
            }

            this.monitorableDependencies.NotifyOfDependencyChange(this.budgetAnalyserDatabase);
            this.monitorableDependencies.NotifyOfDependencyChange<IApplicationDatabaseService>(this);
            return this.budgetAnalyserDatabase;
        }
 /// <summary>
 ///     Saves the application database asynchronously. This may be called using a background worker thread.
 /// </summary>
 public Task SaveAsync(ApplicationDatabase applicationDatabase)
 {
     // Nothing needs to be done here.
     return Task.CompletedTask;
 }
        /// <summary>
        ///     Loads a data source with the provided database reference data asynchronously.
        /// </summary>
        public Task LoadAsync(ApplicationDatabase applicationDatabase)
        {
            if (applicationDatabase == null)
            {
                throw new ArgumentNullException(nameof(applicationDatabase));
            }

            // The To Do Collection persistence is managed by the ApplicationDatabaseService.
            ReconciliationToDoList = applicationDatabase.LedgerReconciliationToDoCollection;
            return Task.CompletedTask;
        }
        /// <summary>
        ///     Saves the application database asynchronously. This may be called using a background worker thread.
        /// </summary>
        /// <exception cref="ValidationWarningException">
        ///     Unable to save transactions at this time, some data is invalid.  +
        ///     messages
        /// </exception>
        public async Task SaveAsync(ApplicationDatabase applicationDatabase)
        {
            if (StatementModel == null)
            {
                return;
            }

            EventHandler<AdditionalInformationRequestedEventArgs> handler = Saving;
            handler?.Invoke(this, new AdditionalInformationRequestedEventArgs());

            var messages = new StringBuilder();
            if (!ValidateModel(messages))
            {
                throw new ValidationWarningException("Unable to save transactions at this time, some data is invalid. " + messages);
            }

            StatementModel.StorageKey = applicationDatabase.FullPath(applicationDatabase.StatementModelStorageKey);
            await this.statementRepository.SaveAsync(StatementModel, applicationDatabase.IsEncrypted);
            this.monitorableDependencies.NotifyOfDependencyChange(StatementModel);
            Saved?.Invoke(this, EventArgs.Empty);
        }
        public async Task<ApplicationDatabase> CreateNewDatabaseAsync(string storageKey)
        {
            if (storageKey.IsNothing())
            {
                throw new ArgumentNullException(nameof(storageKey));
            }

            ClearDirtyDataFlags();
            this.budgetAnalyserDatabase = await this.applicationRepository.CreateNewAsync(storageKey);
            foreach (var service in this.databaseDependents)
            {
                await service.CreateAsync(this.budgetAnalyserDatabase);
            }

            this.monitorableDependencies.NotifyOfDependencyChange(this.budgetAnalyserDatabase);
            return this.budgetAnalyserDatabase;
        }
        public async Task SaveAsync(ApplicationDatabase applicationDatabase)
        {
            var messages = new StringBuilder();
            if (ValidateModel(messages))
            {
                // Prefer to use the file name from the applicationDatabase in case it has been changed upstream.
                await this.ruleRepository.SaveAsync(MatchingRules, applicationDatabase.FullPath(applicationDatabase.MatchingRulesCollectionStorageKey), applicationDatabase.IsEncrypted);
            }
            else
            {
                throw new ValidationWarningException("Unable to save matching rules at this time, some data is invalid.\n" + messages);
            }

            this.monitorableDependencies.NotifyOfDependencyChange<ITransactionRuleService>(this);
            Saved?.Invoke(this, EventArgs.Empty);
        }
        public async Task CreateAsync(ApplicationDatabase applicationDatabase)
        {
            if (applicationDatabase.MatchingRulesCollectionStorageKey.IsNothing())
            {
                throw new ArgumentNullException(nameof(applicationDatabase));
            }

            await this.ruleRepository.CreateNewAndSaveAsync(applicationDatabase.MatchingRulesCollectionStorageKey);
            await LoadAsync(applicationDatabase);
        }
        public async Task LoadAsync(ApplicationDatabase applicationDatabase)
        {
            if (applicationDatabase == null)
            {
                throw new ArgumentNullException(nameof(applicationDatabase));
            }

            Budgets = await this.budgetRepository.LoadAsync(applicationDatabase.FullPath(applicationDatabase.BudgetCollectionStorageKey), applicationDatabase.IsEncrypted);
            UpdateServiceMonitor();
            NewDataSourceAvailable?.Invoke(this, EventArgs.Empty);
        }