/***************************************************************************
 * 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.persistence;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.List;

import kieker.analysis.model.analysisMetaModel.MIProject;
import kieker.webgui.common.ClassContainer;
import kieker.webgui.common.exception.NewerProjectException;
import kieker.webgui.common.exception.ProjectAlreadyExistingException;
import kieker.webgui.common.exception.ProjectNotExistingException;
import kieker.webgui.domain.ComponentListContainer;

import org.primefaces.model.UploadedFile;

import org.springframework.security.access.prepost.PreAuthorize;

/**
 * This is the interface for the data access object(s) which will access for example the file system to manage the available projects.
 * 
 * @author Nils Christian Ehmke
 */
public interface IProjectDAO {

	/**
	 * This method adds a new project to the application. It creates an empty, but nevertheless valid kax-file to the file system. If the method fails due to an
	 * {@link IOException}, it will make sure that the project-directories will be removed as if the method would never have been called.
	 * 
	 * @param projectName
	 *            The name of the new project.
	 * @param username
	 *            The name of the user who created the project.
	 * 
	 * @throws ProjectAlreadyExistingException
	 *             If a project with the same name exists already.
	 * @throws IOException
	 *             If something went wrong during the creation of the project.
	 */
	@PreAuthorize("hasAnyRole('User', 'Administrator')")
	public void addProject(String projectName, String username) throws ProjectAlreadyExistingException, IOException;

	/**
	 * This method removes the given project from the application. This is done by simply removing the whole project directory. It is possible that this action fails
	 * for various reasons - in this cases it is not guaranteed that the project is still in a valid state.
	 * 
	 * @param projectName
	 *            The name of the project.
	 * 
	 * @throws IOException
	 *             If something went wrong during the removing.
	 * @throws ProjectNotExistingException
	 *             If a project with the given name does not exist.
	 */
	@PreAuthorize("hasAnyRole('User', 'Administrator')")
	public void removeProject(String projectName) throws IOException, ProjectNotExistingException;

	/**
	 * This method imports an existing kax-file into the application. If the given project name does already exist, the application will not try to upload it in the
	 * first place.
	 * 
	 * @param projectName
	 *            The name of the new project.
	 * @param username
	 *            The name of the user who imported the project.
	 * @param file
	 *            The kax file to be uploaded.
	 * 
	 * @throws ProjectAlreadyExistingException
	 *             If a project with the same name exists already.
	 * @throws IOException
	 *             If something went wrong during the creation of the project or the uploading of the file.
	 */
	@PreAuthorize("hasAnyRole('User', 'Administrator')")
	public void importProject(String projectName, String username, UploadedFile file) throws ProjectAlreadyExistingException, IOException;

	/**
	 * This method makes a copy of a project and saves it under another name. If the method fails due to an {@link IOException}, it will make sure that the
	 * project-directories of the destination-project will be removed as if the method would never have been called.
	 * 
	 * @param originalProjectName
	 *            The name of the source project.
	 * @param newProjectName
	 *            The name of the target project.
	 * 
	 * @throws ProjectNotExistingException
	 *             If a project with the given (source) name doesn't exist.
	 * @throws ProjectAlreadyExistingException
	 *             If a project with the same (target) name exists already.
	 * @throws IOException
	 *             If something went wrong during the creation of the target-project or during the loading of the source-project.
	 */
	@PreAuthorize("hasAnyRole('User', 'Administrator')")
	public void copyProject(String originalProjectName, String newProjectName) throws ProjectNotExistingException, ProjectAlreadyExistingException,
			IOException;

	/**
	 * This method loads the kax-file for the given project name and delivers an initializes instance of {@link MIProject}.
	 * 
	 * @param projectName
	 *            The name of the project to be loaded.
	 * 
	 * @return The model instance as defined by the corresponding kax-file.
	 * 
	 * @throws ProjectNotExistingException
	 *             If a project with the given (source) name doesn't exist.
	 * @throws IOException
	 *             If something went wrong during the opening of the project.
	 */
	@PreAuthorize("isAuthenticated()")
	public MIProject loadProject(String projectName) throws ProjectNotExistingException, IOException;

