Files @ a321f999a1ea
Branch filter:

Location: ATITD-Tools/Desert-Paint-Codex/Models/ReactionTest.cs - annotation

Jason Maltzen
Fix a crash when trying to reorder the reaction list after recording the first reaction in the list.
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
f419334a476f
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
f419334a476f
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
f419334a476f
40eaee10ae56
40eaee10ae56
40eaee10ae56
f419334a476f
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
f419334a476f
f419334a476f
40eaee10ae56
f419334a476f
f419334a476f
f419334a476f
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
f419334a476f
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
f419334a476f
f419334a476f
f419334a476f
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
f419334a476f
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
d7b40cfbe0f3
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
f419334a476f
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
40eaee10ae56
f419334a476f
f419334a476f
f419334a476f
f419334a476f
f419334a476f
f419334a476f
f419334a476f
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
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using DesertPaintCodex.Services;
using JetBrains.Annotations;

namespace DesertPaintCodex.Models
{
    public class ReactionTest : INotifyPropertyChanged, IProgress<float>, IComparable<ReactionTest>
    {
        public enum TestState
        {
            Unset = -1,
            Untested,
            Scanning,
            LabNotFound,
            ClippedResult,
            GoodResult,
            Saved
        }

        public Reagent Reagent1 { get; }
        public Reagent Reagent2 { get; }

        private Reagent? _bufferReagent;
        public Reagent? BufferReagent
        {
            get => _bufferReagent;
            set
            {
                if (_bufferReagent == value) return;
                _bufferReagent = value;
                _recipe.Clear();
                if (_bufferReagent == null)
                {
                    _recipe.AddReagent(Reagent1.Name);
                    _recipe.AddReagent(Reagent2.Name);
                }
                else
                {
                    _recipe.AddReagent(_bufferReagent.Name);
                    _recipe.AddReagent(Reagent1.Name);
                    _recipe.AddReagent(Reagent2.Name);
                }
                NotifyPropertyChanged(nameof(BufferReagent));
                NotifyPropertyChanged(nameof(CanScan));
                UpdateHypotheticalColor();
            }
        }

        private ClipType _clipType;
        public ClipType Clipped {
            get => _clipType;
            set
            {
                _clipType = value;
                NotifyPropertyChanged(nameof(Clipped));
            }
        }

        public bool IsAllCatalysts { get; }

        private Reaction? _reaction;
        public Reaction? Reaction { get => _reaction; set { _reaction = value; NotifyPropertyChanged(nameof(Reaction)); } }

        private Reaction? _badReaction;
        public Reaction? BadReaction { get => _badReaction; set { _badReaction = value; NotifyPropertyChanged(nameof(BadReaction)); } }

        private int _scanProgress;
        public int ScanProgress { get => _scanProgress; set { _scanProgress = value; NotifyPropertyChanged(nameof(ScanProgress)); } }
        
        
        private TestState _state;

        public TestState State
        {
            get => _state;
            set
            {
                _state = value;
                NotifyPropertyChanged(nameof(State));
                NotifyPropertyChanged(nameof(Requires3Way));
                NotifyPropertyChanged(nameof(CanScan));
                NotifyPropertyChanged(nameof(IsScanning));
                NotifyPropertyChanged(nameof(HasResults));
                NotifyPropertyChanged(nameof(HasReaction));
                NotifyPropertyChanged(nameof(CanClear));
                NotifyPropertyChanged(nameof(CanSave));
                NotifyPropertyChanged(nameof(NoLab));
                NotifyPropertyChanged(nameof(CanPickBuffer));
            }
        }

        public bool Requires3Way =>
            (State == TestState.ClippedResult) || IsAllCatalysts;

        public bool CanScan => (State is TestState.Untested or TestState.LabNotFound) || ((State == TestState.ClippedResult) && (BufferReagent != null));
        
        public bool IsScanning => State == TestState.Scanning;

        public bool HasResults => (ObservedColor != null) && (State is TestState.ClippedResult or TestState.GoodResult or TestState.LabNotFound);

        public bool HasReaction => State is TestState.ClippedResult or TestState.GoodResult or TestState.Saved;
        
        public bool CanClear => State is TestState.ClippedResult or TestState.GoodResult or TestState.Saved;
        
        public bool CanSave => State == TestState.GoodResult;

        public bool NoLab => State == TestState.LabNotFound;

        public bool CanPickBuffer => (State == TestState.ClippedResult) || IsAllCatalysts;


        private PaintColor? _hypotheticalColor;
        public PaintColor? HypotheticalColor { get => _hypotheticalColor; set { _hypotheticalColor = value; NotifyPropertyChanged(nameof(HypotheticalColor)); } }

        private PaintColor? _observedColor;
        public PaintColor? ObservedColor { get => _observedColor; set { _observedColor = value; NotifyPropertyChanged(nameof(ObservedColor)); } }

        private readonly PaintRecipe _recipe = new();

        public bool IsStub { get; }


