package pl.shockah.shocky;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.pircbotx.PircBotX;
import org.pircbotx.User;
import pl.shockah.shocky.cmds.CommandCallback;
import pl.shockah.shocky.interfaces.IAcceptURLs;
import pl.shockah.shocky.interfaces.IModule;
public abstract class Module extends ListenerAdapter implements IModule, Comparable<Module> {
private static final List<Module> modules = Collections.synchronizedList(new ArrayList<Module>());
private static final List<ModuleLoader> loaders = Collections.synchronizedList(new ArrayList<ModuleLoader>());
private static final Map<String, ScriptModule> scriptingModules = Collections.synchronizedMap(new HashMap<String,ScriptModule>());
private static final LinkedList<Module> needsInit = new LinkedList<Module>();
private boolean enabled = false;
private final List<String> disabledChannnels = Collections.synchronizedList(new LinkedList<String>());
static {
Module.registerModuleLoader(new ModuleLoader.Java());
}
public static void registerModuleLoader(ModuleLoader loader) {
if (loaders.contains(loader)) loaders.remove(loader);
loaders.add(loader);
}
public static void unregisterModuleLoader(ModuleLoader loader) {
if (loaders.contains(loader)) {
loader.unloadAllModules();
loaders.remove(loader);
}
}
private static void setup(Module module, ModuleLoader loader, ModuleSource<?> source) {
module.loader = loader;
module.source = source;
}
public static Module load(ModuleSource<?> source) {
Module module = null;
for (int i = 0; i < loaders.size(); i++) {
if (loaders.get(i).accept(source)) module = loaders.get(i).loadModule(source);
if (module != null) {
setup(module,loaders.get(i),source);
break;
}
}
if (module != null) {
for (int i = 0; i < modules.size(); i++) if (modules.get(i).name().equals(module.name())) {
module.loader.unloadModule(module);
return null;
}
modules.add(module);
needsInit.push(module);
if (module instanceof ScriptModule) {
ScriptModule sModule = (ScriptModule)module;
scriptingModules.put(sModule.identifier(), sModule);
}
}
return module;
}
public static void postLoad() {
synchronized (needsInit) {
while (!needsInit.isEmpty()) {
Module module = needsInit.pop();
String name = "module-"+module.name();
Data.config.setNotExists(name,true);
if (Data.config.getBoolean(name))
module.enable(null);
for (String key : Data.config.getKeysSubconfigs())
if (key.startsWith("#")&&!Data.forChannel(key).getBoolean(name))
module.disable(key);
}
}
}
public final boolean unload() {
if (!modules.contains(this))
return false;
if (this.enabled)
this.disable(null);
modules.remove(this);
if (this instanceof ScriptModule)
scriptingModules.remove(((ScriptModule)this).identifier());
this.loader.unloadModule(this);
return true;
}
public final boolean reload() {
ModuleSource<?> src = this.source;
this.unload();
boolean ret = load(src) != null;
postLoad();
return ret;
}
public final boolean enable(String channel) {
if (channel != null) {
return disabledChannnels.remove(channel);
} else {
if (this.enabled)
return false;
this.onEnable(Data.lastSave);
if (this.isListener())
Shocky.getBotManager().getListenerManager().addListener(this);
if (this instanceof IAcceptURLs)
URLDispatcher.addHandler((IAcceptURLs)this);
this.enabled = true;
return true;
}
}
public final boolean disable(String channel) {
if (channel != null) {
if (disabledChannnels.contains(channel))
return false;
return disabledChannnels.add(channel);
} else {
if (!this.enabled)
return false;
if (this instanceof IAcceptURLs)
URLDispatcher.removeHandler((IAcceptURLs)this);
if (this.isListener())
Shocky.getBotManager().getListenerManager().removeListener(this);
this.onDataSave(Data.lastSave);
this.onDisable();
this.enabled = false;
return true;
}
}
public static ArrayList<Module> loadNewModules() {
ArrayList<Module> ret = new ArrayList<Module>();
File dir = new File("modules"); dir.mkdir();
for (File f : dir.listFiles()) {
if (f.isDirectory()) continue;
Module m = load(new ModuleSource<File>(f));
if (m != null) ret.add(m);
}
Module.postLoad();
Collections.sort(ret);
return ret;
}
public static Module getModule(String name) {
for (int i = 0; i < modules.size(); i++)
if (modules.get(i).name().equals(name)) return modules.get(i);
return null;
}
public static ArrayList<Module> getModules() {
ArrayList<Module> ret = new ArrayList<Module>(modules);
Collections.sort(ret);
return ret;
}
public static ArrayList<Module> getModules(boolean enabled) {
ArrayList<Module> ret = new ArrayList<Module>(modules.size());
for (int i = modules.size()-1; i >= 0; --i) {
Module m = modules.get(i);
if (m.enabled == enabled)
ret.add(m);
}
Collections.sort(ret);
return ret;
}
public static ScriptModule getScriptingModule(String id) {
if (scriptingModules.containsKey(id))
return scriptingModules.get(id);
return null;
}
public File[] getReadableFiles() {
return new File[0];
}
private ModuleLoader loader;
private ModuleSource<?> source;
public abstract String name();
public void onEnable(File dir) {}
public void onDisable() {}
public void onDie(PircBotX bot) {}
public void onDataSave(File dir) {}
public void onCleanup(PircBotX bot, CommandCallback callback, User sender) {}
public boolean isListener() {return false;}
public final boolean isEnabled(String channel) {
if (this.disabledChannnels.contains(channel))
return false;
return this.enabled;
}
public final int compareTo(Module module) {
return name().compareTo(module.name());
}
}