Codenew


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;

namespace TrainTicketBookingSystem
{
// User Class to store User related data
public class User
{
public int UserID { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public string Role { get; set; } // "Admin" or "Customer"
}

// Train Class to store Train related data
public class Train
{
    public int TrainNumber { get; set; }
    public string TrainName { get; set; }
    public string Origin { get; set; }
    public string Destination { get; set; }
    public DateTime DepartureTime { get; set; }
    public DateTime ArrivalTime { get; set; }
    public int TotalSeats { get; set; }
}

// Booking Class to store Booking related data
public class Booking
{
    public int BookingID { get; set; }
    public int CustomerID { get; set; }
    public int TrainNumber { get; set; }
    public DateTime BookingDate { get; set; }
    public List<int> SeatNumbers { get; set; } // Changed to List<int> to store multiple seats
    public decimal Fare { get; set; }
    public string BookingStatus { get; set; } // e.g., "Booked", "Cancelled"
}

// Passenger Class to store Passenger related data.
public class Passenger
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Gender { get; set; }
}

// UserRepository Class to manage User data
public class UserRepository
{
    private static List<User> users = new List<User>();
    private static int nextUserId = 1;

    public static void AddUser(User user)
    {
        user.UserID = nextUserId++;
        users.Add(user);
    }

    public static User GetUserByUsername(string username)
    {
        return users.FirstOrDefault(u => u.Username == username);
    }

    public static User GetUserById(int id)
    {
        return users.FirstOrDefault(u => u.UserID == id);
    }
}

// TrainRepository Class to manage Train data
public class TrainRepository
{
    private static List<Train> trains = new List<Train>();

    public static void AddTrain(Train train)
    {
        trains.Add(train);
    }

    public static Train GetTrainByNumber(int trainNumber)
    {
        return trains.FirstOrDefault(t => t.TrainNumber == trainNumber);
    }

    public static List<Train> SearchTrains(string origin, string destination, DateTime departureDate)
    {
        return trains.Where(t => t.Origin.Equals(origin, StringComparison.OrdinalIgnoreCase)
                         && t.Destination.Equals(destination, StringComparison.OrdinalIgnoreCase)
                         && t.DepartureTime.Date == departureDate.Date).ToList();
    }

    public static List<Train> GetAllTrains()
    {
        return trains;
    }

    public static void UpdateTrain(Train train)
    {
        Train existingTrain = GetTrainByNumber(train.TrainNumber);
        if (existingTrain != null)
        {
            existingTrain.TrainName = train.TrainName;
            existingTrain.Origin = train.Origin;
            existingTrain.Destination = train.Destination;
            existingTrain.DepartureTime = train.DepartureTime;
            existingTrain.ArrivalTime = train.ArrivalTime;
            existingTrain.TotalSeats = train.TotalSeats;
        }
    }
}

// BookingRepository Class to manage Booking data
public class BookingRepository
{
    private static List<Booking> bookings = new List<Booking>();
    private static int nextBookingId = 1;

    public static void AddBooking(Booking booking)
    {
        booking.BookingID = nextBookingId++;
        bookings.Add(booking);
    }

    public static Booking GetBookingById(int bookingId)
    {
        return bookings.FirstOrDefault(b => b.BookingID == bookingId);
    }

    public static List<Booking> GetBookingsByUserId(int userId)
    {
        return bookings.Where(b => b.CustomerID == userId).ToList();
    }

    public static void UpdateBooking(Booking booking)
    {
        Booking existingBooking = GetBookingById(booking.BookingID);
        if (existingBooking != null)
        {
            existingBooking.BookingStatus = booking.BookingStatus;
        }
    }

    public static List<Booking> GetBookingsByTrainNumberAndDate(int trainNumber, DateTime bookingDate)
    {
        return bookings.Where(b => b.TrainNumber == trainNumber && b.BookingDate.Date == bookingDate.Date).ToList();
    }
}

// Main Class containing the program's entry point and implementation of the user stories
public class TrainTicketBookingSystem
{
    private static User loggedInUser = null;
    private static List<Passenger> passengers = new List<Passenger>(); // List of passengers for current booking

