using Bridge.Html5;
using System;
using System.Collections.Generic;
namespace FrontendRouting
{
public static class FeRoutingManager
{
public static event EventHandler Navigated;
private static readonly Dictionary Routes = new Dictionary();
private static FeRoutingView _currentView;
private static string _basePath;
private static FeRoutingView _pageNoFoundView = new DefaultPageNoFoundView();
private static Node _parentNode = Window.Document.Body;
public static FeRoutingView PageNoFoundView
{
get => _pageNoFoundView;
set => _pageNoFoundView = value ?? throw new ArgumentNullException(nameof(value));
}
public static Node ParentNode
{
get => _parentNode;
set
{
_currentView?.Leave();
_parentNode = value ?? throw new ArgumentNullException(nameof(value));
_currentView?.Enter(_parentNode);
}
}
public static void Register(string path, FeRoutingView view)
{
if (false == path.StartsWith("/")) throw new ArgumentException($"{nameof(path)} must starts with /", nameof(path));
if (Routes.ContainsKey(path)) throw new ArgumentException($"Route path `{path}' already registed", nameof(path));
Routes.Add(path, view);
}
public static void UnRegister(string path)
{
Routes.Remove(path);
}
public static void Run(string basePath = "/")
{
if (null != _basePath) throw new InvalidOperationException("Already running");
if (false == basePath.StartsWith("/")) throw new ArgumentException($"{nameof(basePath)} must starts with /", nameof(basePath));
_basePath = basePath;
Go(null);
Window.AddEventListener(EventType.PopState, Window_PopState);
}
private static void Window_PopState(Event arg)
{
if (Go(null)) return;
arg.PreventDefault();
Window.History.Go(1);
}
public static bool Go(string path, bool replace = false)
{
if (null != _currentView) return _currentView.BeforeLeave(() => GoInternal(path, replace));
return GoInternal(path, replace);
}
private static bool GoInternal(string path, bool replace)
{
if (null != path)
{
if (replace) Window.History.ReplaceState(null, null, path);
else Window.History.PushState(null, null, path);
}
var routeKey = Window.Location.PathName;
if (routeKey.StartsWith(_basePath)) routeKey = routeKey.Substring(_basePath.Length - 1);
var targetView = Routes.TryGetValue(routeKey, out var controller)
? controller
: PageNoFoundView;
if (targetView.BeforeEnter(_currentView))
{
_currentView?.Leave();
_currentView = targetView;
_currentView.Enter(_parentNode);
OnNavigated();
return true;
}
return false;
}
private static void OnNavigated()
{
Navigated?.Invoke(null, EventArgs.Empty);
}
}
}