Files
Common-VS2019/SacsStandardBase/Base/Procs/SaProcess_Base.cs
T
2021-07-08 20:51:25 +01:00

245 lines
7.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
namespace Sarand.Net.Standard.Base.Procs
{
//=======================================================================
public interface ISacsProcessNotifier
{
void OnStartProcess ();
void SetProgressInfo (List<String> progressInfo);
void OnEndProcess ();
}
//=======================================================================
public abstract class SaProcess_Base : SacsDisposable
{
//-------------------------------------------------------------------
// Process options and groups - for configuration of process to run.
// See Sarand.Win.Forms.Utility.SaForm_SelectOptions.
public class OptionData
{
public OptionData (TypeCodeDesc option)
{
Option = option;
}
public TypeCodeDesc Option { get; set; }
public String Notes { get; set; } = "";
public bool Selected { get; set; } = false;
}
public class GroupData
{
public GroupData (TypeCodeDesc optionGroup)
{
OptionGroup = optionGroup;
}
public TypeCodeDesc OptionGroup { get; set; }
public List<OptionData> Options { get; } = new List<OptionData>();
public bool ExclusiveOptions { get; set; } = false;
public bool Selected { get; set; } = false;
}
//-------------------------------------------------------------------
// Configuration.
public enum ProcessType
{
Unknown = 0,
ImportData,
ExportData,
ImportExportData,
Other,
}
public class Config
{
protected Config ()
{
}
/// <summary>Identifies the type of process.</summary>
public ProcessType ProcessType { get; set; } = ProcessType.Unknown;
/// <summary>Is the process to be run in 'Test' mode.</summary>
public bool TestProcess{ get; set; } = SacsSystem.DebugMode;
/// <summary>Process imports data.</summary>
public bool Import { get { return ProcessType == ProcessType.ImportData || ProcessType == ProcessType.ImportExportData; } }
/// <summary>Process exports data.</summary>
public bool Export { get { return ProcessType == ProcessType.ExportData || ProcessType == ProcessType.ImportExportData; } }
/// <summary>Can the process be interrupted?</summary>
public bool AllowInterruption { get; set; } = true;
/// <summary>Confirm when interruption is requested.</summary>
public bool ConfirmInterruption { get; set; } = true;
/// <summary>Automated processes must not display desktop coponents - popup messages etc.</summary>
public bool Automated { get; set; } = false;
}
//-------------------------------------------------------------------
// Data members.
private Config config;
private String processError = "";
//-------------------------------------------------------------------
// Construction.
protected SaProcess_Base (Config config)
{
this.config = config;
}
protected override void Dispose (bool disposing)
{
if (disposing)
{
}
}
//-------------------------------------------------------------------
// Properties.
public bool DebugMode { get { return SacsSystem.DebugMode; } }
public ISacsProcessNotifier ProcessNotifier { get; set; } = null;
public bool Processing { get; protected set; } = false;
public bool ProcessEnded { get; protected set; } = false;
public DateTime StartedAt { get; private set; } = DateTime.MinValue;
public DateTime FinishedAt { get; private set; } = DateTime.MinValue;
public int ElapsedSecs
{
get
{
if (DateUtil.IsValid(StartedAt))
return (int)((DateUtil.IsValid(FinishedAt) ? FinishedAt : DateTime.Now) - StartedAt).TotalSeconds;
return 0;
}
}
//-------------------------------------------------------------------
// Properties.
/// <summary>Process caption.</summary>
public abstract String ProcessDescription { get; }
/// <summary>Process comments - to be displayed with process selection.</summary>
public virtual List<String> ProcessComments { get { return new List<String>(); } }
/// <summary>Processing statistics.</summary>
public virtual List<StringPair> ProcessingStatistics { get { return new List<StringPair>(); } }
//-------------------------------------------------------------------
// Run process inline.
public bool RunProcess ()
{
String fn = GetType().Name+".RunProcess";
if (ProcessNotifier == null)
throw new NotSupportedException("Process Notifier must be specified");
// Prepare process.
bool runProcess = false;
Reset();
Processing = true;
StartedAt = DateTime.Now;
try
{
// Notify start of process and log/ignore exceptions.
ProcessNotifier.OnStartProcess();
}
catch (Exception exc)
{
SaLogger.Error(fn + " OnStartProcess: " + GetProcessError() + exc.GetStackEntries(6).Concat("", "\n\tat "), true);
}
try
{
// Run process.
OnProcessStarting();
runProcess = Run();
OnProcessEnding();
}
catch (Exception exc)
{
SetProcessError(exc.GetType().Name + ": " + exc.Message);
SaLogger.Error(fn + " " + GetProcessError() + exc.GetStackEntries(6).Concat("", "\n\tat "), true);
}
// Processing completed.
FinishedAt = DateTime.Now;
Processing = false;
ProcessEnded = true;
try
{
// Notify end of process and log/ignore exceptions.
ProcessNotifier.OnEndProcess();
}
catch (Exception exc)
{
SaLogger.Error(fn + " OnEndProcess: " + GetProcessError() + exc.GetStackEntries(6).Concat("", "\n\tat "), true);
}
return runProcess;
}
protected abstract bool Run ();
protected virtual void OnProcessStarting () { }
protected virtual void OnProcessEnding () { }
//-------------------------------------------------------------------
// Process control.
public bool OK
{
get
{
if (HasProcessError()) return false;
if (isInterrupted) return false;
return true;
}
}
private void Reset ()
{
ClearProcessError();
isInterrupted = false;
ProcessEnded = false;
StartedAt = DateTime.MinValue;
FinishedAt = DateTime.MinValue;
}
//-------------------------------------------------------------------
// Progress information.
protected void SetProgressInfo (String progressInfo)
{
SetProgressInfo(StringListUtil.CreateList(progressInfo));
}
protected void SetProgressInfo (List<String> progressInfo)
{
if (ProcessNotifier != null)
ProcessNotifier.SetProgressInfo(progressInfo);
}
//-------------------------------------------------------------------
// Error handling.
public bool HasProcessError () { return !StringUtil.IsEmpty(processError); }
public String GetProcessError () { return StringUtil.EmptyOnNull(processError); }
public void ClearProcessError () { processError = ""; }
/// <summary>Record the processing error - always returns false.</summary>
public bool SetProcessError (String error)
{
processError = StringUtil.EmptyOnNull(error);
return false;
}
//-------------------------------------------------------------------
// Interruption.
private bool isInterrupted = false;
public bool IsInterrupted
{
get { return isInterrupted; }
}
public bool Interrupt ()
{
if (!config.AllowInterruption)
{
SaLogger.Warn("SacsProcess.Interrupt() Interruptions not allowed in " + this.GetType().Name);
return false;
}
if (config.ConfirmInterruption && !IsInterruptionConfirmed()) return false;
isInterrupted = true;
return true;
}
protected virtual bool IsInterruptionConfirmed ()
{
return true;
}
//-------------------------------------------------------------------
}
//=======================================================================
}