/*
Copyright (C) 2013 Linus Lindgren
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package bluetooth;
import host.Configuration;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.ConcurrentHashMap;
import javax.bluetooth.BluetoothStateException;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.UUID;
import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnectionNotifier;
import com.sun.org.apache.xpath.internal.functions.WrongNumberArgsException;
import util.IdHandler;
/**
*
* The BluetoothServer's main tasks is to start up the
* {@link IncomingClientListener} and to keep track of the active clients (
* {@link BluetoothClient}) connected to the server.
*
* @author Linus Lindgren(linlind@student.chalmers.se)
*
*/
public class BluetoothServer {
private static BluetoothServer instance;
private static ConcurrentHashMap<Integer, BluetoothClient> clients;
private final static int MAX_NUMBER_CLIENTS = 10;
private final static int MAX_NUMBER_BUTTONS = 25;
private final static UUID VIRTUALGAMEPAD_UUID = new UUID("27012f0c68af4fbf8dbe6bbaf7aa432a", false);
private final static String NAME = "Virtual Gamepad Host";
private final static String URL = "btspp://localhost:" + VIRTUALGAMEPAD_UUID + ";name=" + NAME + ";authenticate=false;encrypt=false;";
private static boolean allowClientInput;
private LocalDevice device;
private StreamConnectionNotifier server;
private BluetoothServer() {
clients = new ConcurrentHashMap<Integer, BluetoothClient>();
try {
device = LocalDevice.getLocalDevice();
if (device != null) {
if (!LocalDevice.isPowerOn()) {
System.out.println("Device power is off. Turn it on!");
System.exit(1);
}
} else {
System.out.println("No device");
System.exit(1);
}
} catch (BluetoothStateException e) {
System.out.println(e.getMessage());
System.exit(1);
}
}
/**
* The constructor of BluetoothServer checks if the computer has a
* {@link LocalDevice} and if it work's properly, otherwise the application
* will exit.
*
*/
public static BluetoothServer getInstance() {
if (instance == null) {
instance = new BluetoothServer();
}
return instance;
}
/**
* Opens a server connection ({@link StreamConnectionNotifier}) and starts
* up {@link IncomingClientListener} if succeeded. If opening of the
* connection failed, the application will be exited.
*/
public void startServer() {
System.out.println();
System.out.println();
System.out.println("Device:");
System.out.println("\t" + device.getFriendlyName());
System.out.println("\t" + device.getBluetoothAddress());
System.out.println();
System.out.println();
try {
System.out.println("Opening up server connection...");
server = (StreamConnectionNotifier) Connector.open(URL);
} catch (IOException e) {
System.out.println("Failed open server connection: " + e.getMessage());
System.exit(1);
}
System.out.println("Server up and running!");
IncomingClientListener listener = new IncomingClientListener(server);
listener.start();
setAllowClientInput(true);
}
public void addClient(BluetoothClient client) {
clients.put(client.getClientId(), client);
client.connectionAccepted();
}
public void removeClient(BluetoothClient client) {
clients.remove(client.getClientId());
IdHandler.getInstance(Configuration.getInstance().getNumberOfClients()).setIdUnoccupied(client.getClientId());
}
public BluetoothClient getClient(int id) {
return clients.get(id);
}
public ConcurrentHashMap<Integer, BluetoothClient> getClients() {
return clients;
}
/**
* A static method that ask for a user input in the form of an integer with
* values between 1 and 25 to set the number of buttons per client.
*
* @return Returns the number of buttons per client.
*/
public static int getNumberOfButtons() {
try {
System.out.println();
System.out.println("Please enter the number of buttons [1-" + MAX_NUMBER_BUTTONS + "] (default=" + lib.Constants.DEFAULT_NUMBER_OF_BUTTONS + "):");
int i = getInputInt(1, MAX_NUMBER_BUTTONS);
System.out.println("Number of buttons is set to " + i);
System.out.println();
return i;
} catch (IOException e) {
} catch (NumberFormatException e) {
} catch (WrongNumberArgsException e) {
System.out.println(e.getMessage());
}
System.out.println("Number of buttons is set to default: " + lib.Constants.DEFAULT_NUMBER_OF_BUTTONS);
System.out.println();
return lib.Constants.DEFAULT_NUMBER_OF_BUTTONS;
}
/**
* A static method that ask for a user input in the form of an integer with
* values between 1 and 10 to set the number of clients.
*
* @return Returns the number of clients.
*/
public static int getNumberOfClients() {
try {
System.out.println();
System.out.println("Please enter the maximal number of clients [1-" + MAX_NUMBER_CLIENTS + "] (default=" + lib.Constants.DEFAULT_MAX_CLIENTS + "):");
int i = getInputInt(1, MAX_NUMBER_CLIENTS);
System.out.println("Maximal number of clients is set to " + i);
System.out.println();
return i;
} catch (IOException e) {
} catch (NumberFormatException e) {
} catch (WrongNumberArgsException e) {
System.out.println(e.getMessage());
}
System.out.println("Maximal number of clients is set to default: " + lib.Constants.DEFAULT_MAX_CLIENTS);
System.out.println();
return lib.Constants.DEFAULT_MAX_CLIENTS;
}
public static boolean isAllowClientInput() {
return allowClientInput;
}
public static void setAllowClientInput(boolean allowClientInput) {
BluetoothServer.allowClientInput = allowClientInput;
}
private static int getInputInt(int lowest, int highest) throws IOException, NumberFormatException, WrongNumberArgsException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int i = Integer.parseInt(br.readLine());
if (i >= lowest && i <= highest) {
return i;
} else {
throw new WrongNumberArgsException("Number not between " + lowest + " and " + highest);
}
}
}