Files @ 40eaee10ae56
Branch filter:

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

Malkyne
First commit. New UI.
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
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
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
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
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(HypotheticalColor));
                NotifyPropertyChanged(nameof(CanScan));
            }
        }

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

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

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

        public bool HasResults => 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 PaintColor? HypotheticalColor => (IsAllCatalysts && (BufferReagent == null)) ? null : _recipe.BaseColor;

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

        
        #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();
                    }
                }
            }
            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);
            if (State == TestState.Saved)
            {
                profile.Save();
            }
            
            Reaction = null;
            BadReaction = null;
            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 (Requires3Way)
            {
                if (BufferReagent == null) return null;
                return ReactionScannerService.Calculate3WayReaction(ProfileManager.CurrentProfile, HypotheticalColor,
                    ObservedColor, BufferReagent, Reagent1, Reagent2);
            }
            return ReactionScannerService.CalculateReaction(HypotheticalColor, ObservedColor);
        }
        
        
        #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)
            };
        }
    }
}