package org.bimserver.plugins;

/******************************************************************************
 * Copyright (C) 2009-2015  BIMserver.org
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero 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 Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *****************************************************************************/

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileManager;
import javax.tools.ToolProvider;

import org.bimserver.models.store.Parameter;
import org.bimserver.plugins.web.WebModulePlugin;

public class PluginContext {

	private final PluginManager pluginManager;
	private final ClassLoader classLoader;
	private final PluginSourceType pluginType;
	private final String location;
	private final Plugin plugin;
	private final PluginImplementation pluginImplementation;
	private final String classLocation;
	private boolean enabled = true;
	private JavaFileManager javaFileManager;
	private FileSystem filesystem;
	private Path rootPath;

	public PluginContext(PluginManager pluginManager, ClassLoader classLoader, PluginSourceType pluginType, String location, Plugin plugin, PluginImplementation pluginImplementation, String classLocation) throws IOException {
		this.pluginManager = pluginManager;
		this.classLoader = classLoader;
		this.pluginType = pluginType;
		this.location = location;
		this.plugin = plugin;
		this.pluginImplementation = pluginImplementation;
		this.classLocation = classLocation;
		switch (pluginType) {
		case ECLIPSE_PROJECT:
			filesystem = FileSystems.getDefault();
			rootPath = filesystem.getPath(location);
			break;
		case INTERNAL:
			break;
		case JAR_FILE:
			URI uri = URI.create("jar:" + new File(location).toURI());
			System.out.println(uri);
			Map<String, String> env = new HashMap<>();
			env.put("create", "true");
			filesystem = FileSystems.newFileSystem(uri, env, null);
			rootPath = filesystem.getPath("/");
			break;
		default:
			break;
		}
	}
	
	public PluginSourceType getPluginType() {
		return pluginType;
	}

	public Plugin getPlugin() {
		return plugin;
	}

	public String getLocation() {
		return location;
	}

	public void setEnabled(boolean enabled, boolean notify) {
		this.enabled = enabled;
		if (notify) {
			pluginManager.notifyPluginStateChange(this, enabled);
		}
	}

	public boolean isEnabled() {
		return enabled;
	}

	public InputStream getResourceAsInputStream(String name) throws FileNotFoundException {
		InputStream resourceAsStream = classLoader.getResourceAsStream(name);
		if (resourceAsStream == null) {
			File file = new File(location + File.separator + name);
			if (file.exists()) {
				resourceAsStream = new FileInputStream(file);
			}
		}
		if (resourceAsStream == null && !pluginImplementation.getRequires().isEmpty()) {
			for (String dep : pluginImplementation.getRequires()) {
				WebModulePlugin webModulePlugin = pluginManager.getWebModulePlugin(dep, true);
				InputStream resourceAsInputStream = pluginManager.getPluginContext(webModulePlugin).getResourceAsInputStream(name);
				if (resourceAsInputStream != null) {
					return resourceAsInputStream;
				}
			}
		}
		return resourceAsStream;
	}

	public URL getResourceAsUrl(String name) {
		return classLoader.getResource(name);
	}

	public String getClassLocation() {
		return classLocation;
	}

	public ClassLoader getClassLoader() {
		return classLoader;
	}

	public JavaFileManager getFileManager() {
		JavaCompiler systemJavaCompiler = ToolProvider.getSystemJavaCompiler();
		if (systemJavaCompiler == null) {
			throw new RuntimeException("JDK needed");
		}
		switch (pluginType) {
		case ECLIPSE_PROJECT:
			this.javaFileManager = new EclipseProjectPluginFileManager(systemJavaCompiler.getStandardFileManager(null, null, null), classLoader, new File(location, "bin"));
			break;
		case INTERNAL:
			this.javaFileManager = systemJavaCompiler.getStandardFileManager(null, null, null);
			break;
		case JAR_FILE:
			this.javaFileManager = new VirtualFileManager2(systemJavaCompiler.getStandardFileManager(null, null, null), classLoader, filesystem, rootPath);
			break;
		default:
			break;
		}
		return javaFileManager;
	}

	public Path getRootPath() {
		return rootPath;
	}
	
	public FileSystem getFilesystem() {
		return filesystem;
	}

	public Parameter getParameter(String name) {
		return pluginManager.getParameter(this, name);
	}
	
	public PluginImplementation getPluginImplementation() {
		return pluginImplementation;
	}
}
@@ -1462,16 +1462,93 @@
 text %7B%0A%0A
+%09private static final Map%3CString, FileSystem%3E fileSystems = new HashMap%3C%3E();%0A
 %09private
@@ -1919,25 +1919,25 @@
 eSystem file
-s
+S
 ystem;%0A%09priv
@@ -2472,33 +2472,33 @@
 PROJECT:%0A%09%09%09file
-s
+S
 ystem = FileSyst
@@ -2525,33 +2525,33 @@
 %09rootPath = file
-s
+S
 ystem.getPath(lo
@@ -2613,16 +2613,89 @@
 R_FILE:%0A
+%09%09%09fileSystem = fileSystems.get(location);%0A%09%09%09if (fileSystem == null) %7B%0A%09
 %09%09%09URI u
@@ -2753,35 +2753,8 @@
 );%0A%09
-%09%09System.out.println(uri);%0A
 %09%09%09M
@@ -2798,16 +2798,17 @@
 %3E();%0A%09%09%09
+%09
 env.put(
@@ -2829,21 +2829,22 @@
 e%22);%0A%09%09%09
+%09
 file
-s
+S
 ystem = 
@@ -2886,16 +2886,64 @@
  null);%0A
+%09%09%09%09fileSystems.put(location, fileSystem);%0A%09%09%09%7D%0A
 %09%09%09rootP
@@ -2948,25 +2948,25 @@
 tPath = file
-s
+S
 ystem.getPat
@@ -5103,25 +5103,25 @@
 Loader, file
-s
+S
 ystem, rootP
@@ -5294,17 +5294,17 @@
 urn file
-s
+S
 ystem;%0A%09

work in progress