/// <summary> /// Initializes a new instance of the <see cref="BasicTicketService"> class. /// </summary> /// <param name="venue">The venue.</param> /// <param name="maxHoldDuration">The maximum duration for which seat holds are valid.</param> /// <param name="reservationCodeLength">The length of the reservation codes. Defaults to 8.</param> /// <param name="getNow">A function which can mock the current DateTime. Defaults to DateTime.UtcNow; should only be set for unit tests.</param> public BasicTicketService(BasicVenue venue, double maxHoldDuration, int reservationCodeLength = 8, Func <bool, DateTime> getNow = null) { this.Venue = venue; this.firstRowWithAvailableSeats = venue.Rows[0]; this.maxHoldDuration = maxHoldDuration; this.reservationCodeLength = reservationCodeLength; this.getNow = getNow ?? (x => DateTime.UtcNow); }
/// <summary> /// Updates the value of the closest row to the front with available seats. /// </summary> private void UpdateClosestRowWithAvailableSeats() { BasicRow row = this.firstRowWithAvailableSeats; while (row.NumAvailableSeats == 0 && row.RowNumber < this.Venue.NumRows - 1) { row = this.Venue.Rows[row.RowNumber + 1]; } this.firstRowWithAvailableSeats = row; }
/// <summary> /// Makes the specified seat available. /// </summary> /// <param name="seat">The seat.</param> private void MakeSeatAvailable(Seat seat) { seat.Available = true; BasicRow row = this.Venue.Rows[seat.RowNumber]; if (seat.RowNumber < this.firstRowWithAvailableSeats.RowNumber) { this.firstRowWithAvailableSeats = row; } row.NumAvailableSeats++; this.Venue.TotalAvailableSeats++; }
/// <summary> /// Holds the first available seat in the specified row. /// </summary> /// <param name="row"></param> /// <returns></returns> private Seat HoldFirstAvailableSeatInRow(BasicRow row) { Seat seat = null; if (row.NumAvailableSeats > 0) { seat = row.GetFirstAvailableSeat(); seat.Available = false; row.NumAvailableSeats--; } return(seat); }
public void GetPropertyByAttributeWorksProperlyForNamePropertyAddedLater() { Assert.Null(new BasicRow().GetNameField()); var old = BasicRow.Fields.AString.CustomAttributes; try { BasicRow.Fields.AString.CustomAttributes = new object[] { new NamePropertyAttribute() }; var nameField = new BasicRow().GetNameField(); Assert.NotNull(nameField); Assert.Equal("AString", nameField.Name); } finally { BasicRow.Fields.AString.CustomAttributes = old; } }
/// <summary> /// Holds the specified number of seats in the specified row. /// If the number of seats is greater than the number of available seats in the row, /// all remaining seats in the row are held and returned. /// </summary> /// <param name="row">The row in which seats are being held.</param> /// <param name="numSeatsToReserve">The number of seats to hold.</param> /// <returns>The seats that are held.</returns> private List <Seat> HoldAvailableSeatsInRow(BasicRow row, int numSeatsToReserve) { List <Seat> seats = new List <Seat>(); while (numSeatsToReserve > 0) { Seat seat = this.HoldFirstAvailableSeatInRow(row); if (seat == null) { break; } seats.Add(seat); numSeatsToReserve--; } if (row.NumAvailableSeats == 0 && row.RowNumber == this.firstRowWithAvailableSeats.RowNumber) { this.UpdateClosestRowWithAvailableSeats(); } return(seats); }
public void RemoveBasicRow(BasicRow row) { this.Rows.Remove(row); }
public void AddBasicRow(BasicRow row) { this.Rows.Add(row); }
public BasicRowChangeEvent(BasicRow row, global::System.Data.DataRowAction action) { this.eventRow = row; this.eventAction = action; }
/// <summary> /// Find and hold the best available seats for a customer. /// </summary> /// <param name="numSeats">The number of seats to find and hold.</param> /// <param name="customerEmail">Unique identifier for the customer.</param> /// <returns>A SeatHold object identifying the specific seats and related information.</returns> public SeatHold FindAndHoldSeats(int numSeats, string customerEmail) { if (numSeats <= 0) { throw new ArgumentOutOfRangeException($"At least 1 seat must be requested."); } this.ReleaseExpiredSeatHolds(); int numSeatsAvailable = this.NumSeatsAvailable(); if (numSeatsAvailable < numSeats) { throw new TicketServiceException($"There are {numSeatsAvailable} seats available and so {numSeats} seats cannot be reserved."); } SeatHold seatHold = new SeatHold { CustomerEmail = customerEmail, Seats = new List <Seat>() }; // Try to find the closest row to the front with enough seats to seat everyone together. If there is no row in which everyone // can sit together, split group amongst rows closest to the front. Populate backup rows in case no single row with enough seats for whole group. int numSeatsToFill = numSeats; bool existsRowWithEnoughSeats = false; List <BasicRow> backupRows = new List <BasicRow>(); for (int i = firstRowWithAvailableSeats.RowNumber; i < this.Venue.NumRows; i++) { BasicRow row = this.Venue.Rows[i]; if (row.NumAvailableSeats >= numSeats) { existsRowWithEnoughSeats = true; List <Seat> heldSeats = this.HoldAvailableSeatsInRow(row, numSeats); seatHold.Seats.AddRange(heldSeats); break; } if (numSeatsToFill > 0 && row.NumAvailableSeats > 0) { backupRows.Add(row); numSeatsToFill -= row.NumAvailableSeats; } } if (!existsRowWithEnoughSeats) { numSeatsToFill = numSeats; foreach (BasicRow backupRow in backupRows) { List <Seat> heldSeats = this.HoldAvailableSeatsInRow(backupRow, numSeatsToFill); seatHold.Seats.AddRange(heldSeats); numSeatsToFill -= heldSeats.Count; } } this.Venue.TotalAvailableSeats -= seatHold.Seats.Count; seatHold.HoldTime = DateTime.UtcNow; seatHold.Id = Interlocked.Increment(ref incrementingSeatHoldId); this.seatHolds.Add(seatHold.Id, seatHold); return(seatHold); }