    public static void Main(string[] args)
    {
        // Seed data for testing.  Added more train data for comprehensive testing.
        SeedData();

        // Ask for the user's role first
        Console.WriteLine("Welcome to the Train Ticket Booking System!");
        Console.WriteLine("Are you a:");
        Console.WriteLine("1. Admin");
        Console.WriteLine("2. New User");
        Console.WriteLine("3. Already Registered User");
        Console.Write("Enter your choice (1, 2, or 3): ");

        string roleChoice = Console.ReadLine();

        switch (roleChoice)
        {
            case "1":
                loggedInUser = new User { Role = "Admin" }; // Simulate admin login
                break;
            case "2":
                RegisterUser(); // Register the new user and log them in
                break;
            case "3":
                LoginUser();    // Log in the existing user
                break;
            default:
                Console.WriteLine("Invalid choice. Exiting application.");
                return;
        }
        if (loggedInUser == null && roleChoice == "3")
        {
            Console.WriteLine("Login failed. Exiting Application");
            return;
        }

        // Main application loop
        while (true)
        {
            Console.WriteLine("\nTrain Ticket Booking System");
            Console.WriteLine("1. View All Trains (Admin Only)");
            Console.WriteLine("2. Add Train (Admin Only)");
            Console.WriteLine("3. Update Train (Admin Only)");
            Console.WriteLine("4. Search Trains");
            Console.WriteLine("5. Book Ticket");
            Console.WriteLine("6. View Bookings");
            Console.WriteLine("7. Cancel Booking");
            Console.WriteLine("8. View Booking History"); // US_PROG_004
            Console.WriteLine("9. Sort Trains by Departure Time"); // US_PROG_005
            Console.WriteLine("10. Find Trains with Available Seats"); // US_PROG_006
            Console.WriteLine("11. Dynamically Allocate Seats"); // US_PROG_007
            Console.WriteLine("12. Exit");
            Console.Write("Enter your choice: ");

            string choice = Console.ReadLine();

            switch (choice)
            {
                case "1":
                    if (loggedInUser != null && loggedInUser.Role == "Admin")
                        ViewAllTrains();
                    else
                        Console.WriteLine("Unauthorized access.");
                    break;
                case "2":
                    if (loggedInUser != null && loggedInUser.Role == "Admin")
                        AddTrain();
                    else
                        Console.WriteLine("Unauthorized access.");
                    break;
                case "3":
                    if (loggedInUser != null && loggedInUser.Role == "Admin")
                        UpdateTrain();
                    else
                        Console.WriteLine("Unauthorized access.");
                    break;
                case "4":
                    SearchTrains();
                    break;
                case "5":
                    BookTicket();
                    break;
                case "6":
                    ViewBookings();
                    break;
                case "7":
                    CancelBooking();
                    break;
                case "8": // US_PROG_004
                    ViewBookingHistory();
                    break;
                case "9": // US_PROG_005
                    SortTrainsByDepartureTime();
                    break;
                case "10": // US_PROG_006
                    FindTrainsWithAvailableSeats();
                    break;
                case "11": // US_PROG_007
                     if (loggedInUser == null)
                    {
                        Console.WriteLine("Please log in to book a ticket.");
                        break;
                    }
                    Train selectedTrainForAllocation = null;
                    DateTime bookingDateForAllocation = DateTime.Now;
                    int numberOfPassengersForAllocation = 0;

                    Console.Write("Enter train number: ");
                    if (int.TryParse(Console.ReadLine(), out int trainNumberForAllocation))
                    {
                        selectedTrainForAllocation = TrainRepository.GetTrainByNumber(trainNumberForAllocation);
                        if (selectedTrainForAllocation == null)
                        {
                            Console.WriteLine("Train not found.");
                            break;
                        }
                    }
                    else
                    {
                        Console.WriteLine("Invalid Train Number");
                        break;
                    }

                    Console.Write("Enter Booking Date: ");
                    if (!DateTime.TryParse(Console.ReadLine(), out bookingDateForAllocation))
                    {
                        Console.WriteLine("Invalid date format.");
                        break;
                    }
                    Console.Write("Enter Number of Passengers (Max 10): ");
                    if (!int.TryParse(Console.ReadLine(), out numberOfPassengersForAllocation))
                    {
                        Console.WriteLine("Invalid number of passengers.");
                        break;
                    }
                    DynamicallyAllocateSeats(selectedTrainForAllocation, bookingDateForAllocation, numberOfPassengersForAllocation);
                    break;
                case "12":
                    Console.WriteLine("Exiting application.");
                    return;
                default:
                    Console.WriteLine("Invalid choice. Please try again.");
                    break;
            }
        }
    }

