using InABox.Clients;
using InABox.Configuration;
using InABox.Core.Postable;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace InABox.Core
{
public interface IGlobalSettingsPosterEngine
{
IGlobalPosterSettings GetGlobalSettings();
void SaveGlobalSettings(IGlobalPosterSettings settings);
}
///
/// Marks an as having global settings, not specific to certain entities.
///
///
public interface IGlobalSettingsPosterEngine : IGlobalSettingsPosterEngine
where TPoster : IGlobalSettingsPoster
where TGlobalSettings : BaseObject, IGlobalPosterSettings, new()
{
new TGlobalSettings GetGlobalSettings() => PosterUtils.LoadGlobalPosterSettings();
void SaveGlobalSettings(TGlobalSettings settings) => PosterUtils.SaveGlobalPosterSettings(settings);
IGlobalPosterSettings IGlobalSettingsPosterEngine.GetGlobalSettings() => GetGlobalSettings();
void IGlobalSettingsPosterEngine.SaveGlobalSettings(IGlobalPosterSettings settings)
{
if(settings is TGlobalSettings globalSettings)
{
SaveGlobalSettings(globalSettings);
}
}
}
public interface IPosterEngine
where TPostable : Entity, IPostable, IRemotable, IPersistent, new()
{
IPostResult? Process(IDataModel model);
}
public interface IPosterEngine : IPosterEngine
where TPostable : Entity, IPostable, IRemotable, IPersistent, new()
where TPoster : IPoster
where TSettings : PosterSettings, new()
{
}
///
/// A base class for all . A concrete instance of this will be loaded by
/// ; a new instance is guaranteed to be created each time that method is called.
///
///
///
///
public abstract class PosterEngine : IPosterEngine
where TPostable : Entity, IPostable, IRemotable, IPersistent, new()
where TPoster : class, IPoster
where TSettings : PosterSettings, new()
{
protected TPoster Poster;
public PosterEngine()
{
Poster = CreatePoster();
}
private static readonly Type? PosterType = PosterUtils.GetPoster(typeof(TPoster));
protected virtual TPoster CreatePoster()
{
var poster = (Activator.CreateInstance(PosterType!) as TPoster)!;
poster.Settings = GetSettings();
if(this is IGlobalSettingsPosterEngine globalSettingsEngine && poster is IGlobalSettingsPoster globalSettingsPoster)
{
globalSettingsPoster.GlobalSettings = globalSettingsEngine.GetGlobalSettings();
}
return poster;
}
private TSettings? _settings;
protected TSettings GetSettings()
{
_settings ??= PosterUtils.LoadPosterSettings();
return _settings;
}
protected void SaveSettings(TSettings settings)
{
_settings = settings;
PosterUtils.SavePosterSettings(_settings);
}
///
/// Returns the , if is ;
/// otherwise, returns .
///
protected string? GetScript()
{
var settings = GetSettings();
return settings.ScriptEnabled ? settings.Script : null;
}
protected abstract IPostResult DoProcess(IDataModel model);
///
/// Process the before loading;
///
///
/// if the processing must be cancelled.
public abstract bool BeforePost(IDataModel model);
///
/// Prior to saving the entities, make any necessary changes to those entities.
/// This is only called if returned .
///
///
/// The result object returned by
public abstract void AfterPost(IDataModel model, IPostResult result);
private static void SetFailed(IList entities)
{
foreach (var post in entities)
{
post.PostedStatus = PostedStatus.PostFailed;
post.PostedNote = "Post failed.";
}
new Client().Save(entities, "Post failed by user.");
}
public IPostResult? Process(IDataModel model)
{
if (!BeforePost(model))
{
return null;
}
// Add posted flags; if the columns is null, then we don't need to worry, because it will be loaded.
model.GetColumns()?.Add(x => x.PostedStatus)
.Add(x => x.Posted)
.Add(x => x.PostedNote);
model.LoadModel();
var data = model.GetTable();
if (!data.Rows.Any())
{
throw new EmptyPostException();
}
if(data.Rows.Any(x => x.Get(x => x.PostedStatus) == PostedStatus.Posted))
{
throw new RepostedException();
}
try
{
var result = DoProcess(model);
AfterPost(model, result);
Client.Save(result.PostedEntities, "Posted by user.");
foreach (var (type, fragments) in result.Fragments)
{
Client.Create(type).Save(fragments.Cast(), "");
}
return result;
}
catch (PostCancelledException)
{
var entities = data.ToObjects().ToList();
SetFailed(entities);
throw;
}
catch (MissingSettingException)
{
throw;
}
catch (PostFailedMessageException)
{
throw;
}
catch(Exception e)
{
Logger.Send(LogType.Error, "", $"Post Failed: {CoreUtils.FormatException(e)}");
var entities = data.ToObjects().ToList();
SetFailed(entities);
throw;
}
}
}
public interface IPullerEngine
where TPostable : Entity, IPostable, IRemotable, IPersistent, new()
{
IPullResult? Pull();
}
public interface IPullerEngine : IPullerEngine
where TPostable : Entity, IPostable, IRemotable, IPersistent, new()
{
IPullResult DoPull();
IPullResult? IPullerEngine.Pull()
{
try
{
var result = DoPull();
return result;
}
catch (PullCancelledException)
{
throw;
}
catch (MissingSettingException)
{
throw;
}
catch (PullFailedMessageException)
{
throw;
}
catch(Exception e)
{
Logger.Send(LogType.Error, "", $"Post Failed: {CoreUtils.FormatException(e)}");
throw;
}
}
}
}