	/**
	 * This method loads the kax-file for the given project name and delivers an initializes instance of {@link MIProject} - but instead of using the "normal" class
	 * loader, it uses the methods and classes stored in the given instance of {@link ClassContainer}. This means that this method <b>does</b> return an
	 * instance of {@link MIProject}, but the one defined in the container. This is also the reason why this method has to return an {@link Object}-instance.
	 * 
	 * @param projectName
	 *            The name of the project to be loaded.
	 * @param classAndMethodContainer
	 *            The container, which will be used to load the project instance.
	 * 
	 * @return The model instance as defined by the corresponding kax-file.
	 * 
	 * @throws ProjectNotExistingException
	 *             If a project with the given (source) name doesn't exist.
	 * @throws IOException
	 *             If something went wrong during the opening of the project. This can also mean that the given {@link ClassContainer} is somehow invalid.
	 */
	@PreAuthorize("isAuthenticated()")
	public Object loadProject(String projectName, ClassContainer classAndMethodContainer) throws ProjectNotExistingException, IOException;

	/**
	 * This method tries to save the given model instance for the given project. The given time stamp will be compared (if the corresponding flag says so) with the
	 * current time stamp of the project. If the project on the file system has been modified in the meantime, a {@link NewerProjectException} will be thrown. If
	 * something goes wrong during the storage, it is <b>not</b> guaranteed that the resulting file will be valid.
	 * 
	 * @param projectName
	 *            The name of the project which has to be saved.
	 * @param project
	 *            The model instance to be stored in the corresponding kax-file.
	 * @param timeStamp
	 *            The time stamp which has to be compared with the "real" time stamp of the project.
	 * @param overwriteNewerProject
	 *            Determines whether a newer project file will be overwritten without further warning or not.
	 * @param username
	 *            The name of the user who saves the project.
	 * @param analysisLayout
	 *            The current layout of the analysis graph. It is valid if this parameter is null. In this case the stored layout will not be changed.
	 * @param cockpitLayout
	 *            The current layout of the cockpit. It is valid if this parameter is null. In this case the stored layout will not be changed.
	 * 
	 * @throws ProjectNotExistingException
	 *             If a project with the given name does not exist.
	 * @throws IOException
	 *             If something went wrong during the storage of the model instance.
	 * @throws NewerProjectException
	 *             If the project on the file system is newer and the overwriteNewerProject-flag has not been set.
	 */
	@PreAuthorize("hasAnyRole('User', 'Administrator')")
	public void saveProject(String projectName, MIProject project, long timeStamp, boolean overwriteNewerProject, String username, // NOPMD (String parameters)
			String analysisLayout, String cockpitLayout) throws ProjectNotExistingException, IOException, NewerProjectException;

	/**
	 * Delivers the current time stamp of the given project.
	 * 
	 * @param projectName
	 *            The name of the project whose time stamp will be delivered.
	 * 
	 * @return The current time stamp.
	 * 
	 * @throws ProjectNotExistingException
	 *             If a project with the given name does not exist.
	 */
	@PreAuthorize("isAuthenticated()")
	public long getCurrTimeStamp(String projectName) throws ProjectNotExistingException;

	/**
	 * This method tries to upload a dependency to the given project. AN existing version will be overwritten.
	 * 
	 * @param file
	 *            The file to be uploaded to the project.
	 * @param projectName
	 *            The name of the project.
	 * 
	 * @throws ProjectNotExistingException
	 *             If a project with the given name does not exist.
	 * @throws IOException
	 *             If something went wrong during the uploading.
	 */
	@PreAuthorize("hasAnyRole('User', 'Administrator')")
	public void uploadLibrary(UploadedFile file, String projectName) throws ProjectNotExistingException, IOException;

