using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TelegramBotBase.Args;
using TelegramBotBase.Base;
using TelegramBotBase.Form.Navigation;
using TelegramBotBase.Sessions;
using static TelegramBotBase.Base.Async;
namespace TelegramBotBase.Form
{
///
/// Base class for forms
///
public class FormBase : IDisposable
{
public NavigationController NavigationController { get; set; }
public DeviceSession Device { get; set; }
public MessageClient Client { get; set; }
///
/// has this formular already been disposed ?
///
public bool IsDisposed { get; set; } = false;
public List Controls { get; set; }
public EventHandlerList Events = new EventHandlerList();
private static object __evInit = new object();
private static object __evOpened = new object();
private static object __evClosed = new object();
public FormBase()
{
this.Controls = new List();
}
public FormBase(MessageClient Client) : this()
{
this.Client = Client;
}
public async Task OnInit(InitEventArgs e)
{
var handler = this.Events[__evInit]?.GetInvocationList().Cast>();
if (handler == null)
return;
foreach (var h in handler)
{
await Async.InvokeAllAsync(h, this, e);
}
}
/////
///// Will get called at the initialization (once per context)
/////
public event AsyncEventHandler Init
{
add
{
this.Events.AddHandler(__evInit, value);
}
remove
{
this.Events.RemoveHandler(__evInit, value);
}
}
public async Task OnOpened(EventArgs e)
{
var handler = this.Events[__evOpened]?.GetInvocationList().Cast>();
if (handler == null)
return;
foreach (var h in handler)
{
await Async.InvokeAllAsync(h, this, e);
}
}
///
/// Gets invoked if gets navigated to this form
///
///
public event AsyncEventHandler Opened
{
add
{
this.Events.AddHandler(__evOpened, value);
}
remove
{
this.Events.RemoveHandler(__evOpened, value);
}
}
public async Task OnClosed(EventArgs e)
{
var handler = this.Events[__evClosed]?.GetInvocationList().Cast>();
if (handler == null)
return;
foreach (var h in handler)
{
await Async.InvokeAllAsync(h, this, e);
}
}
///
/// Form has been closed (left)
///
///
public event AsyncEventHandler Closed
{
add
{
this.Events.AddHandler(__evClosed, value);
}
remove
{
this.Events.RemoveHandler(__evClosed, value);
}
}
///
/// Get invoked when a modal child from has been closed.
///
///
///
public virtual async Task ReturnFromModal(ModalDialog modal)
{
}
///
/// Pre to form close, cleanup all controls
///
///
public async Task CloseControls()
{
foreach (var b in this.Controls)
{
b.Cleanup().Wait();
}
}
public virtual async Task PreLoad(MessageResult message)
{
}
///
/// Gets invoked if a message was sent or an action triggered
///
///
///
public virtual async Task LoadControls(MessageResult message)
{
//Looking for the control by id, if not listened, raise event for all
if (message.RawData?.StartsWith("#c") ?? false)
{
var c = this.Controls.FirstOrDefault(a => a.ControlID == message.RawData.Split('_')[0]);
if (c != null)
{
await c.Load(message);
return;
}
}
foreach (var b in this.Controls)
{
if (!b.Enabled)
continue;
await b.Load(message);
}
}
///
/// Gets invoked if the form gets loaded and on every message belongs to this context
///
///
///
public virtual async Task Load(MessageResult message)
{
}
///
/// Gets invoked, when a messages has been edited.
///
///
///
public virtual async Task Edited(MessageResult message)
{
}
///
/// Gets invoked if the user clicked a button.
///
///
///
public virtual async Task ActionControls(MessageResult message)
{
//Looking for the control by id, if not listened, raise event for all
if (message.RawData.StartsWith("#c"))
{
var c = this.Controls.FirstOrDefault(a => a.ControlID == message.RawData.Split('_')[0]);
if (c != null)
{
await c.Action(message, message.RawData.Split('_')[1]);
return;
}
}
foreach (var b in this.Controls)
{
if (!b.Enabled)
continue;
await b.Action(message);
if (message.Handled)
return;
}
}
///
/// Gets invoked if the user has clicked a button.
///
///
///
public virtual async Task Action(MessageResult message)
{
}
///
/// Gets invoked if the user has sent some media (Photo, Audio, Video, Contact, Location, Document)
///
///
///
public virtual async Task SentData(DataResult message)
{
}
///
/// Gets invoked at the end of the cycle to "Render" text, images, buttons, etc...
///
///
///
public virtual async Task RenderControls(MessageResult message)
{
foreach (var b in this.Controls)
{
if (!b.Enabled)
continue;
await b.Render(message);
}
}
///
/// Gets invoked at the end of the cycle to "Render" text, images, buttons, etc...
///
///
///
public virtual async Task Render(MessageResult message)
{
}
///
/// Navigates to a new form
///
///
///
public virtual async Task NavigateTo(FormBase newForm, params object[] args)
{
DeviceSession ds = this.Device;
if (ds == null)
return;
ds.FormSwitched = true;
ds.PreviousForm = ds.ActiveForm;
ds.ActiveForm = newForm;
newForm.Client = this.Client;
newForm.Device = ds;
//Notify prior to close
foreach (var b in this.Controls)
{
if (!b.Enabled)
continue;
await b.Hidden(true);
}
this.CloseControls().Wait();
await this.OnClosed(new EventArgs());
await newForm.OnInit(new InitEventArgs(args));
await newForm.OnOpened(new EventArgs());
}
///
/// Opens this form modal, but don't closes the original ones
///
///
///
public virtual async Task OpenModal(ModalDialog newForm, params object[] args)
{
DeviceSession ds = this.Device;
if (ds == null)
return;
var parentForm = this;
ds.FormSwitched = true;
ds.PreviousForm = ds.ActiveForm;
ds.ActiveForm = newForm;
newForm.Client = parentForm.Client;
newForm.Device = ds;
newForm.ParentForm = parentForm;
newForm.Closed += async (s, en) =>
{
await CloseModal(newForm, parentForm);
};
foreach (var b in this.Controls)
{
if (!b.Enabled)
continue;
await b.Hidden(false);
}
await newForm.OnInit(new InitEventArgs(args));
await newForm.OnOpened(new EventArgs());
}
public async Task CloseModal(ModalDialog modalForm, FormBase oldForm)
{
DeviceSession ds = this.Device;
if (ds == null)
return;
if (modalForm == null)
throw new Exception("No modal form");
ds.FormSwitched = true;
ds.PreviousForm = ds.ActiveForm;
ds.ActiveForm = oldForm;
}
///
/// Adds a control to the formular and sets its ID and Device.
///
///
public void AddControl(ControlBase control)
{
//Duplicate check
if (this.Controls.Contains(control))
throw new ArgumentException("Control has been already added.");
control.ID = this.Controls.Count + 1;
control.Device = this.Device;
this.Controls.Add(control);
control.Init();
}
///
/// Removes control from the formular and runs a cleanup on it.
///
///
public void RemoveControl(ControlBase control)
{
if (!this.Controls.Contains(control))
return;
control.Cleanup().Wait();
this.Controls.Remove(control);
}
///
/// Removes all controls.
///
public void RemoveAllControls()
{
foreach(var c in this.Controls)
{
c.Cleanup().Wait();
this.Controls.Remove(c);
}
}
///
/// Cleanup
///
public void Dispose()
{
this.Client = null;
this.Device = null;
this.IsDisposed = true;
}
}
}