    // Method to seed initial data (users, trains)
    private static void SeedData()
    {
        // Add some initial users (1 admin, 2 customers)
        UserRepository.AddUser(new User { Username = "admin", Password = "password", Email = "[email protected]", Role = "Admin" });
        UserRepository.AddUser(new User { Username = "customer1", Password = "password1", Email = "[email protected]", Role = "Customer" });
        UserRepository.AddUser(new User { Username = "customer2", Password = "password2", Email = "[email protected]", Role = "Customer" });

        // Add some initial trains
        TrainRepository.AddTrain(new Train { TrainNumber = 101, TrainName = "ExpressA", Origin = "Mumbai", Destination = "Delhi", DepartureTime = DateTime.Parse("2024-03-10 10:00 AM"), ArrivalTime = DateTime.Parse("2024-03-11 10:00 AM"), TotalSeats = 100 });
        TrainRepository.AddTrain(new Train { TrainNumber = 102, TrainName = "SuperFastB", Origin = "Delhi", Destination = "Kolkata", DepartureTime = DateTime.Parse("2024-03-11 08:00 AM"), ArrivalTime = DateTime.Parse("2024-03-12 12:00 PM"), TotalSeats = 120 });
        TrainRepository.AddTrain(new Train { TrainNumber = 103, TrainName = "MailC", Origin = "Mumbai", Destination = "Goa", DepartureTime = DateTime.Parse("2024-03-12 06:00 AM"), ArrivalTime = DateTime.Parse("2024-03-12 03:00 PM"), TotalSeats = 80 });
        TrainRepository.AddTrain(new Train { TrainNumber = 104, TrainName = "LocalD", Origin = "Kolkata", Destination = "Mumbai", DepartureTime = DateTime.Parse("2024-03-13 09:00 AM"), ArrivalTime = DateTime.Parse("2024-03-14 11:00 AM"), TotalSeats = 150 });
        TrainRepository.AddTrain(new Train { TrainNumber = 105, TrainName = "Rajdhani", Origin = "Bangalore", Destination = "Delhi", DepartureTime = DateTime.Parse("2024-03-15 07:00 AM"), ArrivalTime = DateTime.Parse("2024-03-16 09:00 AM"), TotalSeats = 90 });
    }

    // Method to handle user registration (US001)
    private static void RegisterUser()
    {
        Console.Write("Enter username: ");
        string username = Console.ReadLine();

        // Check if username already exists
        if (UserRepository.GetUserByUsername(username) != null)
        {
            Console.WriteLine("Username already exists. Please choose a different username.");
            return;
        }

        Console.Write("Enter password: ");
        string password = Console.ReadLine();
        Console.Write("Enter email: ");
        string email = Console.ReadLine();

        User newUser = new User
        {
            Username = username,
            Password = password,
            Email = email,
            Role = "Customer" // Default role is customer
        };
        UserRepository.AddUser(newUser);
        Console.WriteLine("Registration successful. Please log in.");
        loggedInUser = newUser; // Log in the new user
    }

    // Method to handle user login (US002)
    private static void LoginUser()
    {
        Console.Write("Enter username: ");
        string username = Console.ReadLine();
        Console.Write("Enter password: ");
        string password = Console.ReadLine();

        User user = UserRepository.GetUserByUsername(username);
        if (user != null && user.Password == password)
        {
            loggedInUser = user;
            Console.WriteLine($"Login successful. Welcome, {loggedInUser.Username}!");
        }
        else
        {
            Console.WriteLine("Invalid username or password.");
            loggedInUser = null;
        }
    }

    // Method to display all trains (Admin Only)
    private static void ViewAllTrains()
    {
        Console.WriteLine("\nAll Trains:");
        List<Train> allTrains = TrainRepository.GetAllTrains();
        if (allTrains.Count == 0)
        {
            Console.WriteLine("No trains available.");
            return;
        }
        Console.WriteLine("--------------------------------------------------------------------------------------------------");
        Console.WriteLine("Train Number | Train Name       | Origin    | Destination | Departure Time        | Arrival Time          | Total Seats");
        Console.WriteLine("--------------------------------------------------------------------------------------------------");
        foreach (Train train in allTrains)
        {
            Console.WriteLine($"{train.TrainNumber,-13} | {train.TrainName,-16} | {train.Origin,-10} | {train.Destination,-12} | {train.DepartureTime,-24:f} | {train.ArrivalTime,-24:f} | {train.TotalSeats,-11}");
        }
        Console.WriteLine("--------------------------------------------------------------------------------------------------");
    }

    // Method to add a new train (Admin Only) (US003)
    private static void AddTrain()
    {
        Console.Write("Enter train number: ");
        if (!int.TryParse(Console.ReadLine(), out int trainNumber))
        {
            Console.WriteLine("Invalid train number.");
            return;
        }

        if (TrainRepository.GetTrainByNumber(trainNumber) != null)
        {
            Console.WriteLine("A train with this number already exists.");
            return;
        }

        Console.Write("Enter train name: ");
        string trainName = Console.ReadLine();
        Console.Write("Enter origin: ");
        string origin = Console.ReadLine();
        Console.Write("Enter destination: ");
        string destination = Console.ReadLine();
        Console.Write("Enter departure time (e.g., 2024-03-15 14:30): ");
        if (!DateTime.TryParse(Console.ReadLine(), out DateTime departureTime))
        {
            Console.WriteLine("Invalid date/time format.");
            return;
        }
        Console.Write("Enter arrival time (e.g., 2024-03-15 16:30): ");
        if (!DateTime.TryParse(Console.ReadLine(), out DateTime arrivalTime))
        {
            Console.WriteLine("Invalid date/time format.");
            return;
        }
        Console.Write("Enter total number of seats: ");
        if (!int.TryParse(Console.ReadLine(), out int totalSeats))
        {
            Console.WriteLine("Invalid number of seats.");
            return;
        }

        Train newTrain = new Train
        {
            TrainNumber = trainNumber,
            TrainName = trainName,
            Origin = origin,
            Destination = destination,
            DepartureTime = departureTime,
            ArrivalTime = arrivalTime,
            TotalSeats = totalSeats
        };
        TrainRepository.AddTrain(newTrain);
        Console.WriteLine("Train added successfully.");
    }

