/**
* Warlock, the open-source cross-platform game client
*
* Copyright 2008, Warlock LLC, and individual contributors as indicated
* by the @authors tag.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package cc.warlock.core.script.internal;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.Reader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import cc.warlock.core.client.IWarlockClientViewer;
import cc.warlock.core.configuration.WarlockConfiguration;
import cc.warlock.core.script.IFilesystemScriptProvider;
import cc.warlock.core.script.IScript;
import cc.warlock.core.script.IScriptEngine;
import cc.warlock.core.script.IScriptFileInfo;
import cc.warlock.core.script.IScriptInfo;
import cc.warlock.core.script.ScriptEngineRegistry;
import cc.warlock.core.script.configuration.ScriptConfiguration;
public class FilesystemScriptProvider implements IFilesystemScriptProvider, Runnable {
// TODO - determine if infos needs to be synchronized
protected HashMap<ScriptFileInfo, Long> infos = new HashMap<ScriptFileInfo, Long>();
protected boolean scanning = false, scanFinished = false;
protected static FilesystemScriptProvider _instance;
protected boolean forcedScan = false;
protected Thread scanningThread;
static {
ScriptEngineRegistry.addScriptProvider(instance());
WarlockConfiguration.getMainConfiguration().addConfigurationProvider(ScriptConfiguration.instance());
instance().scan();
}
public static FilesystemScriptProvider instance()
{
if (_instance == null) {
_instance = new FilesystemScriptProvider();
}
return _instance;
}
protected class ScriptFileInfo implements IScriptFileInfo, Comparable<ScriptFileInfo>
{
public String scriptName;
public File scriptFile;
public String contents;
public File getScriptFile() {
return scriptFile;
}
public String getScriptName() {
return scriptName;
}
public int compareTo(ScriptFileInfo o) {
return scriptName.compareTo(o.scriptName);
}
public String getExtension() {
if (scriptFile.getName().indexOf(".") > 0)
{
return scriptFile.getName().substring(scriptFile.getName().lastIndexOf('.') + 1);
}
return null;
}
public Reader openReader() {
try {
return new FileReader(scriptFile);
} catch (FileNotFoundException e) {
return null;
}
}
}
FilesystemScriptProvider () { }
protected void start () {
scanning = true;
scanningThread = new Thread(this);
scanningThread.start();
}
public void addScriptDirectory (File directory)
{
Set<File> scriptDirs =
ScriptConfiguration.instance().getScriptDirectories();
if (!scriptDirs.contains(directory))
scriptDirs.add(directory);
}
public void removeScriptDirectory (File directory)
{
Set<File> scriptDirs =
ScriptConfiguration.instance().getScriptDirectories();
scriptDirs.remove(directory);
}
public List<IScriptInfo> getScriptInfos() {
if (!scanning && ScriptConfiguration.instance().getAutoScan().get()) {
start();
}
return Arrays.asList(infos.keySet().toArray(new IScriptInfo[infos.keySet().size()]));
}
protected ScriptFileInfo getScriptInfo (File file)
{
for (ScriptFileInfo info : infos.keySet())
{
if (info.scriptFile.getAbsolutePath().equals(file.getAbsolutePath()))
{
return info;
}
}
return null;
}
public IScript startScript(IScriptInfo scriptInfo, IWarlockClientViewer viewer, String[] arguments) {
for (IScriptEngine engine : ScriptEngineRegistry.getScriptEngines())
{
if (engine.supports(scriptInfo))
{
return engine.startScript(scriptInfo, viewer, arguments);
}
}
return null;
}
protected void scanDirectory (File directory)
{
if (!directory.exists()) return;
for (File file : directory.listFiles())
{
if (file.isFile())
{
ScriptFileInfo info = getScriptInfo(file);
if (info == null) {
info = new ScriptFileInfo();
info.scriptFile = file;
info.scriptName = file.getName();
if (info.scriptName.indexOf('.') > 0)
{
info.scriptName = info.scriptName.substring(0, info.scriptName.indexOf('.'));
}
infos.put(info, (long) 0);
}
}
}
for (Iterator<ScriptFileInfo> iter = infos.keySet().iterator(); iter.hasNext(); )
{
ScriptFileInfo info = iter.next();
if (!info.scriptFile.exists())
iter.remove();
}
}
protected void scan ()
{
for (File dir : ScriptConfiguration.instance().getScriptDirectories())
{
if (dir.exists())
{
scanDirectory(dir);
}
}
scanFinished = true;
}
public void run ()
{
while (scanning)
{
scan();
try {
Thread.sleep(ScriptConfiguration.instance().getScanTimeout().get());
} catch (InterruptedException e) {
if (!forcedScan)
{
e.printStackTrace();
}
forcedScan = false;
}
}
}
public List<File> getScriptDirectories() {
Set<File> scriptDirs = ScriptConfiguration.instance().getScriptDirectories();
return Arrays.asList(scriptDirs.toArray(new File[scriptDirs.size()]));
}
public void forceScan() {
forcedScan = true;
scanFinished = false;
scanningThread.interrupt();
while (!scanFinished) {
try {
Thread.sleep((long)200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
@Override
protected void finalize() throws Throwable {
scanning = false;
super.finalize();
}
}