using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using FSI.Lib.Tools.RoboSharp.Interfaces;
namespace FSI.Lib.Tools.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();
}
}