using System; using System.Collections.Generic; using System.Linq; using DryIoc; namespace Artemis.UI.Shared.Routing; internal class RouteResolution { private RouteResolution(string path) { Path = path; } public string Path { get; } public bool Success { get; private set; } public Type? ViewModel { get; private set; } public object[]? Parameters { get; private set; } public RouteResolution? Child { get; private set; } public static RouteResolution Resolve(IRouterRegistration registration, string path) { List segments = path.Split('/').ToList(); if (registration.Route.Segments.Count > segments.Count) return AsFailure(path); // Ensure self is a match List parameters = new(); int currentSegment = 0; foreach (RouteSegment routeSegment in registration.Route.Segments) { string segment = segments[currentSegment]; if (!routeSegment.IsMatch(segment)) return AsFailure(path); object? parameter = routeSegment.GetParameter(segment); if (parameter != null) parameters.Add(parameter); currentSegment++; } if (currentSegment == segments.Count) return AsSuccess(registration.ViewModel, path, parameters.ToArray()); // If segments remain, a child should match it string childPath = string.Join('/', segments.Skip(currentSegment)); foreach (IRouterRegistration routerRegistration in registration.Children) { RouteResolution result = Resolve(routerRegistration, childPath); if (result.Success) return AsSuccess(registration.ViewModel, path, parameters.ToArray(), result); } return AsFailure(path); } public static RouteResolution AsFailure(string path) { return new RouteResolution(path); } public static RouteResolution AsSuccess(Type viewModel, string path, object[] parameters, RouteResolution? child = null) { if (child != null && !child.Success) throw new ArtemisRoutingException("Cannot create a success route resolution with a failed child"); return new RouteResolution(path) { Success = true, ViewModel = viewModel, Parameters = parameters, Child = child }; } public object GetViewModel(IContainer container) { if (ViewModel == null) throw new ArtemisRoutingException("Cannot get a view model of a non-success route resolution"); object? viewModel = container.Resolve(ViewModel); if (viewModel == null) throw new ArtemisRoutingException($"Could not resolve view model of type {ViewModel}"); return viewModel; } public T GetViewModel(IContainer container) { if (ViewModel == null) throw new ArtemisRoutingException("Cannot get a view model of a non-success route resolution"); object? viewModel = container.Resolve(ViewModel); if (viewModel == null) throw new ArtemisRoutingException($"Could not resolve view model of type {ViewModel}"); if (viewModel is not T typedViewModel) throw new ArtemisRoutingException($"View model of type {ViewModel} is does mot implement {typeof(T)}."); return typedViewModel; } public object[] GetAllParameters() { List result = new(); if (Parameters != null) result.AddRange(Parameters); object[]? childParameters = Child?.GetAllParameters(); if (childParameters != null) result.AddRange(childParameters); return result.ToArray(); } }