Files @ 9f255f7e4422
Branch filter:

Location: ATITD-Tools/Desert-Paint-Codex/ViewModels/ExperimentLogViewModel.cs - annotation

Jason Maltzen
Fix a crash when importing a Practical Paint reactions.txt file with empty (not-recorded) entries.
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
7117d2e703c8
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
7117d2e703c8
7117d2e703c8
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
d7b40cfbe0f3
40eaee10ae56
d7b40cfbe0f3
d7b40cfbe0f3
d7b40cfbe0f3
d7b40cfbe0f3
d7b40cfbe0f3
40eaee10ae56
d7b40cfbe0f3
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
7117d2e703c8
7117d2e703c8
d7b40cfbe0f3
d7b40cfbe0f3
7117d2e703c8
d7b40cfbe0f3
7117d2e703c8
7117d2e703c8
7117d2e703c8
7117d2e703c8
7117d2e703c8
d7b40cfbe0f3
d7b40cfbe0f3
d7b40cfbe0f3
d7b40cfbe0f3
d7b40cfbe0f3
d7b40cfbe0f3
d7b40cfbe0f3
d7b40cfbe0f3
d7b40cfbe0f3
d7b40cfbe0f3
d7b40cfbe0f3
d7b40cfbe0f3
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
d7b40cfbe0f3
40eaee10ae56
40eaee10ae56
40eaee10ae56
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using ReactiveUI;
using DesertPaintCodex.Services;
using DesertPaintCodex.Models;
using DesertPaintCodex.Util;
using DynamicData.Binding;

namespace DesertPaintCodex.ViewModels
{
    public class ExperimentLogViewModel : ViewModelBase
    {
        public ObservableCollection<ReactionTest> RemainingTests { get; } = new();
        public ObservableCollection<ReactionTest> CompletedTests { get; } = new();

        private int _selectedList = 0;
        public int SelectedList { get => _selectedList; private set => this.RaiseAndSetIfChanged(ref _selectedList, value); }

        private int _selectedRemainingTest = 0;
        public int SelectedRemainingTest { get => _selectedRemainingTest; private set => this.RaiseAndSetIfChanged(ref _selectedRemainingTest, value); }
        
        private int _selectedCompletedTest = 0;
        public int SelectedCompletedTest { get => _selectedCompletedTest; private set => this.RaiseAndSetIfChanged(ref _selectedCompletedTest, value); }

        private ReactionTestViewModel _testView;
        public ReactionTestViewModel TestView { get => _testView; private set => this.RaiseAndSetIfChanged(ref _testView, value); }
        
        private readonly List<ObservableCollection<ReactionTest>> _testLists = new();

        public ExperimentLogViewModel()
        {
            PlayerProfile? profile = ProfileManager.CurrentProfile;
            Debug.Assert(profile != null);
            
            _testLists.Add(RemainingTests);
            _testLists.Add(CompletedTests);
            
            ReactionTestService.PopulateRemainingTests(RemainingTests);
            ReactionTestService.PopulateCompletedTests(CompletedTests);
            
            // If we have no remaining tests, switch to the completed list.
            _testView = new ReactionTestViewModel();
            if (RemainingTests.Count > 0)
            {
                SelectedList = 0;
                _testView.ReactionTest = RemainingTests[0];
            }
            else
            {
                SelectedList = 1;
                _testView.ReactionTest = CompletedTests[0];
            }

            this.WhenAnyPropertyChanged(nameof(SelectedList), nameof(SelectedRemainingTest), nameof(SelectedCompletedTest))
                .Subscribe(_ => _testView.ReactionTest = GetSelectedReactionTest());

            _testView.ReactionTest = GetSelectedReactionTest();

            TestView.SaveReaction.Subscribe(_ => OnSaveReaction());
            TestView.ClearReaction.Subscribe(_ => OnClearReaction());
            TestView.FinalizeTestResults.Subscribe(_ => OnReactionResults());
        }

        private ReactionTest GetSelectedReactionTest()
        {
            int itemIndex = (SelectedList == 0) ? SelectedRemainingTest : SelectedCompletedTest;
            if (itemIndex < 0) return Constants.StubReactionTest;
            var list = _testLists[SelectedList];
            return (itemIndex >= list.Count) ? Constants.StubReactionTest : list[itemIndex];
        }
        
        #region Command Handlers

        private void OnSaveReaction()
        {
            ReactionTest test = TestView.ReactionTest;
            int oldPos = RemainingTests.IndexOf(test);
            
            // Move test to Completed Tests.
            InsertTestIntoList(test, CompletedTests);
            RemainingTests.RemoveAt(oldPos);
            
            // Select next Remaining Test.
            if (RemainingTests.Count == 0) return;
            SelectedRemainingTest = (oldPos == RemainingTests.Count) ? RemainingTests.Count - 1 : oldPos;

            // If we have just inserted our first completed test, select it.
            if (CompletedTests.Count == 1)
            {
                 SelectedCompletedTest = 0;
            }
        }

        private void OnClearReaction()
        {
            int oldPos = 0;
            ReactionTest test = TestView.ReactionTest;
            if (RemainingTests.Contains(test))
            {
                SelectedRemainingTest = ResortTestInList(test, RemainingTests);
                return;
            }

            oldPos = CompletedTests.IndexOf(test);
            
            // Move test to Remaining Tests.
            InsertTestIntoList(test, RemainingTests);
            CompletedTests.RemoveAt(oldPos);
            
            // Select next Completed Test.
            if (CompletedTests.Count == 0) return;
            SelectedCompletedTest = (oldPos == CompletedTests.Count) ? CompletedTests.Count - 1 : oldPos;

            // If we have just inserted our first remaining test, select it.
            if (RemainingTests.Count == 1)
            {
                SelectedRemainingTest = 0;
            }
        }

        private void OnReactionResults()
        {
            int newPos = ResortTestInList(TestView.ReactionTest, RemainingTests);
            if (newPos != SelectedRemainingTest)
            {
                SelectedRemainingTest = newPos;
            }
        }
        
        #endregion

        private static int ResortTestInList(ReactionTest test, IList<ReactionTest> list)
        {
            int oldPos = list.IndexOf(test);

            if (((oldPos > 0) || (test.CompareTo(list[oldPos - 1]) > 0))
                && ((oldPos == list.Count - 1) || (test.CompareTo(list[oldPos + 1]) < 0))) return oldPos; // No need to move.

            list.RemoveAt(oldPos);
            return InsertTestIntoList(test, list);
        }
        
        private static int InsertTestIntoList(ReactionTest test, IList<ReactionTest> list)
        {
            int i;
            for (i = 0; i < list.Count; i++)
            {
                if (test.CompareTo(list[i]) < 0) break;
            }
            list.Insert(i, test);
            return i;
        }
    }
}