using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using InfoferScraper.Models.Status;
using InfoferScraper.Models.Train.JsonConverters;
namespace InfoferScraper.Models.Train {
#region Interfaces
public interface ITrainScrapeResult {
public string Rank { get; }
public string Number { get; }
///
/// Date in the DD.MM.YYYY format
/// This date is taken as-is from the result.
///
public string Date { get; }
public string Operator { get; }
public IReadOnlyList Groups { get; }
}
public interface ITrainGroup {
public ITrainRoute Route { get; }
public ITrainStatus? Status { get; }
public IReadOnlyList Stations { get; }
}
public interface ITrainRoute {
public string From { get; }
public string To { get; }
}
public interface ITrainStatus {
public int Delay { get; }
public string Station { get; }
public StatusKind State { get; }
}
public interface ITrainStopDescription {
public string Name { get; }
public int Km { get; }
///
/// The time the train waits in the station in seconds
///
public int? StoppingTime { get; }
public string? Platform { get; }
public ITrainStopArrDep? Arrival { get; }
public ITrainStopArrDep? Departure { get; }
public IReadOnlyList Notes { get; }
}
public interface ITrainStopNote {
public NoteKind Kind { get; }
}
public interface ITrainStopTrainNumberChangeNote : ITrainStopNote {
public string Rank { get; }
public string Number { get; }
}
public interface ITrainStopDepartsAsNote : ITrainStopNote {
public string Rank { get; }
public string Number { get; }
public DateTimeOffset DepartureDate { get; }
}
public interface ITrainStopDetachingWagonsNote : ITrainStopNote {
public string Station { get; }
}
public interface ITrainStopReceivingWagonsNote : ITrainStopNote {
public string Station { get; }
}
public interface ITrainStopArrDep {
public DateTimeOffset ScheduleTime { get; }
public IStatus? Status { get; }
}
#endregion
[JsonConverter(typeof(StatusKindConverter))]
public enum StatusKind {
Passing,
Arrival,
Departure,
}
[JsonConverter(typeof(NoteKindConverter))]
public enum NoteKind {
TrainNumberChange,
DetachingWagons,
ReceivingWagons,
DepartsAs,
}
#region Implementations
internal record TrainScrapeResult : ITrainScrapeResult {
private List ModifyableGroups { get; set; } = new();
public string Rank { get; set; } = "";
public string Number { get; set; } = "";
public string Date { get; set; } = "";
public string Operator { get; set; } = "";
public IReadOnlyList Groups => ModifyableGroups.AsReadOnly();
private void AddTrainGroup(ITrainGroup trainGroup) {
ModifyableGroups.Add(trainGroup);
}
internal void AddTrainGroup(Action configurator) {
TrainGroup newTrainGroup = new();
configurator(newTrainGroup);
AddTrainGroup(newTrainGroup);
}
}
internal record TrainGroup : ITrainGroup {
private List ModifyableStations { get; set; } = new();
public ITrainRoute Route { get; init; } = new TrainRoute();
public ITrainStatus? Status { get; private set; }
public IReadOnlyList Stations => ModifyableStations.AsReadOnly();
private void AddStopDescription(ITrainStopDescription stopDescription) {
ModifyableStations.Add(stopDescription);
}
internal void AddStopDescription(Action configurator) {
TrainStopDescription newStopDescription = new();
configurator(newStopDescription);
AddStopDescription(newStopDescription);
}
internal void ConfigureRoute(Action configurator) {
configurator((TrainRoute)Route);
}
internal void MakeStatus(Action configurator) {
TrainStatus newStatus = new();
configurator(newStatus);
Status = newStatus;
}
}
internal record TrainRoute : ITrainRoute {
public TrainRoute() {
From = "";
To = "";
}
public string From { get; set; }
public string To { get; set; }
}
internal record TrainStatus : ITrainStatus {
public int Delay { get; set; }
public string Station { get; set; } = "";
public StatusKind State { get; set; }
}
internal record TrainStopDescription : ITrainStopDescription {
private List ModifyableNotes { get; } = new();
public string Name { get; set; } = "";
public int Km { get; set; }
public int? StoppingTime { get; set; }
public string? Platform { get; set; }
public ITrainStopArrDep? Arrival { get; private set; }
public ITrainStopArrDep? Departure { get; private set; }
public IReadOnlyList Notes => ModifyableNotes.AsReadOnly();
internal void MakeArrival(Action configurator) {
TrainStopArrDep newArrival = new();
configurator(newArrival);
Arrival = newArrival;
}
internal void MakeDeparture(Action configurator) {
TrainStopArrDep newDeparture = new();
configurator(newDeparture);
Departure = newDeparture;
}
class DepartsAsNote : ITrainStopDepartsAsNote {
public NoteKind Kind => NoteKind.DepartsAs;
public string Rank { get; set; } = "";
public string Number { get; set; } = "";
public DateTimeOffset DepartureDate { get; set; }
}
class TrainNumberChangeNote : ITrainStopTrainNumberChangeNote {
public NoteKind Kind => NoteKind.TrainNumberChange;
public string Rank { get; set; } = "";
public string Number { get; set; } = "";
}
class ReceivingWagonsNote : ITrainStopReceivingWagonsNote {
public NoteKind Kind => NoteKind.ReceivingWagons;
public string Station { get; set; } = "";
}
class DetachingWagonsNote : ITrainStopReceivingWagonsNote {
public NoteKind Kind => NoteKind.DetachingWagons;
public string Station { get; set; } = "";
}
internal void AddDepartsAsNote(string rank, string number, DateTimeOffset departureDate) {
ModifyableNotes.Add(new DepartsAsNote { Rank = rank, Number = number, DepartureDate = departureDate });
}
internal void AddTrainNumberChangeNote(string rank, string number) {
ModifyableNotes.Add(new TrainNumberChangeNote { Rank = rank, Number = number });
}
internal void AddReceivingWagonsNote(string station) {
ModifyableNotes.Add(new ReceivingWagonsNote { Station = station });
}
internal void AddDetachingWagonsNote(string station) {
ModifyableNotes.Add(new DetachingWagonsNote { Station = station });
}
}
public record TrainStopArrDep : ITrainStopArrDep {
public DateTimeOffset ScheduleTime { get; set; }
public IStatus? Status { get; private set; }
internal void MakeStatus(Action configurator) {
Status.Status newStatus = new();
configurator(newStatus);
Status = newStatus;
}
}
#endregion
#region JSON Converters
namespace JsonConverters {
internal class StatusKindConverter : JsonConverterFactory {
public override bool CanConvert(Type typeToConvert) {
return typeToConvert == typeof(StatusKind);
}
public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) {
return new Converter();
}
private class Converter : JsonConverter {
public override StatusKind Read(
ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options
) {
return reader.GetString() switch {
"arrival" => StatusKind.Arrival,
"departure" => StatusKind.Departure,
"passing" => StatusKind.Passing,
_ => throw new NotImplementedException()
};
}
public override void Write(Utf8JsonWriter writer, StatusKind value, JsonSerializerOptions options) {
writer.WriteStringValue(value switch {
StatusKind.Passing => "passing",
StatusKind.Arrival => "arrival",
StatusKind.Departure => "departure",
_ => throw new NotImplementedException()
});
}
}
}
internal class NoteKindConverter : JsonConverterFactory {
public override bool CanConvert(Type typeToConvert) {
return typeToConvert == typeof(NoteKind);
}
public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) {
return new Converter();
}
private class Converter : JsonConverter {
public override NoteKind Read(
ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options
) {
return reader.GetString() switch {
"departsAs" => NoteKind.DepartsAs,
"trainNumberChange" => NoteKind.TrainNumberChange,
"receivingWagons" => NoteKind.ReceivingWagons,
"detachingWagons" => NoteKind.DetachingWagons,
_ => throw new NotImplementedException()
};
}
public override void Write(Utf8JsonWriter writer, NoteKind value, JsonSerializerOptions options) {
writer.WriteStringValue(value switch {
NoteKind.DepartsAs => "departsAs",
NoteKind.TrainNumberChange => "trainNumberChange",
NoteKind.DetachingWagons => "detachingWagons",
NoteKind.ReceivingWagons => "receivingWagons",
_ => throw new NotImplementedException()
});
}
}
}
}
#endregion
}