ReservationForm.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 java.util.Calendar;
import java.util.Date;
import java.util.Hashtable;

import com.nokia.example.moviebooking.moviedb.Movie;
import com.nokia.example.moviebooking.moviedb.Showing;

import org.eclipse.ercp.swt.mobile.Command;
import org.eclipse.ercp.swt.mobile.ConstrainedText;
import org.eclipse.ercp.swt.mobile.DateEditor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Combo;

/**
 * This class contains a common Form to enter the data needed to make
 * a reservation. It contains fields such as first name,
 * family name date, etc.
 *
 * The seating location is obtained in a separate form
 */
public class ReservationForm implements SelectionListener, ModifyListener {

    private MovieBooking main;
    private Command exitCommand, seatCommand, confirmCommand;
    private DateEditor movieDate;
    private Combo movieTime;
    private Composite mainComposite;
    private Hashtable validDates = new Hashtable();
    private Text firstNameText, familyNameText;
    private ConstrainedText ticketsText;
    private int[][] selectedSeats;

    ReservationForm(MovieBooking main, Shell mainShell, Movie movie) {
        this.main = main;
        mainShell.setText("Reservation");
        mainShell.setRedraw(false);
        mainComposite = new Composite(mainShell, SWT.NONE);

        // Size and location of this Composite are controlled by
        // the GridLayout of the mainShell
        mainComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

        // Create all the widgets in the Composite
        Label firstNameLabel = new Label(mainComposite, SWT.NONE);
        firstNameLabel.setText("First name");
        // Contains the first name
        firstNameText = new Text(mainComposite, SWT.SINGLE | SWT.BORDER);
        firstNameText.setTextLimit(20);

        Label familyNameLabel = new Label(mainComposite, SWT.NONE);
        familyNameLabel.setText("Family name");
        // Contains the family name
        familyNameText = new Text(mainComposite, SWT.SINGLE | SWT.BORDER);
        familyNameText.setTextLimit(20);

        Label dateLabel = new Label(mainComposite, SWT.NONE);
        dateLabel.setText("Date");
        // Date for the movie, by default today
        movieDate = new DateEditor(
                mainComposite,
                SWT.NONE,
                DateEditor.DATE | SWT.BORDER);
        movieDate.setDate(new Date());
        movieDate.addModifyListener(this);

        // A drop-down list of times
        Label timeLabel = new Label(mainComposite, SWT.NONE);
        timeLabel.setText("Time");
        movieTime = new Combo(mainComposite, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.BORDER);

        Vector showings = movie.getShowings();
        Vector times = new Vector();
        // Store in the time combo the time valid
        // for all showings, validDates contains
        // a map between showingDate and showing
        for (int i = 0; i < showings.size(); ++i) {
            Showing show = (Showing) showings.elementAt(i);
            Calendar cal = Calendar.getInstance();
            cal.setTime(show.getDate());
            String showingTime = cal.get(Calendar.HOUR_OF_DAY) + ":00";
            if (!times.contains(showingTime)) {
                times.addElement(showingTime);
            }
            validDates.put(show.getDate(), show);
        }
        for (int i = 0; i < times.size(); ++i) {
            movieTime.add((String) times.elementAt(i));
        }
        movieTime.select(0);
        movieTime.addSelectionListener(this);

        Label ticketsLabel = new Label(mainComposite, SWT.NONE);
        ticketsLabel.setText("Tickets");

        // Amount of tickets, note that ConstrainedText only takes numbers
        ticketsText = new ConstrainedText(mainComposite, SWT.SINGLE | SWT.BORDER, ConstrainedText.NUMERIC);
        ticketsText.addModifyListener(this);
        ticketsText.setText("2");

        // Use a grid layout with two columns
        GridLayout layout = new GridLayout();
        layout.makeColumnsEqualWidth = false;
        layout.numColumns = 2;
        mainComposite.setLayout(layout);

        // Distribute the forms using the layout
        firstNameText.setLayoutData(
                new GridData(SWT.FILL, SWT.CENTER, true, false));
        familyNameText.setLayoutData(
                new GridData(SWT.FILL, SWT.CENTER, true, false));
        ticketsText.setLayoutData(
                new GridData(SWT.FILL, SWT.CENTER, true, false));
        movieDate.setLayoutData(
                new GridData(SWT.FILL, SWT.CENTER, true, false));
        movieTime.setLayoutData(
                new GridData(SWT.FILL, SWT.CENTER, true, false));

        setCommands();
        mainShell.layout();
        mainShell.setRedraw(true);
    }