    // Method to update an existing train (Admin Only) (US003)
    private static void UpdateTrain()
    {
        Console.Write("Enter train number to update: ");
        if (!int.TryParse(Console.ReadLine(), out int trainNumberToUpdate))
        {
            Console.WriteLine("Invalid train number.");
            return;
        }

        Train trainToUpdate = TrainRepository.GetTrainByNumber(trainNumberToUpdate);
        if (trainToUpdate == null)
        {
            Console.WriteLine("Train not found.");
            return;
        }

        Console.Write($"Enter new train name (current: {trainToUpdate.TrainName}): ");
        string newTrainName = Console.ReadLine();
        if (string.IsNullOrEmpty(newTrainName))
            newTrainName = trainToUpdate.TrainName;

        Console.Write($"Enter new origin (current: {trainToUpdate.Origin}): ");
        string newOrigin = Console.ReadLine();
        if (string.IsNullOrEmpty(newOrigin))
            newOrigin = trainToUpdate.Origin;

        Console.Write($"Enter new destination (current: {trainToUpdate.Destination}): ");
        string newDestination = Console.ReadLine();
        if (string.IsNullOrEmpty(newDestination))
            newDestination = trainToUpdate.Destination;

        Console.Write($"Enter new departure time (e.g., 2024-03-15 14:30) (current: {trainToUpdate.DepartureTime:f}): ");
        string departureTimeStr = Console.ReadLine();
        DateTime newDepartureTime;
        if (string.IsNullOrEmpty(departureTimeStr) || !DateTime.TryParse(departureTimeStr, out newDepartureTime))
        {
            newDepartureTime = trainToUpdate.DepartureTime;
        }

        Console.Write($"Enter new arrival time (e.g., 2024-03-15 16:30) (current: {trainToUpdate.ArrivalTime:f}): ");
        string arrivalTimeStr = Console.ReadLine();
        DateTime newArrivalTime;
        if (string.IsNullOrEmpty(arrivalTimeStr) || !DateTime.TryParse(arrivalTimeStr, out newArrivalTime))
        {
            newArrivalTime = trainToUpdate.ArrivalTime;
        }


        Console.Write($"Enter new total number of seats (current: {trainToUpdate.TotalSeats}): ");
        string totalSeatsStr = Console.ReadLine();
        int newTotalSeats;
        if (string.IsNullOrEmpty(totalSeatsStr) || !int.TryParse(totalSeatsStr, out newTotalSeats))
        {
            newTotalSeats = trainToUpdate.TotalSeats;
        }

        Train updatedTrain = new Train
        {
            TrainNumber = trainToUpdate.TrainNumber,
            TrainName = newTrainName,
            Origin = newOrigin,
            Destination = newDestination,
            DepartureTime = newDepartureTime,
            ArrivalTime = newArrivalTime,
            TotalSeats = newTotalSeats
        };

        TrainRepository.UpdateTrain(updatedTrain);
        Console.WriteLine("Train updated successfully.");
    }

