/**
* Copyright (C) 2013 Colorado School of Mines
*
* This file is part of the Interface Software Development Kit (SDK).
*
* The InterfaceSDK 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.
*
* The InterfaceSDK 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 the InterfaceSDK. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Class that all modules that want to use processing should extend from.
* Extend from PApplet, so all normal processing should work with this.
* Wraps a ModuleHeper in several methods so as to mimic multiple
* inheritance.
*
* @author Andrew DeMaria
* @author Austin Diviness
*/
package edu.mines.acmX.exhibit.module_management.modules;
import java.awt.Frame;
import java.awt.GraphicsEnvironment;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.rmi.RemoteException;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import javax.imageio.ImageIO;
import edu.mines.acmX.exhibit.input_services.hardware.BadDeviceFunctionalityRequestException;
import edu.mines.acmX.exhibit.input_services.hardware.BadFunctionalityRequestException;
import edu.mines.acmX.exhibit.input_services.hardware.UnknownDriverRequest;
import edu.mines.acmX.exhibit.input_services.hardware.devicedata.DeviceDataInterface;
import edu.mines.acmX.exhibit.input_services.hardware.drivers.InvalidConfigurationFileException;
import edu.mines.acmX.exhibit.module_management.ModuleManager;
import edu.mines.acmX.exhibit.module_management.modules.implementation.ModuleRMIHelper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import edu.mines.acmX.exhibit.module_management.loaders.ManifestLoadException;
import edu.mines.acmX.exhibit.module_management.loaders.ModuleLoadException;
import edu.mines.acmX.exhibit.module_management.metas.ModuleMetaData;
import edu.mines.acmX.exhibit.module_management.modules.implementation.ModuleHelper;
import processing.core.*;
public abstract class ProcessingModule extends PApplet implements ModuleInterface {
private static Logger log = LogManager.getLogger(ProcessingModule.class.getName());
/**
* Due to the limitations of java in regards to inheritance, ProcessingModule
* uses a ModuleHelper so that it can extend PApplet while keeping the
* functionality of a Module.
*/
private final ModuleInterface moduleHelper;
public Frame frame;
public static String IMAGES_LOCATION = "images/";
public ProcessingModule() {
super();
moduleHelper = new ModuleHelper();
// frame = new Frame();
}
/**
* Delegation method, wraps ModuleHelper's setNextModuleToLoad function
* in its own method.
*
* @param moduleName Package name of next moduleHelper to load
* @throws RemoteException
*/
@Override
public boolean setNextModule( String moduleName ) throws RemoteException {
return moduleHelper.setNextModule( moduleName );
}
@Override
public InputStream loadResourceFromModule( String jarResourcePath, ModuleMetaData m ) throws ManifestLoadException, ModuleLoadException, RemoteException {
return moduleHelper.loadResourceFromModule(jarResourcePath, m);
}
@Override
public InputStream loadResourceFromModule( String jarResourcePath ) throws ManifestLoadException, ModuleLoadException, RemoteException {
return moduleHelper.loadResourceFromModule(jarResourcePath);
}
@Override
public ModuleMetaData getModuleMetaData(String packageName) throws RemoteException {
return moduleHelper.getModuleMetaData(packageName);
}
@Override
public String[] getAllAvailableModules() throws RemoteException {
return moduleHelper.getAllAvailableModules();
}
@Override
public String getCurrentModulePackageName() throws RemoteException {
return moduleHelper.getCurrentModulePackageName();
}
@Override
public ModuleMetaData getDefaultModuleMetaData() throws RemoteException {
return moduleHelper.getDefaultModuleMetaData();
}
@Override
public InputStream loadResourceFromModule(String jarResourcePath,
String packageName) throws RemoteException, ManifestLoadException,
ModuleLoadException {
return moduleHelper.loadResourceFromModule(jarResourcePath, packageName);
}
@Override
public String next() throws RemoteException {
return moduleHelper.next();
}
@Override
public int nextInt() throws RemoteException {
return moduleHelper.nextInt();
}
@Override
public Map<String, String> getConfigurations() throws RemoteException {
return moduleHelper.getConfigurations();
}
@Override
public String getPathToModules() throws RemoteException {
return moduleHelper.getPathToModules();
}
@Override
public DeviceDataInterface getInitialDriver( String functionality )
throws RemoteException, BadFunctionalityRequestException, UnknownDriverRequest,
InvalidConfigurationFileException, BadDeviceFunctionalityRequestException {
return moduleHelper.getInitialDriver( functionality );
}
/**
* This function does the dirty work for creating a new Processing window.
* This will call Processing's init() function which does further Processing
* specific setup stuff and will finally call this PApplets overridden
* setup, draw and update function if they exist
*
* TODO try to run PApplet without creating a new frame.
*/
@Override
public void execute(){
// frame.dispose(); // Dispose the window to make it undisplayable and be able to change its properties
// frame.setExtendedState(Frame.MAXIMIZED_BOTH); //maximize the window
// frame.setUndecorated(true); //disable bordering
// GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
// frame.setSize(env.getMaximumWindowBounds().getSize()); //set window size to maximum for maximized windows
// frame.addWindowListener( new WindowAdapter() {
// public void windowClosing( WindowEvent e ) {
// exit(); //exit the specific moduleHelper when the window is closed, not ModuleManager
// }
// });
//
// frame.setVisible(true); //get correct screen size for Windows
// frame.add(this);
// frame.setVisible(true);
super.init();
}
// TODO: check if buffered image supports same image types asProcessing
// loadImage function
@Override
public PImage loadImage(String name) {
//use original function if from an outside resource
if (name.startsWith("http://") || name.startsWith("https://")) {
return super.loadImage(name);
}
name = IMAGES_LOCATION + name;
try {
InputStream stream = loadResourceFromModule(name); //, "edu.mines.acmX.exhibit.modules.home_screen");
//InputStream stream = moduleHelper.loadResourceFromModule(name);
BufferedImage buf = ImageIO.read(stream);
return buffImagetoPImage(buf);
} catch (Exception e) {
log.error("Exception was hit: " + e.getClass().toString());
return null;
}
}
public PImage loadImage(String name, ModuleMetaData m) {
name = IMAGES_LOCATION + name;
InputStream stream;
try {
stream = moduleHelper.loadResourceFromModule(name, m);
if (stream == null ) {
log.debug("Could not load the image for the given resource");
return null;
}
BufferedImage buf = ImageIO.read(stream);
return buffImagetoPImage(buf);
} catch (ManifestLoadException e) {
log.error("Exception was hit: " + e.getClass().toString());
e.printStackTrace();
} catch (ModuleLoadException e) {
log.error("Exception was hit: " + e.getClass().toString());
e.printStackTrace();
} catch (IOException e) {
log.error("Exception was hit: " + e.getClass().toString());
e.printStackTrace();
}
return null;
}
private static PImage buffImagetoPImage(BufferedImage bimg) {
PImage img = new PImage(bimg.getWidth(), bimg.getHeight(), PConstants.ARGB);
bimg.getRGB(0, 0, img.width, img.height, img.pixels, 0, img.width);
return img;
}
@Override
public void destroy() {
//System.out.println("In processing module destroy");
super.destroy();
//System.out.println("After destroy");
ModuleManager.destroyCurrentModule();
//System.out.println("After destroyCurrentModule");
}
}