MovieDB.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.moviedb;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Calendar;
import java.util.Random;
import java.util.Date;
import java.io.InputStream;
import java.io.IOException;
/**
* MovieDB: Gets access to the local/remote movie database For this
* example we use a simple file to store the data A more elaborated
* example would probably connect to a remote server
*/
public class MovieDB {
private MovieDBListener listener;
private int moviesCount = 3;
private Vector movies = new Vector();
private Hashtable props;
public MovieDB(InputStream in) {
props = new Hashtable();
try {
StringBuffer sb = new StringBuffer();
String key = null;
String value = null;
int chr = 0;
while (chr != -1) {
chr = in.read();
if (chr == '=') {
key = new String(sb).trim();
sb = new StringBuffer();
} else if (key != null && (chr == '\n' || chr == -1)) {
value = new String(sb).trim();
sb = new StringBuffer();
props.put(key, value);
key = null;
} else {
sb.append((char) chr);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
// set the listener
public void setDBListener(MovieDBListener listener) {
this.listener = listener;
}
// request MovieDB to get the data
public void loadData() {
// Create the database in a separate thread
new Thread(new DBGenerator()).start();
}
// return a list of movies
public Vector getMovies() {
return movies;
}
public void close() {
// do nothing. In a real case this should close any
// DB or network connection
}
// request a Booking
public void sendBookingRequest(String firstNameText,
String familyNameText, Showing showing,
int[][] selectedSeats) {
// Simulate a request in a separate
// thread
new Thread(new ReservationRequest(selectedSeats, showing)).start();
}
// Sends an event to listeners
private void sendEvent(int event, Object data) {
if (listener != null) {
listener.handleEvent(new MovieDBEvent(event, data));
}
}
private final class DBGenerator implements Runnable {
// use a set of fixed times for Showings
private final int[] SHOWING_TIMES = new int[]{13, 15, 19, 22, 23};
public void run() {
try {
synchronized (this) {
sendEvent(MovieDBEvent.CONNECTING, "Local database..");
//if (props != null) {
if (props != null) {
// Simulate a connection delay
wait(500);
moviesCount = Integer.parseInt((String) props.get("count"));
// Inform how many movies are there
sendEvent(MovieDBEvent.MOVIES_COUNT,
new Integer(moviesCount));
Random r = new Random();
Date now = new Date();
for (int i = 0; i < moviesCount; i++) {
// Small delay per movie
wait(1000);
Vector showings = new Vector();
// generate showings for 3 days from now
final int DAYS_OF_SHOWINGS = 3;
for (int k = 0; k < DAYS_OF_SHOWINGS; k++) {
// and for each hour in SHOWING_TIMES
for (int j = 0; j < SHOWING_TIMES.length; j++) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
cal.set(Calendar.DAY_OF_MONTH, cal.get(Calendar.DAY_OF_MONTH) + k);
try {
// If this fails, this month doesn't have so many days
cal.getTime();
} catch (IllegalArgumentException e) {
// Move to the next month
if (cal.get(Calendar.MONTH) == Calendar.DECEMBER) {
cal.set(Calendar.MONTH, Calendar.JANUARY);
} else {
cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) + 1);
}
// Continue from the beginning of the next month.
cal.set(Calendar.DAY_OF_MONTH, DAYS_OF_SHOWINGS - k);
}
cal.set(Calendar.HOUR_OF_DAY, cal.get(Calendar.HOUR_OF_DAY) + SHOWING_TIMES[j]);
// only add showings after now
if (cal.getTime().getTime() > now.getTime()) {
// the teather is a bit boring, always 10x15
int rows = 10;
int seatsPerRow = 15;
boolean[][] seating = new boolean[rows][seatsPerRow];
// Generate the seating
for (int l = 0; l < rows; l++) {
for (int m = 0; m < seatsPerRow; m++) {
// one third of seats is occupied
seating[l][m] = (Math.abs(r.nextInt() % 3) == 0);
}
}
// give it some random price
Showing show = new Showing(cal.getTime(), Math.abs(r.nextInt() % 100) * 10, seating);
showings.addElement(show);
}
}
}
// Create movie based on the property file
String movieKey = "movie" + i;
Movie movie = new Movie((String) props.get(movieKey + ".name"),
(String) props.get(movieKey + ".imageLocation"),
(String) props.get(movieKey + ".description"),
showings);
movies.addElement(movie);
sendEvent(MovieDBEvent.MOVIE_LOADED, new Integer(i));
}
sendEvent(MovieDBEvent.DATA_LOADED, null);
} else {
sendEvent(MovieDBEvent.DATA_ERROR, "No database found");
}
}
} catch (InterruptedException e) {
// Ignore, this shouldn't happen
}
}
}
// Internal class used to simulate a booking request in a separate
// thread
private final class ReservationRequest implements Runnable {
private final int[][] seats;
private final Showing showing;
private final Random rnd = new Random();
private ReservationRequest(int[][] seats, Showing showing) {
this.seats = seats;
this.showing = showing;
}
public void run() {
try {
synchronized (this) {
sendEvent(MovieDBEvent.RESERVATION_REQUESTED, null);
// add a small delay
wait(1000);
// the booking is always approved so generate the price
// and an id code
double price = showing.getPrice() * seats.length;
int code = Math.abs(rnd.nextInt());
BookingTicket ticket = new BookingTicket(price, code);
sendEvent(MovieDBEvent.MOVIE_RESERVED, ticket);
}
} catch (InterruptedException e) {
// just ignore
}
}
}
}