package org.springframework.prospring.ticket.web;

import java.util.*;

import javax.servlet.http.*;
import org.springframework.web.servlet.mvc.*;
import org.springframework.web.servlet.*;
import org.springframework.web.util.*;
import org.springframework.prospring.ticket.service.*;
import org.springframework.prospring.ticket.domain.*;

/**
 * Kontroler prezentujący rezerwację po określeniu przez użytkownika ilości miejsc.
 * Ogólnie rzecz biorąc, ta strona mogłaby być wyświetlana przez kontroler BookSeetController, jednak
 * w takim przypadku gdyby użytkownik odświeżył stronę (na przykład, naciskając klawisz F5), to formularz
 * zostałby ponownie przesłany, a my musielibyśmy poprawnie obsługiwać tę sytuację w metodzie onSubmit() kontrolera.
 * Aby zaoszczędzić sobie tego problemu, przekierowujemy żądanie do tego kontrolera. Dzięki temu, gdy użytkownik
 * odświeży stronę, nowe żądanie zostanie obsłużone przez ten kontroler, a nie przez kontroler formularza.
 */
public class ShowReservationController extends AbstractController {

    private String viewName;

    /**
     * @see AbstractController#handleRequestInternal(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
     */
    protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {

        Reservation reservation = getReservationFromSession(request);
        ReservationRequest reservationRequest = getReservationRequestFromSession(request);


        ModelAndView mav = new ModelAndView(viewName);
        mav.addObject("reservation", reservation);
        mav.addObject("performance", reservationRequest.getPerformance());
        mav.addObject("minutesReservationWillBeValid", new Integer(reservationRequest.getMinutesToHold()));
        mav.addObject("bookingFee", reservationRequest.getBookingFee());
        mav.addObject("seatsAdjacent", ((areAdjacentSeats(reservation.getSeats())) ? Boolean.TRUE : Boolean.FALSE));
        mav.addObject("seatsCount", new Integer(reservation.getSeats().length));
        return mav;

    }

    /**
     * Ustawia nazwę widoku zwracanego przez ten kontroler.
     * @param viewName Nazwa widoku zwracanego przez ten kontroler.
     */
    public void setViewName(String viewName) {
        this.viewName = viewName;
    }

    // pobiera rezerwację z sesji.
    protected Reservation getReservationFromSession(HttpServletRequest request) {
        return (Reservation)WebUtils.getRequiredSessionAttribute(request, "reservation");
    }

    // pobiera żądanie rezerwacji z sesji.
    protected ReservationRequest getReservationRequestFromSession(HttpServletRequest request) {
        return (ReservationRequest)WebUtils.getRequiredSessionAttribute(request, "reservationRequest");
    }

    /*
     * Sprawdza czy podane miejsca sąsiadują ze sobą.
     *
     * algorytm:  Ogólnie rzecz biorąc, jeśli wszystkie miejsca mają ze sobą sąsiadować, to może być
     *            tylko jedno miejsce, takie że miejsce z jego lewej stroni nie będzie na liście
     *            oraz tylko jedno miejsce takie że miejsce z jego prawej strony nie będzie na liście.
     *            Dla wszystkich pozostałych miejsc, miejsca z ich prawej oraz lewej strony 
     *            powinny być na liście.
     *
     *            Musimy przejrzeć wszystkie miejsca i dla każdego z nich sprawdzić czy 
     *            miejsca z jego lewej oraz prawej strony znajdują się na liście. Jeśli
     *            odszukamy więcej niż jedno miejsce dla którego miejsce z jego lewej lub 
     *            prawej strony nie znajduje się na liście, to będziemy wiedzieć, że 
     *            miejsca nie są sąsiadujące.
     */
    protected boolean areAdjacentSeats(Seat[] seatList) {

        boolean foundLeftNotInList = false;
        boolean foundRightNotInList = false;

        // umieszczamy wszystkie miejsca w obiekcie HashSet by zapewnić szybszy dostęp do nich.
        HashSet seats = new HashSet();
        for (int i=0; i<seatList.length; i++) {
            seats.add(seatList[i]);
        }

        for (int i=0; i<seatList.length; i++) {
            Seat seat = seatList[i];
            if (!seats.contains(seat.getLeftSide())) {
                if (foundLeftNotInList) {
                    return false;
                }
                foundLeftNotInList = true;
            }
            if (!seats.contains(seat.getRightSide())) {
                if (foundRightNotInList) {
                    return false;
                }
                foundRightNotInList = true;
            }
        }

        return true;
    }

}