        public ReactionTest(Reagent reagent1, Reagent reagent2, Reaction? reaction, ClipType clipType, bool isStub = false)
        {
            Reagent1 = reagent1;
            Reagent2 = reagent2;
            IsAllCatalysts = reagent1.IsCatalyst && reagent2.IsCatalyst;
            Clipped = clipType;
            Reaction = reaction;
            State = (reaction != null) ? TestState.Saved :
                (clipType == ClipType.None) ? TestState.Untested : TestState.ClippedResult;
            _recipe.AddReagent(reagent1.Name);
            _recipe.AddReagent(reagent2.Name);
            IsStub = isStub;
            UpdateHypotheticalColor();
        }

        
        #region Actions
        public async Task StartScan()
        {
            Clipped = ClipType.None;
            ScanProgress = 0;
            Reaction = null;
            BadReaction = null;
            State = TestState.Scanning;
            bool foundLab = await ReactionScannerService.Instance.CaptureReactionAsync(this);
            if (foundLab)
            {
                ObservedColor = ReactionScannerService.Instance.RecordedColor;
                if (_observedColor != null)
                {
                    Clipped = _observedColor.Red switch
                        {
                            0   => ClipType.RedLow,
                            255 => ClipType.RedHigh,
                            _   => ClipType.None
                        }
                        | _observedColor.Green switch
                        {
                            0   => ClipType.GreenLow,
                            255 => ClipType.GreenHigh,
                            _   => ClipType.None
                        }
                        | _observedColor.Blue switch
                        {
                            0   => ClipType.BlueLow,
                            255 => ClipType.BlueHigh,
                            _   => ClipType.None
                        };

                    if (Clipped == ClipType.None)
                    {
                        State = TestState.GoodResult;
                        Reaction = CalculateReaction();
                    }
                    else
                    {
                        State = TestState.ClippedResult;
                        BadReaction = CalculateReaction();
                    }
                    
                    PlayerProfile? profile = ProfileManager.CurrentProfile;
                    profile?.SetPairClipStatus(Reagent1, Reagent2, Clipped);
                }
            }
            else
            {
                Debug.WriteLine("ERROR: Lab UI not found.");
                State = TestState.LabNotFound;
            }
        }

        public void CancelScan()
        {
            ReactionScannerService.Instance.CancelScan();
            State = TestState.Untested;
        }

        public void MarkInert()
        {
            Reaction = new Reaction(0, 0, 0);
            State = TestState.GoodResult;
        }

        public void ClearReaction()
        {
            PlayerProfile? profile = ProfileManager.CurrentProfile;
            if (profile == null) return;
            profile.Reactions.Remove(Reagent1, Reagent2);
            profile.SetPairClipStatus(Reagent1, Reagent2, ClipType.None);
            if (State == TestState.Saved)
            {
                profile.Save();
            }
            
            Reaction = null;
            BadReaction = null;
            Clipped = ClipType.None;
            State = TestState.Untested;
        }

        public void SaveReaction()
        {
            PlayerProfile? profile = ProfileManager.CurrentProfile;
            if (profile == null) return;
            profile.Reactions.Set(Reagent1, Reagent2, Reaction);
            profile.Save();
            State = TestState.Saved;
        }
        
        #endregion
        
        #region Internals

        private Reaction? CalculateReaction()
        {
            if (ProfileManager.CurrentProfile == null) return null;
            if (HypotheticalColor == null) return null;
            if (ObservedColor == null) return null;

            if (BufferReagent != null)
            {
                return ReactionScannerService.Calculate3WayReaction(ProfileManager.CurrentProfile, HypotheticalColor,
                    ObservedColor, BufferReagent, Reagent1, Reagent2);
            }
            return ReactionScannerService.CalculateReaction(HypotheticalColor, ObservedColor);
        }


        private void UpdateHypotheticalColor()
        {
            HypotheticalColor = null;
            HypotheticalColor = (IsAllCatalysts && (BufferReagent == null)) ? null : _recipe.BaseColor;
        }
        
        #endregion
        
        

        #region Interface Implementations
        
        public event PropertyChangedEventHandler? PropertyChanged;

        [NotifyPropertyChangedInvocator]
        private void NotifyPropertyChanged([CallerMemberName] string? propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        public void Report(float value)
        {
            ScanProgress = (int)Math.Round(value * 100);
        }
        
        #endregion

        public int CompareTo(ReactionTest? other)
        {
            if (other == null) return 1;
            
            if (Clipped == ClipType.None)
            {
                if (other.Clipped != ClipType.None) return -1;
            }
            else if (other.Clipped == ClipType.None) return 1;

            if (IsAllCatalysts)
            {
                if (!other.IsAllCatalysts) return 1;
            }
            else if (other.IsAllCatalysts) return -1;
            
            return string.CompareOrdinal(Reagent1.Name, other.Reagent1.Name) switch
            {
                < 0 => -1,
                > 0 => 1,
                _   => string.CompareOrdinal(Reagent2.Name, other.Reagent2.Name)
            };
        }
    }
}