/// <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);
        }
Пример #5
0
        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);
        }
Пример #11
0
 public BasicRowChangeEvent(BasicRow row, global::System.Data.DataRowAction action)
 {
     this.eventRow    = row;
     this.eventAction = action;
 }