MovieBooking.java

/*
 * Copyright © 2011 Nokia Corporation. All rights reserved.
 * Nokia and Nokia Connecting People are registered trademarks of Nokia Corporation. 
 * Oracle and Java are trademarks or registered trademarks of Oracle and/or its
 * affiliates. Other product and company names mentioned herein may be trademarks
 * or trade names of their respective owners. 
 * See LICENSE.TXT for license information.
 */
package com.nokia.example.moviebooking.ui;

import java.util.Vector;

import javax.microedition.midlet.MIDlet;

import com.nokia.example.moviebooking.moviedb.BookingTicket;
import com.nokia.example.moviebooking.moviedb.Movie;
import com.nokia.example.moviebooking.moviedb.MovieDB;
import com.nokia.example.moviebooking.moviedb.MovieDBEvent;
import com.nokia.example.moviebooking.moviedb.MovieDBListener;
import com.nokia.example.moviebooking.moviedb.Showing;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.MessageBox;

/**
 * The class MovieBooking is the core of the application It takes care
 * of managing the user interface, drive the eSWT event loop and talk
 * to the Movie Database
 */
public class MovieBooking implements Runnable, MovieDBListener {

    private MovieDB movieDB;
    private Shell mainShell;
    private SplashScreen splashScreen;
    private Display display;
    private ReservationForm reservationForm;
    private boolean running = false;
    private MIDlet midlet;

    public MovieBooking(MIDlet midlet) {
        this.midlet = midlet;
    }

    // In the run method we execute the eSWT event loop
    public void run() {

        running = true;
        // Note that Display has to be created here since that
        // determines the UI thread
        display = new Display();

        // Create the main shell
        mainShell = new Shell(display, SWT.NONE);
        mainShell.setText("MovieBooking");

        // Create a layout for the shell
        GridLayout layout = new GridLayout();
        // Zero the margins that are non-zero by default
        layout.horizontalSpacing = 0;
        layout.verticalSpacing = 0;
        layout.marginWidth = 0;
        layout.marginHeight = 0;
        mainShell.setLayout(layout);

        // open first this shell to be in the background
        mainShell.open();
        mainShell.setRedraw(false);
        // Creates the splash screen
        splashScreen = new SplashScreen(this, mainShell);

        // Activate the layout of the mainShell to make it resize
        // the splashScreen
        mainShell.layout();
        mainShell.setRedraw(true);
        // Create the MovieDB and request that it starts loading the data
        movieDB = new MovieDB(getClass().getResourceAsStream(
                "/res/movieDB.properties"));
        movieDB.setDBListener(this);
        // This starts loading the data on a separate thread
        movieDB.loadData();

        // eSWT event loop runs until the main shell is disposed
        // or the running flag is set to false.
        // The flag can get set due to a user initiated exit or due to
        // a system request to terminate the application.
        while (running && !mainShell.isDisposed()) {
            // Check if there are pending events
            if (!display.readAndDispatch()) {
                // otherwise sleep
                display.sleep();
            }
        }

        // Dispose the display, this will also dispose mainShell
        display.dispose();
        // Destroy the MIDlet
        midlet.notifyDestroyed();
    }

    // This is called when new data is loaded by MovieDB
    public void handleEvent(MovieDBEvent event) {
        // check anyway if the mainShell is still alive
        if (!mainShell.isDisposed()) {
            // this is a non-GUI thread. we need to do  actions
            // in the GUI thread and so asyncExec is used
            SplashScreenRunnable runnable = new SplashScreenRunnable(event);
            display.asyncExec(runnable);
        }
    }

    // Exit method
    public void exit() {
        // close the DB and dispose the main shell
        movieDB.close();
        running = false;
        display.wake();
    }

    // Show the reservation form when coming back from seatingShell
    void setSelectedSeats(int[][] selected) {
        reservationForm.setSelectedSeats(selected);
    }

    void cancelSeatSelection() {
        reservationForm.cancelSeatSelection();
    }

