/*
* Copyright (c) 2010-2011 by Stefan Laubenberger.
*
* Tyr is free software: you can redistribute it and/or modify
* it under the terms of the General Public License v2.0.
*
* Tyr 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:
* <http://www.gnu.org/licenses>
*
* This distribution is available at:
* <http://code.google.com/p/tyr/>
* <http://dev.laubenberger.net/tyr/>
*
* Contact information:
* Stefan Laubenberger
* Bullingerstrasse 53
* CH-8004 Zuerich
*
* <http://www.laubenberger.net>
*
* <laubenberger@gmail.com>
*/
package net.laubenberger.tyr.controller;
import java.io.File;
import java.io.FileFilter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.SwingUtilities;
import javax.xml.bind.JAXBException;
import net.laubenberger.bogatyr.controller.ControllerAbstract;
import net.laubenberger.bogatyr.helper.HelperArray;
import net.laubenberger.bogatyr.helper.HelperIO;
import net.laubenberger.bogatyr.helper.HelperLog;
import net.laubenberger.bogatyr.helper.HelperString;
import net.laubenberger.bogatyr.helper.HelperXml;
import net.laubenberger.bogatyr.misc.JarLoader;
import net.laubenberger.bogatyr.service.localizer.EncodingControl;
import net.laubenberger.bogatyr.service.localizer.LocalizerFile;
import net.laubenberger.bogatyr.service.property.PropertyImpl;
import net.laubenberger.bogatyr.view.swing.Menu;
import net.laubenberger.tyr.misc.Callback;
import net.laubenberger.tyr.misc.ScalableIcon;
import net.laubenberger.tyr.misc.ScalableIconImpl;
import net.laubenberger.tyr.model.FileType;
import net.laubenberger.tyr.model.ModuleConfig;
import net.laubenberger.tyr.model.ModuleConfigImpl;
import net.laubenberger.tyr.model.ModuleData;
import net.laubenberger.tyr.model.ModuleDataImpl;
import net.laubenberger.tyr.model.TyrData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The implementation of the module controller.
*
* @author Stefan Laubenberger
* @version 0.9.0 (20110527)
* @since 0.2.0
*/
public final class ControllerModuleImpl extends ControllerAbstract implements ControllerModule, Observer {
static final Logger log = LoggerFactory.getLogger(ControllerModuleImpl.class);
final ControllerTyr controller;
final TyrData data;
final Collection<ModuleAbstract> modules = new HashSet<ModuleAbstract>();
ControllerModuleImpl(final ControllerTyr controller) {
super();
if (log.isTraceEnabled()) log.trace(HelperLog.constructor(controller));
this.controller = controller;
data = controller.getData();
}
/*
* Implemented methods
*/
@Override
public Collection<Module> getModules() {
if (log.isDebugEnabled()) log.debug(HelperLog.methodStart());
final List<Module> result = new ArrayList<Module>(modules.size());
for (final Module module : modules) {
result.add(module);
}
Collections.sort(result, new Comparator<Module>() {
@Override
public int compare(final Module arg0, final Module arg1) {
return arg0.getModuleConfig().getName().compareTo(arg1.getModuleConfig().getName());
}
});
if (log.isDebugEnabled()) log.debug(HelperLog.methodExit(result));
return result;
}
@Override
public void load() {
if (log.isDebugEnabled()) log.debug(HelperLog.methodStart());
final FileFilter filter = new FileFilter() {
@Override
public boolean accept(final File file) {
return file.getName().contains(FileType.CONFIGURATION.getExtension());
}
};
// if (!data.getDirectoryData().exists()) {
// data.getDirectoryData().mkdir();
// }
// if (!data.getDirectoryDB().exists()) {
// data.getDirectoryDB().mkdir();
// }
final Collection<File> list = HelperIO.getFiles(data.getDirectoryModule(), filter);
for (final File file : list) {
try {
final ModuleConfig cm = HelperXml.deserialize(file, ModuleConfigImpl.class);
try {
final URL[] urls = new URL[cm.getJars().size()];
for (int ii = 0; ii < cm.getJars().size(); ii++) {
urls[ii] = new URL("file:" + file.getParent() + '/' + cm.getJars().get(ii)); //$NON-NLS-1$
}
final JarLoader jl = new JarLoader(urls);
try {
if (null != cm.getProperties()) {
// cm.setProperty(new PropertyImpl(jl.getResourceAsStream(cm.getProperties())));
cm.setProperty(new PropertyImpl(new File(file.getParent(), cm.getProperties())));
}
cm.setLocalizer(new LocalizerFile(cm.getLocalizerBase(), jl, new EncodingControl()));
cm.getLocalizer().setLocale(data.getLanguage().getLocale());
// read data for the module
final File tmd = new File(data.getDirectoryData(), cm.getUUID() + FileType.DATA.getExtension());
try {
ModuleData md = new ModuleDataImpl();
if (tmd.exists()) {
md = HelperXml.deserialize(tmd, ModuleDataImpl.class);
}
final ModuleAbstract module = (ModuleAbstract) jl.createInstance(cm.getModuleClass(), HelperArray
.getArray(ModuleConfig.class, ModuleData.class, Callback.class, ScalableIcon.class,
File.class), HelperArray.getArray(cm, md, controller,
new ScalableIconImpl(cm.getLogo(), cm.getLogoLarge(), jl), data.getDirectoryDB())); // TODO
// add
// large
// icon
modules.add(module);
} catch (JAXBException ex) {
log.error("Could not process module data file " + HelperString.quote(tmd.getAbsolutePath()), ex); //$NON-NLS-1$
}
} catch (Exception ex) {
log.error(
"Could not create instantiate class " + HelperString.quote(cm.getModuleClass()) + " from module configuration file " + HelperString.quote(file.getAbsolutePath()), ex); //$NON-NLS-1$//$NON-NLS-2$
}
} catch (MalformedURLException ex) {
log.error("Invalid JAR destination in module configuration file " + HelperString.quote(file.getAbsolutePath()), ex); //$NON-NLS-1$
}
} catch (JAXBException ex) {
log.error("Could not process module configuration file " + HelperString.quote(file.getAbsolutePath()), ex); //$NON-NLS-1$
}
}
if (log.isDebugEnabled()) log.debug(HelperLog.methodExit());
}
@Override
public void run() {
if (log.isDebugEnabled()) log.debug(HelperLog.methodStart());
for (final Module module : modules) {
if (module.getModuleEnabled()) {
// final Thread thread = new Thread(module);
// thread.start();
SwingUtilities.invokeLater(module);
}
}
controller.getData().addObserver(this);
if (log.isDebugEnabled()) log.debug(HelperLog.methodExit());
}
@Override
public void exit(final int returnCode) {
if (log.isDebugEnabled()) log.debug(HelperLog.methodStart());
// Store data from the modules
for (final Module module : modules) {
module.exit(returnCode);
final File tmd = new File(data.getDirectoryData(), module.getModel().getUUID() + FileType.DATA.getExtension());
try {
HelperXml.serialize(tmd, module.getModuleData());
} catch (JAXBException ex) {
log.error("Could not save the module data file " + HelperString.quote(tmd.getAbsolutePath()), ex); //$NON-NLS-1$
}
}
if (log.isDebugEnabled()) log.debug(HelperLog.methodExit());
}
@Override
public List<JMenu> getMenuItems() {
if (log.isDebugEnabled()) log.debug(HelperLog.methodStart());
List<JMenu> result = null;
if (!getModules().isEmpty()) {
result = new ArrayList<JMenu>();
for (final Module module : getModules()) {
if (module.getModuleEnabled()) {
final JMenu menu = new Menu(module.getModel().getName(), controller.getScaledIcon(module.getLogo()),
module.getModel().getName(), 0);
for (final Object item : module.getMenuItems()) {
if (item instanceof Action) {
menu.add((Action) item);
} else if (item instanceof JComponent) {
menu.add((JComponent) item);
} else {
log.warn("Unsupported object in getMenuItems() of module " + module.getModel().getName() + ": " //$NON-NLS-1$//$NON-NLS-2$
+ item);
}
}
result.add(menu);
}
}
}
if (log.isDebugEnabled()) log.debug(HelperLog.methodExit(result));
return result;
}
@Override
public void setPopupEnabled(final boolean isEnabled) {
if (log.isDebugEnabled()) log.debug(HelperLog.methodStart());
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
for (final Module module : modules) {
module.setPopupEnabled(isEnabled);
}
}
});
if (log.isDebugEnabled()) log.debug(HelperLog.methodExit());
}
@Override
public void update(final Observable o, final Object arg) {
if (log.isDebugEnabled()) log.debug(HelperLog.methodStart(o, arg));
if (TyrData.MEMBER_FONT_SIZE_OFFSET == arg) {
for (final ModuleAbstract module : modules) {
module.setFontSizeChanged();
}
} else if (TyrData.MEMBER_ICON_SIZE == arg) {
for (final ModuleAbstract module : modules) {
module.setIconSizeChanged();
}
} else if (TyrData.MEMBER_LANGUAGE == arg) {
for (final ModuleAbstract module : modules) {
module.setLocale(data.getLanguage().getLocale());
}
} else if (TyrData.MEMBER_LOOK_AND_FEEL == arg) {
for (final ModuleAbstract module : modules) {
module.setLookAndFeelChanged();
}
}
if (log.isDebugEnabled()) log.debug(HelperLog.methodExit());
}
}