auto.bus_razor/TicketOffice/Pages/Routes/Index.cshtml.cs

417 lines
12 KiB
C#

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using TicketOffice.Data;
using TicketOffice.Models;
using Route = TicketOffice.Models.Route;
namespace TicketOffice.Pages.Routes;
public class IndexModel : PageModel
{
// Error massage displaying when passenger's last name validation failed.
public string? PassengerLastNameValidationError;
// Error massage displaying when passenger's first name validation failed.
public string? PassengerFirstNameValidationError;
// Error massage displaying when passenger's place validation failed.
public string? PassengerPlaceValidationError;
private readonly TicketOfficeContext context;
public IndexModel(TicketOfficeContext context)
{
this.context = context;
}
// Route list representing search results.
[BindProperty]
public List<Route>? Routes { get; set; }
// Object representing ticket which user wants to buy.
[BindProperty]
public Ticket? Ticket { get; set; }
// Search condition: departure city.
[BindProperty(SupportsGet = true)]
public string? From { get; set; }
// Search condition: arrival city.
[BindProperty(SupportsGet = true)]
public string? To { get; set; }
// Search condition: departure date.
[BindProperty(SupportsGet = true)]
public DateTime? Date { get; set; } = DateTime.Today;
// Sort condition: determines in which order tickets will be displayed.
// in the search results table
[BindProperty(SupportsGet = true)]
public string? SortString { get; set; }
// Called when GET request is sent to the page. Retrieves routes based on
// search conditions and sorts them.
public ActionResult OnGet()
{
GetRoutes();
return Page();
}
// Called when POST request is sent to the page (when user tries to buy a
// ticket). Validates input, creates new ticket in the database and
// redirects to "Account" page, where all bought tickets are shown.
public ActionResult OnPost()
{
GetRoutes();
if (!PassengerNameValidation(Ticket!.PassengerLastName,
out PassengerLastNameValidationError) |
!PassengerNameValidation(Ticket.PassengerFirstName,
out PassengerFirstNameValidationError) |
!PassengerPlaceValidation(Ticket.PassengerPlace,
out PassengerPlaceValidationError))
{
return OnGet();
}
CopyDataToTicket();
RevertChangesToRouteCities();
Ticket.OderDate = DateTime.Now;
context.Ticket.Add(Ticket);
context.SaveChanges();
return RedirectToPage("/Auth/Account");
}
// Sorts routes by routes' number.
public void OnGetSortByNumber()
{
OnGet();
if (SortString == "increasingNumber")
{
Routes!.Sort((x, y) =>
Math.Clamp(x.Number - y.Number, -1, 1));
}
else
{
Routes!.Sort((x, y) =>
Math.Clamp(y.Number - x.Number, -1, 1));
}
}
// Sorts routes by routes' departure time .
public void OnGetSortByDeparture()
{
OnGet();
Routes!.Sort((x, y) =>
{
TimeSpan? totalDuration;
if (SortString == "increasingDeparture")
{
totalDuration = x.Cities.First().DepartureTime -
y.Cities.First().DepartureTime;
}
else
{
totalDuration = y.Cities.First().DepartureTime -
x.Cities.First().DepartureTime;
}
return
Math.Clamp((int) totalDuration!.Value.TotalMilliseconds, -1, 1);
});
}
// Sorts routes by routes' arrival time.
public void OnGetSortByArrival()
{
OnGet();
Routes!.Sort((x, y) =>
{
TimeSpan? totalDuration;
if (SortString == "increasingArrival")
{
totalDuration = x.Cities.Last().ArrivalTime -
y.Cities.Last().ArrivalTime;
}
else
{
totalDuration = y.Cities.Last().ArrivalTime -
x.Cities.Last().ArrivalTime;
}
return
Math.Clamp((int) totalDuration!.Value.TotalMilliseconds, -1, 1);
});
}
// Sorts routes by routes' duration.
public void OnGetSortByDuration()
{
OnGet();
Routes!.Sort((x, y) =>
{
TimeSpan? xDuration = x.Cities.Last().ArrivalTime -
x.Cities.First().DepartureTime;
TimeSpan? yDuration = y.Cities.Last().ArrivalTime -
y.Cities.First().DepartureTime;
TimeSpan? totalDuration;
if (SortString == "increasingDuration")
{
totalDuration = xDuration - yDuration;
}
else
{
totalDuration = yDuration - xDuration;
}
return
Math.Clamp((int) totalDuration!.Value.TotalMilliseconds, -1, 1);
});
}
// Returns remaining route's capacity depending on
// arrival and departure cities.
public int GetRemainingCapacity(Route route)
{
int remainingCapacity = route.Capacity;
foreach (var ticket in route.Tickets!)
{
List<DateTime?> intersection = GetCitiesDates(route.Cities.ToList())
.Intersect(GetCitiesDates(ticket.Cities.ToList()))
.ToList();
if (intersection.Count > 1)
{
remainingCapacity--;
}
}
return remainingCapacity;
}
// Returns true if place is available otherwise returns false.
public bool IsTakenPlace(Route route, int place)
{
foreach (var ticket in route.Tickets!.Where(t => t.PassengerPlace == place))
{
List<DateTime?> intersection = GetCitiesDates(route.Cities.ToList())
.Intersect(GetCitiesDates(ticket.Cities.ToList()))
.ToList();
if (intersection.Count > 1)
{
return true;
}
}
return false;
}
// Returns list of route cities' departure dates.
public List<DateTime?> GetCitiesDates(List<RouteCity> cities)
{
List<DateTime?> citiesDates = new List<DateTime?>();
foreach (var city in cities)
{
citiesDates.Add(city.DepartureTime);
}
return citiesDates;
}
// Overload of the method above. Returns list of ticket cities' departure dates.
public List<DateTime?> GetCitiesDates(List<TicketCity> cities)
{
List<DateTime?> citiesDates = new List<DateTime?>();
foreach (var city in cities)
{
citiesDates.Add(city.DepartureTime);
}
return citiesDates;
}
private void RetrieveAllRoutes()
{
Routes = context.Route
.Include(r => r.Cities)
.Include(r => r.Tickets)
.ToList();
// Add cities to tickets.
for (int i = 0; i < Routes.Count; i++)
{
for (int j = 0; j < Routes[i].Tickets!.Count; j++)
{
Routes[i].Tickets!.ToList()[j].Cities = context.TicketCity
.Where(tc => tc.Ticket == Routes[i].Tickets!.ToList()[j])
.ToList();
}
}
}
private void FilterRoutesByCities()
{
if (From == To)
{
Routes!.RemoveAll(_ => true);
return;
}
Routes!.RemoveAll(r =>
r.Cities.All(c => c.Name.ToLower() != From!.ToLower().Trim())
|| r.Cities.All(c => c.Name.ToLower() != To!.ToLower().Trim()));
if (Routes.Count == 0)
{
return;
}
RouteCity? fromCityFirst;
RouteCity? toCityFirst;
RouteCity? fromCityLast;
RouteCity? toCityLast;
foreach (var route in Routes!)
{
fromCityLast = route.Cities.LastOrDefault(c =>
c.Name.ToLower() == From!.ToLower().Trim());
toCityLast = route.Cities.LastOrDefault(c =>
c.Name.ToLower() == To!.ToLower().Trim());
if (fromCityLast == null || toCityLast == null)
{
continue;
}
if (fromCityLast.Id > toCityLast.Id)
{
fromCityFirst = route.Cities.First(c =>
c.Name.ToLower() == From!.ToLower().Trim());
toCityFirst = route.Cities.First(c =>
c.Name.ToLower() == To!.ToLower().Trim());
route.Cities = route.Cities
.SkipWhile(c => c != fromCityFirst)
.TakeWhile(c =>
route.Cities.ToList().IndexOf(c) !=
route.Cities.ToList().IndexOf(toCityFirst) + 1)
.ToList();
}
else
{
route.Cities = route.Cities
.SkipWhile(c => c != fromCityLast)
.TakeWhile(c =>
route.Cities.ToList().IndexOf(c) !=
route.Cities.ToList().IndexOf(toCityLast) + 1)
.ToList();
}
}
}
private void FilterRoutesByDate()
{
if (Date < DateTime.Today)
{
Routes!.RemoveAll(_ => true);
return;
}
Routes!.RemoveAll(r =>
r.Cities.First().DepartureTime!.Value.Date != Date?.Date);
}
private void GetRoutes()
{
if (string.IsNullOrWhiteSpace(From) || string.IsNullOrWhiteSpace(To) ||
Date == null)
{
return;
}
RetrieveAllRoutes();
FilterRoutesByCities();
FilterRoutesByDate();
}
private bool PassengerNameValidation(
string? name,
out string validationError)
{
if (String.IsNullOrEmpty(name))
{
validationError = "Поле має бути заповненим";
return false;
}
validationError = String.Empty;
return true;
}
private bool PassengerPlaceValidation(
int place,
out string validationError)
{
if (place == 0)
{
validationError = "Поле має бути заповненим";
return false;
}
if (IsTakenPlace(
Routes?.Where(r => r.Id == Ticket!.RouteId).ToList()[0]!,
Ticket!.PassengerPlace))
{
validationError = "Місце вже зайняте";
return false;
}
validationError = String.Empty;
return true;
}
private void CopyDataToTicket()
{
List<RouteCity> routeCities =
Routes!.Find(r => r.Id == Ticket!.RouteId)!.Cities.ToList();
Ticket!.Cities = new List<TicketCity>();
foreach (var city in routeCities)
{
Ticket.Cities.Add(new TicketCity
{
Name = city.Name,
DepartureTime = city.DepartureTime,
ArrivalTime = city.ArrivalTime,
CostFromPreviousCity = city.CostFromPreviousCity
});
}
}
private void RevertChangesToRouteCities()
{
context.ChangeTracker.Entries()
.Where(e =>
e.Metadata.Name == "TicketOffice.Models.RouteCity")
.ToList().ForEach(e => e.State = EntityState.Unchanged);
}
}