	/**
	 * This method delivers a class loader containing the currently available libraries of the given project.
	 * 
	 * @param projectName
	 *            The name of the project.
	 * @param requester
	 *            The requester of the classloader.
	 * 
	 * @return A class loader for the given project.
	 * 
	 * @throws ProjectNotExistingException
	 *             If a project with the given name does not exist.
	 * @throws IOException
	 *             If something went wrong during the initialization of the class loader.
	 */
	@PreAuthorize("isAuthenticated()")
	public ClassLoader getClassLoader(String projectName, Object requester) throws ProjectNotExistingException, IOException;

	/**
	 * This method lists all available libraries of the given project.
	 * 
	 * @param projectName
	 *            The name of the project whose libraries have to be delivered.
	 * 
	 * @return A list containing all available library-names of the project.
	 * 
	 * @throws ProjectNotExistingException
	 *             If a project with the given name does not exist.
	 */
	@PreAuthorize("isAuthenticated()")
	public List<String> listAllLibraries(String projectName) throws ProjectNotExistingException;

	/**
	 * This method lists all available projects on the file system. This method is not secured with an annotation, as one of the services needs it only during
	 * initialization. It should not be called during normal runtime.
	 * 
	 * @return A list containing all available project names.
	 */
	public Collection<String> listAllProjects();

	/**
	 * Delivers the kax-file for the given project.
	 * 
	 * @param projectName
	 *            The name of the project.
	 * 
	 * @return The kax-file of the project.
	 */
	@PreAuthorize("isAuthenticated()")
	public File getProjectFile(String projectName);

	/**
	 * Deletes the given library of the given project.
	 * 
	 * @param projectName
	 *            The name of the project.
	 * @param libName
	 *            The name of the library.
	 * 
	 * @return true if and only if the given library has been removed.
	 * 
	 * @throws IOException
	 *             If something went wrong during the reloading of the components.
	 * @throws ProjectNotExistingException
	 *             If a project with the given name does not exist.
	 */
	@PreAuthorize("hasAnyRole('User', 'Administrator')")
	public boolean deleteLibrary(String projectName, String libName) throws IOException, ProjectNotExistingException;

	/**
	 * Delivers the available components (readers, filters and repositories) for the given project.
	 * 
	 * @param project
	 *            The project whose components should be loaded.
	 * 
	 * @return An object containing the available components as model instances.
	 */
	@PreAuthorize("isAuthenticated()")
	public ComponentListContainer getAvailableComponents(String project);

	/**
	 * Delivers the owner of the given project or a substitution if the meta data is corrupt or missing.
	 * 
	 * @param projectName
	 *            The name of the project whose owner should be delivered.
	 * 
	 * @return The owner (creator) of the project.
	 */
	@PreAuthorize("isAuthenticated()")
	public String getOwner(String projectName);

	/**
	 * Delivers the last user of the given project or a substitution if the meta data is corrupt or missing.
	 * 
	 * @param projectName
	 *            The name of the project whose last user should be delivered.
	 * 
	 * @return The last user of the project.
	 */
	@PreAuthorize("isAuthenticated()")
	public String getLastUser(String projectName);

	/**
	 * Delivers the stored analysis layout for the given project.
	 * 
	 * @param projectName
	 *            The name of the project.
	 * 
	 * @return The layout string as it is stored within the meta data. If this isn't available, null will be returned.
	 */
	@PreAuthorize("isAuthenticated()")
	public String getAnalysisLayout(String projectName);

	/**
	 * Delivers the stored cockpit layout for the given project.
	 * 
	 * @param projectName
	 *            The name of the project.
	 * 
	 * @return The layout string as it is stored within the meta data. If this isn't available, null will be returned.
	 */
	@PreAuthorize("isAuthenticated()")
	public String getCockpitLayout(String projectName);

}
