using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using MyInfoMate.Vr.Net;
using UnityEngine;
namespace MyInfoMate.Vr.Menu
{
///
/// Remplit une à partir d'une section — item E8 du
/// lot XR-4. C'est ici, et nulle part ailleurs, que vit ce qui distingue un Slider
/// d'une Map ou d'un Event.
///
/// Trois types sur les quatre retenus au §8. Le quatrième, la Video 360, attend
/// la ressource 360° côté backend. Le Parcours est volontairement rendu comme une Map :
/// « chaque étape = un lieu autour de soi » demande de la 3D, donc `SectionScene3D`.
///
public static class SectionPages
{
/// Les types qu'on sait ouvrir aujourd'hui.
public static bool CanRender(ConfigurationExport.SectionType type) =>
type == ConfigurationExport.SectionType.Slider
|| type == ConfigurationExport.SectionType.Map
|| type == ConfigurationExport.SectionType.Parcours
|| type == ConfigurationExport.SectionType.Event;
public static async Task FillAsync(PagedView view,
ConfigurationExport.SectionSummary section,
ApiClient client,
string language)
{
switch (section.Type)
{
case ConfigurationExport.SectionType.Slider:
await FillSlider(view, section, client, language);
break;
case ConfigurationExport.SectionType.Map:
case ConfigurationExport.SectionType.Parcours:
await FillMap(view, section, client, language);
break;
case ConfigurationExport.SectionType.Event:
FillEvent(view, section, language);
break;
}
if (view != null && view.PageCount == 0)
view.ShowEmpty("Ce contenu est vide.");
}
static async Task FillSlider(PagedView view,
ConfigurationExport.SectionSummary section,
ApiClient client,
string language)
{
foreach (var content in section.OrderedContents())
{
var texture = await LoadImage(client, content.Resource?.Url);
if (view == null) return;
if (texture == null) continue;
view.AddPage(new PagedView.Page
{
Heading = ConfigurationExport.Translate(content.Title, language) ?? "",
Body = ConfigurationExport.Translate(content.Description, language),
Image = texture
});
}
}
///
/// Une Map devient une liste de points d'intérêt, un par page.
///
/// ⚠️ Ce n'est pas la Map que le plan promet. Sa valeur en VR, c'est « le plan posé
/// devant soi comme une maquette » — et ça demande un modèle 3D, donc
/// `SectionScene3D` (§9). Une carte Google affichée sur un panneau flottant serait
/// moins bonne qu'un téléphone : autant montrer les lieux eux-mêmes, avec
/// leur photo et leurs horaires, ce que le `GeoPoint` porte déjà.
///
static async Task FillMap(PagedView view,
ConfigurationExport.SectionSummary section,
ApiClient client,
string language)
{
foreach (var point in section.Points)
{
var texture = await LoadImage(client, point.ImageUrl);
if (view == null) return;
var parts = new List();
var description = ConfigurationExport.Translate(point.Description, language);
if (!string.IsNullOrEmpty(description)) parts.Add(description);
var schedules = ConfigurationExport.Translate(point.Schedules, language);
if (!string.IsNullOrEmpty(schedules)) parts.Add(schedules);
view.AddPage(new PagedView.Page
{
Heading = ConfigurationExport.Translate(point.Title, language) ?? "",
Body = string.Join("\n", parts),
Image = texture
});
}
}
///
/// Un Event devient le programme, une page par bloc.
///
/// « Ce qui se passe aujourd'hui » est l'usage visé (§8) : un casque en
/// écran d'attente dans un office de tourisme. On ne montre donc que la journée en
/// cours — et seulement s'il s'y passe quelque chose : un programme vide le jour
/// même vaut mieux rempli par les dates suivantes que pas rempli du tout.
///
static void FillEvent(PagedView view,
ConfigurationExport.SectionSummary section,
string language)
{
var blocks = new List(section.Programme);
blocks.Sort((a, b) => Nullable.Compare(a.StartTime, b.StartTime));
var today = new List();
var upcoming = new List();
foreach (var block in blocks)
{
if (block.StartTime == null) continue;
var start = block.StartTime.Value.ToLocalTime();
if (start.Date == DateTime.Now.Date) today.Add(block);
else if (start > DateTime.Now) upcoming.Add(block);
}
var shown = today.Count > 0 ? today : upcoming;
foreach (var block in shown)
{
var start = block.StartTime?.ToLocalTime();
var end = block.EndTime?.ToLocalTime();
var when = start == null ? "" :
today.Count > 0
? (end == null ? $"{start:HH:mm}" : $"{start:HH:mm} – {end:HH:mm}")
: $"{start:dd/MM} · {start:HH:mm}";
var description = ConfigurationExport.Translate(block.Description, language);
view.AddPage(new PagedView.Page
{
Heading = ConfigurationExport.Translate(block.Title, language) ?? "",
Body = string.IsNullOrEmpty(description) ? when : $"{when}\n{description}"
});
}
if (view.PageCount == 0)
view.ShowEmpty("Rien au programme aujourd'hui.");
}
static async Task LoadImage(ApiClient client, string url)
{
if (string.IsNullOrEmpty(url)) return null;
var path = await ContentCache.MediaPathAsync(client, url);
if (path == null) return null;
var texture = new Texture2D(2, 2);
return texture.LoadImage(File.ReadAllBytes(path)) ? texture : null;
}
}
}