    private void setCommands() {
        // add commands
        exitCommand = new Command(mainComposite.getShell(), Command.EXIT, 0);
        exitCommand.setText("Exit");
        exitCommand.addSelectionListener(this);

        seatCommand = new Command(mainComposite.getShell(), Command.GENERAL, 1);
        seatCommand.setText("Seating");
        seatCommand.addSelectionListener(this);
    }

    // Called when some command is selected
    public void widgetSelected(SelectionEvent e) {
        if (e.widget == exitCommand) {
            // Exit the main application
            destroy();
            main.exit();
        } else if (e.widget == movieTime) {
            selectedSeats = null;
            if (confirmCommand != null) {
                confirmCommand.dispose();
                confirmCommand = null;
            }
        } else if (e.widget == seatCommand) {
            // Iterate over the valid dates
            Date showingDate = calculateTime();

            if (validDates.containsKey(showingDate) || (ticketsText.getText().length() == 0)) {
                int ticketsCount = 0;
                try {
                    ticketsCount = Integer.parseInt(ticketsText.getText());
                } catch (NumberFormatException ex) {
                    // Ignore, just use 0
                }
                if (ticketsCount == 0) {
                    return;
                }
                Showing show = (Showing) validDates.get(showingDate);
                exitCommand.dispose();
                exitCommand = null;
                seatCommand.dispose();
                seatCommand = null;
                if (confirmCommand != null) {
                    confirmCommand.dispose();
                    confirmCommand = null;
                }
                main.showSeatingDialog(show, selectedSeats, ticketsCount);
            } else {
                main.displayMessageBox(SWT.ICON_ERROR | SWT.OK,
                        "Error",
                        "Wrong date selected");
            }
        } else if (e.widget == confirmCommand) {
            Date showingDate = calculateTime();
            // Validate the fields
            if (selectedSeats == null || firstNameText.getText().equals("")
                    || familyNameText.getText().equals("")) {
                main.displayMessageBox(SWT.ICON_ERROR | SWT.OK,
                        "Error",
                        "Missing required fields");
                return;
            } else {
                // Request to main to make the reservation
                String firstName = firstNameText.getText();
                String familyName = familyNameText.getText();
                destroy();
                main.confirmReservation(firstName,
                        familyName, (Showing) validDates.get(showingDate), selectedSeats);
            }
        }
    }

    public void widgetDefaultSelected(SelectionEvent e) {
    }

    // Called when the user has selected the seats
    void setSelectedSeats(int[][] selected) {
        this.selectedSeats = selected;
        setCommands();
        if (confirmCommand == null && selectedSeats != null) {
            // Add a new command
            confirmCommand = new Command(
                    mainComposite.getShell(),
                    Command.GENERAL,
                    1);
            confirmCommand.setText("Confirm");
            confirmCommand.addSelectionListener(this);
            confirmCommand.setDefaultCommand();
        }
    }

    void cancelSeatSelection() {
        selectedSeats = null;
        if (confirmCommand != null) {
            confirmCommand.dispose();
            confirmCommand = null;
        }
        setCommands();
    }

    // Close the main composite and dispose it
    private void destroy() {
        if (confirmCommand != null) {
            confirmCommand.dispose();
            confirmCommand = null;
        }
        if (seatCommand != null) {
            seatCommand.dispose();
            seatCommand = null;
        }
        if (exitCommand != null) {
            exitCommand.dispose();
            exitCommand = null;
        }
        mainComposite.dispose();
    }

    // Create a time based on movieDate and timeCombo
    private Date calculateTime() {
        if (movieTime.getSelectionIndex() == -1) {
            return null;
        } else {
            Calendar cal = Calendar.getInstance();
            // Take the date from movieDate
            Date showingDate = movieDate.getDate();
            cal.setTime(showingDate);

            // Get the time from movieTime, so we remove the last ":00"
            // Notice that we expect only exact minutes
            String time = movieTime.getItem(movieTime.getSelectionIndex());
            int hourOfDay = Integer.parseInt(time.substring(0, time.indexOf(':')));
            int minutes = Integer.parseInt(time.substring(time.indexOf(':') + 1, time.length() - 1));

            cal.set(Calendar.HOUR_OF_DAY, hourOfDay);
            cal.set(Calendar.MINUTE, minutes);
            cal.set(Calendar.SECOND, 0);
            cal.set(Calendar.MILLISECOND, 0);
            return cal.getTime();
        }
    }

    public void modifyText(ModifyEvent e) {
        selectedSeats = null;
        if (confirmCommand != null) {
            confirmCommand.dispose();
            confirmCommand = null;
        }
    }
}