    // Show the reservation form
    void startReserve(Movie movie) {
        reservationForm = new ReservationForm(MovieBooking.this,
                mainShell,
                movie);
    }

    // Shown when the reservation is being sent to movieDB
    void confirmReservation(String firstNameText,
            String familyNameText, Showing showing, int[][] selectedSeats) {
        // Ask MovieDB to request some seats
        dataLoaded();
        int result = displayMessageBox(SWT.ICON_INFORMATION | SWT.YES | SWT.NO,
                "Booking",
                "Are you sure you want to reserve?");
        if (result == SWT.YES) {
            // return to the movie list
            movieDB.sendBookingRequest(firstNameText, familyNameText,
                    showing, selectedSeats);
        }
    }

    // Displays a message box
    int displayMessageBox(int type, String text, String message) {
        if (Thread.currentThread() == display.getThread()) {
            MessageBox box = new MessageBox(mainShell, type);
            box.setText(text);
            box.setMessage(message);
            return box.open();
        } else {
            return -1;
        }
    }

    // Shows the seating dialog
    void showSeatingDialog(Showing showing, int[][] selectedSeats,
            int ticketsCount) {
        new SeatingScreen(this, mainShell, showing,
                selectedSeats, ticketsCount);
    }

    // Advance the progress bar in SplashShell
    private void advanceSplashShellProgress(String message) {
        splashScreen.setLabel(message);
        splashScreen.advance();
    }

    // Called if an error occured in movieDB
    private void movieDBDataError() {
        displayMessageBox(SWT.ICON_ERROR,
                "Information",
                "Error loading the database");
        // Exit the swt loop
        mainShell.dispose();
    }

    // Set the total amount of movies to display
    private void setMovieCount(int count) {
        splashScreen.setMoviesCount(count);
    }

    // Show a dialog box when a reservation has been confirmed
    private void displayReservationConfirmed(BookingTicket booking) {
        displayMessageBox(SWT.ICON_INFORMATION | SWT.OK,
                "Booking",
                "Reservation confirmed number " + booking.getCode()
                + " total: " + booking.getPrice());
    }

    // Called when all the data in MovieDB is
    // available. We close splashShell and
    // start Movie Display
    private void dataLoaded() {
        if (splashScreen != null) {
            splashScreen.destroy();
            splashScreen = null;
        }
        Vector movies = movieDB.getMovies();
        if (movies.isEmpty()) {
            // No movie found
            displayMessageBox(SWT.ICON_INFORMATION | SWT.OK,
                    "Information",
                    "No movies available");
            // Exit the swt loop
            mainShell.dispose();
        } else {
            // Start the new MovieDisplay screen
            new MoviesListScreen(MovieBooking.this, mainShell, movies);
        }
    }

    // Inner class used to call actions on the GUI
    // being initiated in MovieDB
    private class SplashScreenRunnable implements Runnable {

        private MovieDBEvent event;

        SplashScreenRunnable(MovieDBEvent event) {
            this.event = event;
        }

        public void run() {
            // Note that this is called from the GUI thread
            switch (event.getEvent()) {
                case MovieDBEvent.CONNECTING:
                    // When connecting update the progress label
                    // in the splash shell
                    advanceSplashShellProgress("Loading from " + (String) event.getData());
                    break;
                case MovieDBEvent.DATA_ERROR:
                    movieDBDataError();
                    break;
                case MovieDBEvent.MOVIES_COUNT:
                    setMovieCount(((Integer) event.getData()).intValue() + 1);
                    break;
                case MovieDBEvent.MOVIE_LOADED:
                    // Called when data for a new movie is available
                    advanceSplashShellProgress("Movie "
                            + (((Integer) event.getData()).intValue() + 1));
                    break;
                case MovieDBEvent.DATA_LOADED:
                    dataLoaded();
                    break;
                case MovieDBEvent.MOVIE_RESERVED:
                    displayReservationConfirmed((BookingTicket) event.getData());
                    break;
            }
        }
    }
}