    // Method to search for trains (US004)
    private static void SearchTrains()
    {
        Console.Write("Enter origin: ");
        string origin = Console.ReadLine();
        Console.Write("Enter destination: ");
        string destination = Console.ReadLine();
        Console.Write("Enter departure date (e.g., 2024-03-15): ");
        if (!DateTime.TryParse(Console.ReadLine(), out DateTime departureDate))
        {
            Console.WriteLine("Invalid date format.");
            return;
        }

        List<Train> searchResults = TrainRepository.SearchTrains(origin, destination, departureDate);
        if (searchResults.Count == 0)
        {
            Console.WriteLine("No trains found for the given criteria.");
            return;
        }

        Console.WriteLine("\nSearch Results:");
        Console.WriteLine("-----------------------------------------------------------------------------------");
        Console.WriteLine("Train Number | Train Name       | Departure Time        | Arrival Time          | Origin    | Destination");
        Console.WriteLine("-----------------------------------------------------------------------------------");
        foreach (Train train in searchResults)
        {
            Console.WriteLine($"{train.TrainNumber,-13} | {train.TrainName,-16} | {train.DepartureTime,-24:f} | {train.ArrivalTime,-24:f} | {train.Origin,-10} | {train.Destination,-12}");
        }
        Console.WriteLine("-----------------------------------------------------------------------------------");

        // Allow user to view details of a specific train
        Console.Write("Enter train number to view details (or 0 to skip): ");
        if (!int.TryParse(Console.ReadLine(), out int selectedTrainNumber))
        {
            Console.WriteLine("Invalid train number.");
            return;
        }

        if (selectedTrainNumber > 0)
        {
            Train selectedTrain = TrainRepository.GetTrainByNumber(selectedTrainNumber);
            if (selectedTrain != null)
            {
                Console.WriteLine("\nTrain Details:");
                Console.WriteLine($"Train Number: {selectedTrain.TrainNumber}");
                Console.WriteLine($"Train Name: {selectedTrain.TrainName}");
                Console.WriteLine($"Origin: {selectedTrain.Origin}");
                Console.WriteLine($"Destination: {selectedTrain.Destination}");
                Console.WriteLine($"Departure Time: {selectedTrain.DepartureTime:f}");
                Console.WriteLine($"Arrival Time: {selectedTrain.ArrivalTime:f}");
                Console.WriteLine($"Total Seats: {selectedTrain.TotalSeats}");
            }
            else
            {
                Console.WriteLine("Invalid train number.");
            }
        }
    }

    // Method to book a ticket (US005)
    private static void BookTicket()
    {
        if (loggedInUser == null)
        {
            Console.WriteLine("Please log in to book a ticket.");
            return;
        }

        Console.Write("Enter train number: ");
        if (!int.TryParse(Console.ReadLine(), out int trainNumber))
        {
            Console.WriteLine("Invalid train number.");
            return;
        }

        Train train = TrainRepository.GetTrainByNumber(trainNumber);
        if (train == null)
        {
            Console.WriteLine("Train not found.");
            return;
        }

        Console.Write("Enter booking date (e.g., 2024-03-15): ");
        if (!DateTime.TryParse(Console.ReadLine(), out DateTime bookingDate))
        {
            Console.WriteLine("Invalid date format.");
            return;
        }
        if (bookingDate.Date < DateTime.Now.Date)
        {
            Console.WriteLine("Booking date cannot be in the past.");
            return;
        }

        //Check for available seats
        List<Booking> existingBookings = BookingRepository.GetBookingsByTrainNumberAndDate(trainNumber, bookingDate);
        int bookedSeats = existingBookings.Sum(b => b.SeatNumbers.Count);
        int availableSeats = train.TotalSeats - bookedSeats;

        if (availableSeats <= 0)
        {
            Console.WriteLine("No seats available on this train for the selected date.");
            return;
        }
        Console.Write("Enter number of passengers: ");
        if (!int.TryParse(Console.ReadLine(), out int numberOfPassengers))
        {
            Console.WriteLine("Invalid number of passengers.");
            return;
        }

        if (numberOfPassengers <= 0)
        {
            Console.WriteLine("Number of passengers must be greater than zero.");
            return;
        }

        if (numberOfPassengers > availableSeats)
        {
            Console.WriteLine($"Only {availableSeats} seats available. Please enter a lower number of passengers.");
            return;
        }
        passengers.Clear(); // Clear any previous passenger data
        // Get passenger details
        for (int i = 0; i < numberOfPassengers; i++)
        {
            Console.WriteLine($"\nPassenger {i + 1}:");
            Console.Write("Enter name: ");
            string name = Console.ReadLine();
            Console.Write("Enter age: ");
            if (!int.TryParse(Console.ReadLine(), out int age))
            {
                Console.WriteLine("Invalid age. Please enter a valid number.");
                return; // Exit the booking process
            }
            Console.Write("Enter gender: ");
            string gender = Console.ReadLine();

            passengers.Add(new Passenger { Name = name, Age = age, Gender = gender });
        }List<int> selectedSeatNumbers = new List<int>();
        // Seat selection
        Console.WriteLine($"Available Seats: {availableSeats}");
        Console.Write("Enter seat numbers (comma-separated, e.g., 1,2,3):");
        string seatNumbersInput = Console.ReadLine();

        if (string.IsNullOrEmpty(seatNumbersInput))
        {
            Console.WriteLine("No seat numbers provided.");
            return;
        }
        string[] seatNumbersArray = seatNumbersInput.Split(',');
        foreach (string seatNumberStr in seatNumbersArray)
        {
            if (int.TryParse(seatNumberStr.Trim(), out int seatNumber))
            {
                if (seatNumber > 0 && seatNumber <= train.TotalSeats) //Basic seat number validation
                {
                    selectedSeatNumbers.Add(seatNumber);
                }
                else
                {
                    Console.WriteLine($"Invalid seat number: {seatNumber}.  Seat numbers must be between 1 and {train.TotalSeats}.");
                    return;
                }
            }
            else
            {
                Console.WriteLine($"Invalid seat number format: {seatNumberStr}.");
                return;
            }
        }
        // Check for duplicate seats
        if (selectedSeatNumbers.Distinct().Count() != selectedSeatNumbers.Count)
        {
            Console.WriteLine("Duplicate seat numbers detected.  Please select unique seatnumbers.");
            return;
        }

        //Check if the seats are already booked
        foreach (int seatNumber in selectedSeatNumbers)
        {
            if (existingBookings.Any(b => b.SeatNumbers.Contains(seatNumber)))
            {
                Console.WriteLine($"Seat number {seatNumber} is already booked.");
                return;
            }
        }
        if (selectedSeatNumbers.Count != numberOfPassengers)
        {
            Console.WriteLine($"Number of seats selected ({selectedSeatNumbers.Count}) does not match the number of passengers ({numberOfPassengers}).");
            return;
        }

        decimal fare = selectedSeatNumbers.Count * 100; // Assume a fare of $100 per seat.  Can be made more complex.

        Booking newBooking = new Booking
        {
            CustomerID = loggedInUser.UserID,
            TrainNumber = trainNumber,
            BookingDate = bookingDate,
            SeatNumbers = selectedSeatNumbers,
            Fare = fare,
            BookingStatus = "Booked"
        };

        BookingRepository.AddBooking(newBooking);

        Console.WriteLine($"Booking successful! Your Booking ID is {newBooking.BookingID}.");
        Console.WriteLine("Passenger Details:");
        for (int i = 0; i < passengers.Count; i++)
        {
            Console.WriteLine($"- {passengers[i].Name}, Age: {passengers[i].Age}, Gender: {passengers[i].Gender}, Seat Number: {selectedSeatNumbers[i]}");
        }
        Console.WriteLine($"Total Fare: ${newBooking.Fare}");
    }

