/** * The number of seats in the requested level that are neither held nor reserved * * @param venueLevel a numeric venue level identifier to limit the search * @return the number of tickets available on the provided level */ @Override public int numSeatsAvailable(Integer venueLevel) { resetHolds(); List<LevelVO> levelList = TemporaryDatabase.getStage(); int seatsAvailable = 0; if (levelList != null && !levelList.isEmpty()) { for (LevelVO levelVO : levelList) { if (levelVO != null && levelVO.getLevelId() == venueLevel) { Map<Integer, List<SeatVO>> rowsAndSeats = levelVO.getRowsAndSeats(); if (rowsAndSeats != null && !rowsAndSeats.isEmpty()) { Set<Integer> rows = rowsAndSeats.keySet(); if (rows != null && !rows.isEmpty()) { for (Integer rowId : rows) { if (rowId != -1) { List<SeatVO> seats = rowsAndSeats.get(rowId); if (seats != null && !seats.isEmpty()) { for (SeatVO seatVO : seats) { if (seatVO.getStatusCode() == Constants.SEAT_AVAILABLE) { seatsAvailable++; } } } } } } } } } } return seatsAvailable; }
/** * If holds are not expired, seat status will be changed to reserved. * * @param levelNumber The level number where seats need to be reserved * @param rowNumber row number where seats need to be reserved * @param seatNum seat number to be reserved * @return reservation status. */ private boolean processSeatReserve(int levelNumber, int rowNumber, int seatNum) { List<LevelVO> levels = TemporaryDatabase.getStage(); for (LevelVO levelVO : levels) { if (levelVO != null && levelVO.getLevelId() == levelNumber) { Map<Integer, List<SeatVO>> rowsAndSeats = levelVO.getRowsAndSeats(); Set<Integer> rows = rowsAndSeats.keySet(); if (rows != null && !rows.isEmpty()) { for (Integer row : rows) { if (row == rowNumber) { List<SeatVO> seats = rowsAndSeats.get(row); if (seats != null && !seats.isEmpty()) { for (SeatVO seatVO : seats) { if (seatVO != null && seatVO.getSeatNum() == seatNum && seatVO.getStatusCode() == Constants.SEAT_HOLD) { // Update stauts code if (holdNotExpired(seatVO.getHoldTimeStamp().getTime())) { seatVO.setStatusCode(Constants.SEAT_RESERVED); return true; } else { seatVO.setStatusCode(Constants.SEAT_AVAILABLE); return false; } } } } } } } } } return false; }
/** * @param minLevel minimum level where best selection starts * @param maxLevel maximum level where best selection ends * @param numSeats number of seats need to be put on hold * @param seatsToHold List keeps track of seats on hold in this perticualr request. * @return SeatHold object which contains hold details. */ private SeatHoldVO processSeatHold( int minLevel, int maxLevel, int numSeats, List<SeatHoldVO> seatsToHold) { List<LevelVO> levels = TemporaryDatabase.getStage(); if (numSeats > 0) { // Generates a randome SeatHoldId while creating SeatHold object. SeatHoldVO seatHold = new SeatHoldVO(generateRandom()); for (LevelVO levelVO : levels) { if (numSeats <= 0) { break; } if (levelVO != null && levelVO.getLevelId() == minLevel && minLevel <= maxLevel) { Map<Integer, List<SeatVO>> rowsAndSeats = levelVO.getRowsAndSeats(); Set<Integer> rows = rowsAndSeats.keySet(); if (rows != null && !rows.isEmpty()) { for (Integer row : rows) { if (numSeats <= 0) { break; } List<SeatVO> seats = rowsAndSeats.get(row); if (seats != null && !seats.isEmpty()) { for (SeatVO seatVO : seats) { if (numSeats <= 0) { break; } if (seatVO != null && seatVO.getStatusCode() == Constants.SEAT_AVAILABLE && numSeats > 0) { Date dt = new Date(); // Update with Random ID SeatInfoVO seatInfo = new SeatInfoVO( levelVO.getLevelId(), row, seatVO.getSeatNum(), levelVO.getPrice(), levelVO.getLevelName(), dt); seatHold.addSeat(seatInfo); // Update stauts code seatVO.setHoldTimeStamp(dt); seatVO.setStatusCode(Constants.SEAT_HOLD); numSeats--; } } } } } minLevel++; } } seatsToHold.add(seatHold); return seatHold; } return null; }
/** * Commit seats held for a specific customer * * @param seatHoldId the seat hold identifier * @param customerEmail the email address of the customer to which the seat hold is assigned * @return a reservation confirmation code */ @Override public String reserveSeats(int seatHoldId, String customerEmail) { // Before proceeding with reservation, make sure holds are not expired. resetHolds(); // NOW proceed with reservation logic. Map<String, List<SeatHoldVO>> seatsOnHold = TemporaryDatabase.getSeatsOnHold(); int failureCnt = 0; if (seatsOnHold != null && !seatsOnHold.isEmpty()) { List<SeatHoldVO> seatHoldList = seatsOnHold.get(customerEmail); if (seatHoldList != null && !seatHoldList.isEmpty()) { Iterator<SeatHoldVO> seatHoldIter = seatHoldList.iterator(); while (seatHoldIter.hasNext()) { SeatHoldVO seatHold = seatHoldIter.next(); if (seatHold != null && seatHold.getSeatHoldId() == seatHoldId) { List<SeatInfoVO> seatsList = seatHold.getSeatsList(); if (seatsList != null && !seatsList.isEmpty()) { Iterator<SeatInfoVO> seatInfoIter = seatsList.iterator(); while (seatInfoIter.hasNext()) { SeatInfoVO seatInfo = seatInfoIter.next(); boolean reserveStatus = processSeatReserve( seatInfo.getLevelNum(), seatInfo.getRowNum(), seatInfo.getSeatNum()); if (!reserveStatus) { failureCnt++; } seatInfoIter.remove(); } seatHoldIter.remove(); } else { // WE are about to reserve seats, but seats are EMPTY, which means failure. failureCnt++; } } } } else { // WE are about to reserve seats, but seats are EMPTY, which means failure. failureCnt++; } } if (failureCnt > 0) { return Constants.FAILURE_MSG; } return Constants.SUCCES_MSG; }
/** * Find and hold the best available seats for a customer * * @param numSeats the number of seats to find and hold * @param minLevel the minimum venue level * @param maxLevel the maximum venue level * @param customerEmail unique identifier for the customer * @return a SeatHold object identifying the specific seats and related information */ @Override public SeatHoldVO findAndHoldSeats( int numSeats, Integer minLevel, Integer maxLevel, String customerEmail) { resetHolds(); List<SeatHoldVO> seatsToHold = new ArrayList<>(); if (minLevel > 0 && (maxLevel > 0 && maxLevel < 5)) { // Va Map<String, List<SeatHoldVO>> seatsOnHold = TemporaryDatabase.getSeatsOnHold(); if (seatsOnHold.isEmpty()) { SeatHoldVO seatHold = processSeatHold(minLevel, maxLevel, numSeats, seatsToHold); seatsOnHold.put(customerEmail, seatsToHold); return seatHold; } else { seatsToHold = seatsOnHold.get(customerEmail); if (seatsToHold == null) { seatsToHold = new ArrayList<>(); } SeatHoldVO seatHold = processSeatHold(minLevel, maxLevel, numSeats, seatsToHold); seatsOnHold.put(customerEmail, seatsToHold); return seatHold; } } return null; }
/** * This method updates temporary database maps hold status to AVAILABLE, if Hold expired after 10 * seconds. */ private void resetHolds() { // Reset Holds on Levels List<LevelVO> levels = TemporaryDatabase.getStage(); for (LevelVO levelVO : levels) { if (levelVO != null) { Map<Integer, List<SeatVO>> rowsAndSeats = levelVO.getRowsAndSeats(); Set<Integer> rows = rowsAndSeats.keySet(); if (rows != null && !rows.isEmpty()) { for (Integer row : rows) { List<SeatVO> seats = rowsAndSeats.get(row); if (seats != null && !seats.isEmpty()) { for (SeatVO seatVO : seats) { if (seatVO != null && seatVO.getStatusCode() == Constants.SEAT_HOLD) { if (!holdNotExpired(seatVO.getHoldTimeStamp().getTime())) { // Update stauts code to available seatVO.setStatusCode(Constants.SEAT_AVAILABLE); } } } } } } } } // Reset Holds on HoldsAndSeats Map<String, List<SeatHoldVO>> holds = TemporaryDatabase.getSeatsOnHold(); if (holds != null && !holds.isEmpty()) { Collection<List<SeatHoldVO>> seatHolds = holds.values(); if (seatHolds != null && !seatHolds.isEmpty()) { for (List<SeatHoldVO> seatHoldList : seatHolds) { if (seatHoldList != null && !seatHoldList.isEmpty()) { Iterator<SeatHoldVO> seatHoldIter = seatHoldList.iterator(); while (seatHoldIter.hasNext()) { SeatHoldVO seatHold = seatHoldIter.next(); if (seatHold != null && seatHold.getSeatsList() != null && !seatHold.getSeatsList().isEmpty()) { Iterator<SeatInfoVO> seatInfoIter = seatHold.getSeatsList().iterator(); while (seatInfoIter.hasNext()) { SeatInfoVO seatInfo = seatInfoIter.next(); if (!holdNotExpired(seatInfo.getHoldTimeStamp().getTime())) { seatInfoIter.remove(); } } } if (seatHold != null && seatHold.getSeatsList().isEmpty()) { seatHoldIter.remove(); } } } } } } // Map<String, List<SeatHoldVO>> resetHolds = TemporaryDatabase.getSeatsOnHold(); // if (resetHolds != null && !resetHolds.isEmpty()) { // Collection<List<SeatHoldVO>> seatHolds = resetHolds.values(); // Iterator<List<SeatHoldVO>> seatIter = seatHolds.iterator(); // while (seatIter.hasNext()) { // List<SeatHoldVO> seatholdList = seatIter.next(); // if (seatholdList != null && !seatholdList.isEmpty()) { // Iterator<SeatHoldVO> seatholdIter = seatholdList.iterator(); // while (seatholdIter.hasNext()) { // // } // } // } // } }