using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using RoboSharp.Interfaces; namespace RoboSharp.Results { /// /// Object that evaluates the ExitCode reported after RoboCopy finishes executing. /// /// /// /// public class RoboCopyExitStatus { /// /// Initializes a new instance of the class. /// public RoboCopyExitStatus(int exitCodeValue) { ExitCodeValue = exitCodeValue; } /// ExitCode as reported by RoboCopy public int ExitCodeValue { get; protected set; } /// ExitCode reported by RoboCopy converted into the Enum public RoboCopyExitCodes ExitCode => (RoboCopyExitCodes)ExitCodeValue; /// public bool Successful => !WasCancelled && ExitCodeValue < 0x10; /// public bool HasWarnings => ExitCodeValue >= 0x4; /// public bool HasErrors => ExitCodeValue >= 0x10; /// public virtual bool WasCancelled => ExitCodeValue < 0x0; /// /// Returns a string that represents the current object. /// public override string ToString() { return $"ExitCode: {ExitCodeValue} ({ExitCode})"; } } /// /// Represents the combination of multiple Exit Statuses /// public sealed class RoboCopyCombinedExitStatus : RoboCopyExitStatus, IRoboCopyCombinedExitStatus { #region < Constructor > /// /// Initializes a new instance of the class. /// public RoboCopyCombinedExitStatus() : base(0) { } /// /// Initializes a new instance of the class. /// public RoboCopyCombinedExitStatus(int exitCodeValue) : base(exitCodeValue) { } /// /// Clone this into a new instance /// /// public RoboCopyCombinedExitStatus(RoboCopyCombinedExitStatus obj) :base((int)obj.ExitCode) { wascancelled = obj.wascancelled; noCopyNoError = obj.noCopyNoError; } #endregion #region < Fields and Event > //Private bools for the Combine methods private bool wascancelled; private bool noCopyNoError; private bool EnablePropertyChangeEvent = true; /// This event when the ExitStatus summary has changed public event PropertyChangedEventHandler PropertyChanged; #endregion #region < Public Properties > /// Overides /// public override bool WasCancelled => AnyWasCancelled; /// /// Atleast one objects combined into this result resulted in no errors and no files/directories copied. /// public bool AnyNoCopyNoError => noCopyNoError || ExitCodeValue == 0x0; /// /// Atleast one object combined into this result had been cancelled / exited prior to completion. /// public bool AnyWasCancelled => wascancelled || ExitCodeValue < 0x0; /// /// All jobs completed without errors or warnings. /// public bool AllSuccessful => !WasCancelled && (ExitCodeValue == 0x0 || ExitCodeValue == 0x1); /// /// All jobs completed without errors or warnings, but Extra Files/Folders were detected. /// public bool AllSuccessful_WithWarnings => !WasCancelled && Successful && ExitCodeValue > 0x1; #endregion #region < RaiseEvent Methods > #if !NET40 [MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)] #endif private object[] StoreCurrentValues() { return new object[10] { WasCancelled, AnyNoCopyNoError, AnyWasCancelled, AllSuccessful, AllSuccessful_WithWarnings, HasErrors, HasWarnings, Successful, ExitCode, ExitCodeValue }; } #if !NET40 [MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)] #endif private void CompareAndRaiseEvents(object[] OriginalValues) { object[] CurrentValues = StoreCurrentValues(); if (CurrentValues[0] != OriginalValues[0]) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("WasCancelled")); if (CurrentValues[1] != OriginalValues[1]) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("AnyNoCopyNoError")); if (CurrentValues[2] != OriginalValues[2]) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("AnyWasCancelled")); if (CurrentValues[3] != OriginalValues[3]) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("AllSuccessful")); if (CurrentValues[4] != OriginalValues[4]) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("AllSuccessful_WithWarnings")); if (CurrentValues[5] != OriginalValues[5]) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("HasErrors")); if (CurrentValues[6] != OriginalValues[6]) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("HasWarnings")); if (CurrentValues[7] != OriginalValues[7]) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Successful")); if (CurrentValues[8] != OriginalValues[8]) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ExitCode")); if (CurrentValues[9] != OriginalValues[9]) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ExitCodeValue")); } #endregion /// /// Combine the RoboCopyExitCodes of the supplied ExitStatus with this ExitStatus. /// /// If any were Cancelled, set the WasCancelled property to TRUE. Otherwise combine the exit codes. /// ExitStatus to combine with #if !NET40 [MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)] #endif public void CombineStatus(RoboCopyExitStatus status) { if (status == null) return; object[] OriginalValues = EnablePropertyChangeEvent ? StoreCurrentValues() : null; //Combine the status if (status.WasCancelled) { wascancelled = true; } else { if (status.ExitCode == 0x0) this.noCopyNoError = true; //0x0 is lost if any other values have been added, so this logs the state RoboCopyExitCodes code = this.ExitCode | status.ExitCode; this.ExitCodeValue = (int)code; } //Raise Property Change Events if (EnablePropertyChangeEvent) CompareAndRaiseEvents(OriginalValues); } internal void CombineStatus(RoboCopyExitStatus status, bool enablePropertyChangeEvent) { EnablePropertyChangeEvent = enablePropertyChangeEvent; CombineStatus(status); EnablePropertyChangeEvent = enablePropertyChangeEvent; } /// /// Combine all the RoboCopyExitStatuses together. /// /// Array or List of ExitStatuses to combine. public void CombineStatus(IEnumerable status) { foreach (RoboCopyExitStatus s in status) { EnablePropertyChangeEvent = s == status.Last(); CombineStatus(s); } } /// /// Combine all the RoboCopyExitStatuses together. /// /// Array or List of ExitStatuses to combine. /// new RoboCopyExitStatus object public static RoboCopyCombinedExitStatus CombineStatuses(IEnumerable statuses) { RoboCopyCombinedExitStatus ret = new RoboCopyCombinedExitStatus(0); ret.CombineStatus(statuses); return ret; } /// /// Reset the value of the object /// #if !NET40 [MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)] #endif public void Reset() { object[] OriginalValues = EnablePropertyChangeEvent ? StoreCurrentValues() : null; this.wascancelled = false; this.noCopyNoError = false; this.ExitCodeValue = 0; if (EnablePropertyChangeEvent) CompareAndRaiseEvents(OriginalValues); } /// /// Reset the value of the object /// internal void Reset(bool enablePropertyChangeEvent) { EnablePropertyChangeEvent = enablePropertyChangeEvent; Reset(); EnablePropertyChangeEvent = true; } /// public RoboCopyCombinedExitStatus Clone() => new RoboCopyCombinedExitStatus(this); object ICloneable.Clone() => Clone(); } }