    // Method to view user's bookings (US007)
    private static void ViewBookings()
    {
        if (loggedInUser == null)
        {
            Console.WriteLine("Please log in to view your bookings.");
            return;
        }

        List<Booking> userBookings = BookingRepository.GetBookingsByUserId(loggedInUser.UserID);
        if (userBookings.Count == 0)
        {
            Console.WriteLine("You have no bookings.");
            return;
        }

        Console.WriteLine("\nYour Bookings:");
        Console.WriteLine("---------------------------------------------------------------------------------------------------");
        Console.WriteLine("Booking ID | Train Number | Booking Date    | Seat Numbers       | Fare    | Booking Status");
        Console.WriteLine("---------------------------------------------------------------------------------------------------");
        foreach (Booking booking in userBookings)
        {
            string seatNumbers = string.Join(",", booking.SeatNumbers); // Convert seat list to string
            Console.WriteLine($"{booking.BookingID,-11} | {booking.TrainNumber,-12} | {booking.BookingDate,-16:d} | {seatNumbers,-18} | {booking.Fare,-8} | {booking.BookingStatus,-14}");
        }
        Console.WriteLine("---------------------------------------------------------------------------------------------------");
    }

    // Method to cancel a booking (US006)
    private static void CancelBooking()
    {
        if (loggedInUser == null)
        {
            Console.WriteLine("Please log in to cancel a booking.");
            return;
        }

        Console.Write("Enter booking ID to cancel: ");
        if (!int.TryParse(Console.ReadLine(), out int bookingIdToCancel))
        {
            Console.WriteLine("Invalid booking ID.");
            return;
        }

        Booking bookingToCancel = BookingRepository.GetBookingById(bookingIdToCancel);
        if (bookingToCancel == null)
        {
            Console.WriteLine("Booking not found.");
            return;
        }

        if (bookingToCancel.CustomerID != loggedInUser.UserID)
        {
            Console.WriteLine("You are not authorized to cancel this booking.");
            return;
        }

        if (bookingToCancel.BookingDate.Date < DateTime.Now.Date)
        {
            Console.WriteLine("Cannot cancel booking.  The departure date has already passed.");
            return;
        }
        if (bookingToCancel.BookingStatus == "Cancelled")
        {
            Console.WriteLine("This booking has already been cancelled.");
            return;
        }

        Console.Write($"Are you sure you want to cancel booking ID {bookingIdToCancel}? (yes/no): ");
        string confirmation = Console.ReadLine().ToLower();
        if (confirmation == "yes")
        {
            bookingToCancel.BookingStatus = "Cancelled"; // Update the booking status
            BookingRepository.UpdateBooking(bookingToCancel);
            Console.WriteLine("Booking cancelled successfully.");
            //  Refund logic can be added here
        }
        else
        {
            Console.WriteLine("Booking cancellation aborted.");
        }
    }

