/***************************************************************************
 * Copyright 2014 Kieker Project (http://kieker-monitoring.net)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ***************************************************************************/
package kieker.webgui.common;

import java.lang.annotation.Annotation;

import kieker.analysis.AnalysisController;
import kieker.analysis.AnalysisControllerThread;
import kieker.analysis.display.HtmlText;
import kieker.analysis.display.Image;
import kieker.analysis.display.MeterGauge;
import kieker.analysis.display.PieChart;
import kieker.analysis.display.PlainText;
import kieker.analysis.display.TagCloud;
import kieker.analysis.display.XYPlot;
import kieker.analysis.display.annotation.Display;
import kieker.analysis.plugin.annotation.InputPort;
import kieker.analysis.plugin.annotation.Plugin;
import kieker.analysis.plugin.annotation.RepositoryPort;
import kieker.analysis.plugin.filter.AbstractFilterPlugin;
import kieker.analysis.plugin.filter.visualization.AbstractWebVisualizationFilterPlugin;
import kieker.analysis.plugin.reader.AbstractReaderPlugin;
import kieker.analysis.repository.AbstractRepository;
import kieker.analysis.repository.annotation.Repository;
import kieker.common.logging.LogImplWebguiLogging;
import kieker.webgui.common.exception.ReflectionException;

/**
 * This is a container which contains various classes. It uses a given class loader to load the equivalence of specific classes via the Java reflection API. This
 * makes sure that comparisons and assignments can be done correctly. The whole procedure is necessary, as every project within this application has a various number
 * of libraries and therefore another class loader. This results in multiple instances of the same class and has to be managed correctly.<br>
 * </br>
 * 
 * Not all classes and methods which are used in the web application are loaded in this container. Some other elements are accessed with the Mirror framework (which
 * simplifies the usage of the Java reflection API).
 * 
 * @author Nils Christian Ehmke
 */
public final class ClassContainer {

	private Class<?> logImplWebguiLoggingClass;
	private Class<?> analysisControllerClass;
	private Class<?> analysisControllerThreadClass;
	private Class<?> abstractRepositoryClass;
	private Class<?> abstractFilterPluginClass;
	private Class<?> abstractReaderPluginClass;
	private Class<?> abstractWebVisualizationFilterPluginClass;
	private Class<?> imageClass;
	private Class<?> plainTextClass;
	private Class<?> htmlTextClass;
	private Class<?> xyPlotClass;
	private Class<?> meterGaugeClass;
	private Class<?> tagCloudClass;
	private Class<?> pieChartClass;

	private Class<? extends Annotation> pluginAnnotationClass;
	private Class<? extends Annotation> repositoryAnnotationClass;
	private Class<? extends Annotation> inputPortAnnotationClass;
	private Class<? extends Annotation> repositoryPortAnnotationClass;
	private Class<? extends Annotation> displayAnnotationClass;

	/**
	 * Creates a new instance of this class, using the given class loader.
	 * 
	 * @param classLoader
	 *            The class loader which will be used to load all classes and determine their methods.
	 * 
	 * @throws ReflectionException
	 *             If one or more of the classes or methods for this container could not be found.
	 */
	@SuppressWarnings("unchecked")
	public ClassContainer(final ClassLoader classLoader) throws ReflectionException {
		try {
			// Load the classes
			this.logImplWebguiLoggingClass = classLoader.loadClass(LogImplWebguiLogging.class.getName());
			this.analysisControllerClass = classLoader.loadClass(AnalysisController.class.getName());
			this.analysisControllerThreadClass = classLoader.loadClass(AnalysisControllerThread.class.getName());
			this.abstractFilterPluginClass = classLoader.loadClass(AbstractFilterPlugin.class.getName());
			this.abstractReaderPluginClass = classLoader.loadClass(AbstractReaderPlugin.class.getName());
			this.abstractRepositoryClass = classLoader.loadClass(AbstractRepository.class.getName());
			this.abstractWebVisualizationFilterPluginClass = classLoader.loadClass(AbstractWebVisualizationFilterPlugin.class.getName());
			this.htmlTextClass = classLoader.loadClass(HtmlText.class.getName());
			this.plainTextClass = classLoader.loadClass(PlainText.class.getName());
			this.imageClass = classLoader.loadClass(Image.class.getName());
			this.xyPlotClass = classLoader.loadClass(XYPlot.class.getName());
			this.meterGaugeClass = classLoader.loadClass(MeterGauge.class.getName());
			this.tagCloudClass = classLoader.loadClass(TagCloud.class.getName());
			this.pieChartClass = classLoader.loadClass(PieChart.class.getName());

			// Now we load the more specific annotation classes
			this.pluginAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(Plugin.class.getName());
			this.repositoryAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(Repository.class.getName());
			this.inputPortAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(InputPort.class.getName());
			this.repositoryPortAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(RepositoryPort.class.getName());
			this.displayAnnotationClass = (Class<? extends Annotation>) classLoader.loadClass(Display.class.getName());

		} catch (final ClassNotFoundException ex) {
			// Something went wrong. We can do nothing except throwing an exception
			throw new ReflectionException("An error occured while loading the classes", ex);
		}
	}

	public Class<?> getAbstractFilterPluginClass() {
		return this.abstractFilterPluginClass;
	}

	public Class<?> getAbstractReaderPluginClass() {
		return this.abstractReaderPluginClass;
	}

	public Class<? extends Annotation> getPluginAnnotationClass() {
		return this.pluginAnnotationClass;
	}

	public Class<? extends Annotation> getRepositoryAnnotationClass() {
		return this.repositoryAnnotationClass;
	}

	public Class<? extends Annotation> getInputPortAnnotationClass() {
		return this.inputPortAnnotationClass;
	}

	public Class<? extends Annotation> getRepositoryPortAnnotationClass() {
		return this.repositoryPortAnnotationClass;
	}

	public Class<? extends Annotation> getDisplayAnnotationClass() {
		return this.displayAnnotationClass;
	}

	public Class<?> getAbstractRepositoryClass() {
		return this.abstractRepositoryClass;
	}

	public Class<?> getImageClass() {
		return this.imageClass;
	}

	public Class<?> getPlainTextClass() {
		return this.plainTextClass;
	}

	public Class<?> getHtmlTextClass() {
		return this.htmlTextClass;
	}

	public Class<?> getAnalysisControllerClass() {
		return this.analysisControllerClass;
	}

	public Class<?> getAnalysisControllerThreadClass() {
		return this.analysisControllerThreadClass;
	}

	public Class<?> getLogImplWebguiLoggingClass() {
		return this.logImplWebguiLoggingClass;
	}

	public Class<?> getXYPlotClass() {
		return this.xyPlotClass;
	}

	public Class<?> getMeterGaugeClass() {
		return this.meterGaugeClass;
	}

	public Class<?> getTagCloudClass() {
		return this.tagCloudClass;
	}

	public Class<?> getPieChartClass() {
		return this.pieChartClass;
	}

	public Class<?> getAbstractWebVisualizationFilterPluginClass() {
		return this.abstractWebVisualizationFilterPluginClass;
	}

}