    // Method to view booking history (US_PROG_004)
    private static void ViewBookingHistory()
    {
        if (loggedInUser == null)
        {
            Console.WriteLine("Please log in to view your booking history.");
            return;
        }

        Console.Write("Enter customer ID: ");
        if (!int.TryParse(Console.ReadLine(), out int customerId))
        {
            Console.WriteLine("Invalid customer ID.");
            return;
        }

        User customer = UserRepository.GetUserById(customerId);
        if (customer == null)
        {
            Console.WriteLine("Customer ID does not exist in the system.");
            return;
        }

        List<Booking> bookingHistory = BookingRepository.GetBookingsByUserId(customerId);
        if (bookingHistory.Count == 0)
        {
            Console.WriteLine("No booking history found for this customer.");
            return;
        }

        Console.WriteLine("\nBooking History:");
        Console.WriteLine("---------------------------------------------------------------------------------------------------");
        Console.WriteLine("Booking ID | Train Number | Booking Date    | Seat Numbers       | Fare    | Booking Status");
        Console.WriteLine("---------------------------------------------------------------------------------------------------");
        foreach (Booking booking in bookingHistory)
        {
            string seatNumbers = string.Join(",", booking.SeatNumbers);
            Console.WriteLine($"{booking.BookingID,-11} | {booking.TrainNumber,-12} | {booking.BookingDate,-16:d} | {seatNumbers,-18} | {booking.Fare,-8} | {booking.BookingStatus,-14}");
        }
        Console.WriteLine("---------------------------------------------------------------------------------------------------");
    }

    // Method to view trains sorted by departure time (US_PROG_005)
    private static void SortTrainsByDepartureTime()
    {
        Console.Write("Enter origin station: ");
        string origin = Console.ReadLine();
        Console.Write("Enter destination station: ");
        string destination = Console.ReadLine();

        // Basic input validation
        if (string.IsNullOrEmpty(origin) || string.IsNullOrEmpty(destination))
        {
            Console.WriteLine("Origin and Destination stations are required.");
            return;
        }

        List<Train> sortedTrains = TrainRepository.SearchTrains(origin, destination, DateTime.MinValue) // Pass DateTime.MinValue to get all
                                                             .OrderBy(t => t.DepartureTime)
                                                             .ToList();

        if (sortedTrains.Count == 0)
        {
            Console.WriteLine("No trains found for the given origin and destination.");
            return;
        }

        Console.WriteLine("\nTrains Sorted by Departure Time:");
        Console.WriteLine("---------------------------------------------------------------------------------------------------");
        Console.WriteLine("Train Number | Train Name       | Departure Time        | Arrival Time          | Origin    | Destination");
        Console.WriteLine("---------------------------------------------------------------------------------------------------");
        foreach (Train train in sortedTrains)
        {
            Console.WriteLine($"{train.TrainNumber,-13} | {train.TrainName,-16} | {train.DepartureTime,-24:f} | {train.ArrivalTime,-24:f} | {train.Origin,-10} | {train.Destination,-12}");
        }
        Console.WriteLine("---------------------------------------------------------------------------------------------------");
    }

    // Method to find trains with available seats (US_PROG_006)
    private static void FindTrainsWithAvailableSeats()
    {
        Console.Write("Enter origin station: ");
        string origin = Console.ReadLine();
        Console.Write("Enter destination station: ");
        string destination = Console.ReadLine();
        Console.Write("Enter number of tickets: ");
        if (!int.TryParse(Console.ReadLine(), out int numberOfTickets))
        {
            Console.WriteLine("Invalid number of tickets.");
            return;
        }

        // Basic input validation
        if (string.IsNullOrEmpty(origin) || string.IsNullOrEmpty(destination))
        {
            Console.WriteLine("Origin and Destination stations are required.");
            return;
        }

        if (numberOfTickets <= 0)
        {
            Console.WriteLine("Number of tickets must be greater than zero.");
            return;
        }

        List<Train> availableTrains = new List<Train>();
        List<Train> allTrains = TrainRepository.SearchTrains(origin, destination, DateTime.MinValue); // Get all trains first

        foreach (Train train in allTrains)
        {
            // Calculate available seats for each train
            List<Booking> existingBookings = BookingRepository.GetBookingsByTrainNumberAndDate(train.TrainNumber, DateTime.Now); // Consider bookings for today
            int bookedSeats = existingBookings.Sum(b => b.SeatNumbers.Count);
            int availableSeats = train.TotalSeats - bookedSeats;

            if (availableSeats >= numberOfTickets)
            {
                availableTrains.Add(train);
            }
        }

        if (availableTrains.Count == 0)
        {
            Console.WriteLine($"No trains found with {numberOfTickets} or more available seats for the given origin and destination.");
            return;
        }

        Console.WriteLine($"\nTrains with {numberOfTickets} or more Available Seats:");
        Console.WriteLine("---------------------------------------------------------------------------------------------------");
        Console.WriteLine("Train Number | Train Name       | Departure Time        | Arrival Time          | Origin    | Destination | Available Seats");
        Console.WriteLine("---------------------------------------------------------------------------------------------------");
        foreach (Train train in availableTrains)
        {
            List<Booking> existingBookings = BookingRepository.GetBookingsByTrainNumberAndDate(train.TrainNumber, DateTime.Now); // Consider bookings for today
            int bookedSeats = existingBookings.Sum(b => b.SeatNumbers.Count);
            int availableSeats = train.TotalSeats - bookedSeats;
            Console.WriteLine($"{train.TrainNumber,-13} | {train.TrainName,-16} | {train.DepartureTime,-24:f} | {train.ArrivalTime,-24:f} | {train.Origin,-10} | {train.Destination,-12} | {availableSeats,-15}");
        }
        Console.WriteLine("---------------------------------------------------------------------------------------------------");
    }

    // Method to dynamically allocate seats (US_PROG_007)
    private static void DynamicallyAllocateSeats(Train train, DateTime bookingDate, int numberOfPassengers)
    {
        if (train == null)
        {
            Console.WriteLine("Train not found.");
            return;
        }

        if (numberOfPassengers <= 0 || numberOfPassengers > 10)
        {
            Console.WriteLine("Number of passengers must be between 1 and 10.");
            return;
        }
        if (bookingDate.Date < DateTime.Now.Date)
        {
            Console.WriteLine("Booking date cannot be in the past.");
            return;
        }

        // Get existing bookings for the train and date to determine occupied seats
        List<Booking> existingBookings = BookingRepository.GetBookingsByTrainNumberAndDate(train.TrainNumber, bookingDate);
        List<int> occupiedSeats = new List<int>();
        foreach (var booking in existingBookings)
        {
            occupiedSeats.AddRange(booking.SeatNumbers);
        }

        // Get all available seat numbers
        List<int> allSeats = Enumerable.Range(1, train.TotalSeats).ToList();
        List<int> availableSeats = allSeats.Except(occupiedSeats).ToList();

        if (availableSeats.Count < numberOfPassengers)
        {
            Console.WriteLine("Not enough available seats to accommodate the requested number of passengers.");
            return;
        }

        List<int> allocatedSeats = new List<int>();
        // 1. Try to find adjacent seats
        for (int i = 0; i <= availableSeats.Count - numberOfPassengers; i++)
        {
            bool areAdjacent = true;
            for (int j = 0; j < numberOfPassengers; j++)
            {
                if (availableSeats[i + j] != availableSeats[i] + j)
                {
                    areAdjacent = false;
                    break;
                }
            }
            if (areAdjacent)
            {
                allocatedSeats = availableSeats.GetRange(i, numberOfPassengers);
                break;
            }
        }

        // 2. If adjacent seats not found, allocate closest available seats
        if (allocatedSeats.Count == 0)
        {
            availableSeats.Sort(); // Sort for closest
            allocatedSeats = availableSeats.Take(numberOfPassengers).ToList();
        }
        if (allocatedSeats.Count != numberOfPassengers)
        {
            Console.WriteLine("Error: Could not allocate the required number of seats.");
            return; // Or throw an exception
        }

        // Display the allocated seats to the user for confirmation
        Console.WriteLine("\nDynamically Allocated Seats:");
        Console.WriteLine(string.Join(", ", allocatedSeats));

        Console.Write("Do you want to confirm these seats? (yes/no): ");
        string confirmation = Console.ReadLine().ToLower();

        if (confirmation == "yes")
        {
            // Create a new booking with the allocated seats
            decimal fare = allocatedSeats.Count * 100;
            Booking newBooking = new Booking
            {
                CustomerID = loggedInUser.UserID, // Use the logged-in user's ID
                TrainNumber = train.TrainNumber,
                BookingDate = bookingDate,
                SeatNumbers = allocatedSeats,
                Fare = fare, // Calculate fare
                BookingStatus = "Booked"
            };

            BookingRepository.AddBooking(newBooking);
            Console.WriteLine($"Booking confirmed. Your Booking ID is {newBooking.BookingID}.");
            Console.WriteLine($"Total Fare: ${newBooking.Fare}");
        }
        else
        {
            Console.WriteLine("Seat allocation cancelled.");
        }
    }
}

}