/**
* OLAT - Online Learning and Training<br>
* http://www.olat.org
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
* University of Zurich, Switzerland.
* <hr>
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* This file has been modified by the OpenOLAT community. Changes are licensed
* under the Apache 2.0 license as the original file.
*/

package org.olat.course.nodes;

import java.io.File;
import java.util.List;
import java.util.Locale;
import java.util.zip.ZipOutputStream;

import org.olat.core.gui.ShortName;
import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.stack.BreadcrumbPanel;
import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.generic.tabbable.TabbableController;
import org.olat.core.id.Identity;
import org.olat.core.util.nodes.INode;
import org.olat.course.ICourse;
import org.olat.course.condition.Condition;
import org.olat.course.condition.interpreter.ConditionExpression;
import org.olat.course.condition.interpreter.ConditionInterpreter;
import org.olat.course.editor.CourseEditorEnv;
import org.olat.course.editor.PublishEvents;
import org.olat.course.editor.StatusDescription;
import org.olat.course.export.CourseEnvironmentMapper;
import org.olat.course.run.navigation.NodeRunConstructionResult;
import org.olat.course.run.userview.NodeEvaluation;
import org.olat.course.run.userview.TreeEvaluation;
import org.olat.course.run.userview.TreeFilter;
import org.olat.course.run.userview.UserCourseEnvironment;
import org.olat.course.statistic.StatisticResourceOption;
import org.olat.course.statistic.StatisticResourceResult;
import org.olat.ims.qti.statistics.QTIType;
import org.olat.modules.ModuleConfiguration;
import org.olat.repository.RepositoryEntry;

/**
 * Initial Date: Feb 9, 2004
 * @author Felix Jost
 * @author BPS (<a href="http://www.bps-system.de/">BPS Bildungsportal Sachsen GmbH</a>)
 */
public interface CourseNode extends INode, ShortName {
	
	public static final String DISPLAY_OPTS_SHORT_TITLE_DESCRIPTION_CONTENT = "shorttitle+desc+content";
	public static final String DISPLAY_OPTS_TITLE_DESCRIPTION_CONTENT = "title+desc+content";
	public static final String DISPLAY_OPTS_SHORT_TITLE_CONTENT = "shorttitle+content";
	public static final String DISPLAY_OPTS_TITLE_CONTENT = "title+content";
	public static final String DISPLAY_OPTS_CONTENT = "content";

	/**
	 * @return String
	 */
	public String getLearningObjectives();

	/**
	 * @return String
	 */
	public String getLongTitle();

	/**
	 * @return String
	 */
	public String getShortTitle();
	
	/**
	 * @return String
	 */
	public String getDisplayOption();

	/**
	 * @return String
	 */
	public String getType();

	/**
	 * Set this node's ident.
	 * 
	 * @param ident
	 */
	public void setIdent(String ident);

	/**
	 * Sets the learningObjectives.
	 * 
	 * @param learningObjectives The learningObjectives to set
	 */
	public void setLearningObjectives(String learningObjectives);

	/**
	 * Sets the longTitle.
	 * 
	 * @param longTitle The longTitle to set
	 */
	public void setLongTitle(String longTitle);

	/**
	 * Sets the shortTitle.
	 * 
	 * @param shortTitle The shortTitle to set
	 */
	public void setShortTitle(String shortTitle);
	
	/**
	 * Set display option
	 * @param displayOption
	 */
	public void setDisplayOption(String displayOption);

	/**
	 * Set the text that will show up when no access is granted to this node but
	 * the node is still visible to the user
	 * 
	 * @param noAccessExplanation
	 */
	public void setNoAccessExplanation(String noAccessExplanation);

	/**
	 * Get the text that will show up when no access is granted to this node but
	 * the node is still visible to the user
	 * 
	 * @return String
	 */
	public String getNoAccessExplanation();

	/**
	 * Set the visibility precondition. If this condition is true, the node is
	 * visible to the user
	 * 
	 * @param visibilityCondition
	 */
	public void setPreConditionVisibility(Condition visibilityCondition);

	/**
	 * Get the visibility precondition. If this condition is true, the node is
	 * visible to the user
	 * 
	 * @return String
	 */
	public Condition getPreConditionVisibility();

	/**
	 * Get the access precondition. If this condition is true, the node is
	 * accessable for the user
	 * 
	 * @return String
	 */
	public Condition getPreConditionAccess();

	/**
	 * used by the publish process to ensure the reference counters for a
	 * repository entry are correct. (you can only delete Repositoryentries if
	 * there are no references to it) returns exception when called even
	 * !needsReferenceToARespositoryEntry return the referenced RepositoryEntry if
	 * it can be found return null if the referenced RepositoryEntry could not be
	 * found
	 * 
	 * @return the RepositoryEntry (if it still exists in the repository) which is
	 *         referenced in this course node if there is a reference, or null
	 *         otherwise
	 */
	public RepositoryEntry getReferencedRepositoryEntry();

	/**
	 * @return true if this node type potentially has a repository entry
	 *         reference, false otherwhise. Attention: this method does not test
	 *         if ther is actually such a reference. Use getReferencedRepository()
	 *         to get this information.
	 */
	public boolean needsReferenceToARepositoryEntry();

	/**
	 * special configuration, used by the module, e.g. briefcase: quota,
	 * singlepage:chosen file, tunneling: chosen site, etc.
	 * 
	 * @return ModuleConfiguration
	 */
	public ModuleConfiguration getModuleConfiguration();

	/**
	 * Create a course run controller for this node
	 * 
	 * @param ureq The user request
	 * @param wControl The current window controller
	 * @param userCourseEnv The course environment
	 * @param ne The node evaluation
	 * @return The node run controller
	 * 
	 * ATTENTION:
	 * udpateModuleConfigDefaults(false) should be called inside from the
	 * courseNode.createNodeRunConstructionResult(ureq, bwControl, userCourseEnv, nodeEval, nodecmd)
	 * to set the course node specific configuration default values!
	 */
	public NodeRunConstructionResult createNodeRunConstructionResult(UserRequest ureq, WindowControl wControl,
			UserCourseEnvironment userCourseEnv, NodeEvaluation ne, String nodecmd);

	/**
	 * Create a node edit controller for this node to configure node specific
	 * features
	 * 
	 * @param ureq The user request
	 * @param wControl The current window controller
	 * @param course The course
	 * @param euce the editor user course environment provides syntax/semantic
	 *          check methods for conditions
	 * @return A tabbable node edit controller
	 */
	public TabbableController createEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, ICourse course, UserCourseEnvironment euce);

	/**
	 * @param ureq
	 * @param wControl
	 * @param userCourseEnv
	 * @param ne
	 * @return Controller
	 */
	public Controller createPreviewController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv, NodeEvaluation ne);

	/**
	 * Create a minimised view for this course node that gives some insight about
	 * the real content of the view in a limited space. E.g. a forum could list
	 * the two most recent postings or active threads, a folder could show the
	 * newest files.
	 * 
	 * @param ureq
	 * @param wContro
	 * @param userCourseEnv
	 * @param ne
	 * @return 
	 */
	public Controller createPeekViewRunController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv, NodeEvaluation ne);
	
	/**
	 * Return a construct with all the informations needed to build the statistics of
	 * a course node.
	 * 
	 * @param ureq
	 * @param wControl
	 * @param userCourseEnv
	 * @param options
	 * @return
	 */
	public StatisticResourceResult createStatisticNodeResult(UserRequest ureq, WindowControl wControl,
			UserCourseEnvironment userCourseEnv, StatisticResourceOption options, QTIType... type);
	
	public boolean isStatisticNodeResultAvailable(UserCourseEnvironment userCourseEnv, QTIType... type);
	
	/**
	 * this method must generate a nodeevaluation and take care of (if any) child
	 * nodeevaluations. A nodeevaluation is done in the context of ci (an
	 * interpreter per user is needed at the moment) and a treeeval
	 * 
	 * @param ci
	 * @param treeEval
	 * @return NodeEvaluation
	 */
	public NodeEvaluation eval(ConditionInterpreter ci, TreeEvaluation treeEval, TreeFilter filter);

	/**
	 * @return true if the course node configuration is correct without the course
	 *         context.
	 * @see CourseNode#isConfigValid(UserCourseEnvironment) for a config
	 *      validation method taking the course environment into account.
	 */
	public StatusDescription isConfigValid();

	/**
	 * @param userCourseEnv
	 * @return true if the course node configuration is valid for itself and also
	 *         within the specified course environment.
	 */
	public StatusDescription[] isConfigValid(CourseEditorEnv cev);
	
	
	public void updateOnPublish(Locale locale, ICourse course, Identity publisher, PublishEvents publishEvents);

	/**
	 * Called if this node is ABOUT TO BE deleted. For the time being, the node
	 * may provide a user message which is shown to the user within the publish
	 * confirm dialog.
	 * 
	 * @param ureq The user request
	 * @param course The course
	 * @return The dialogue message if any data will be deleted in the next step
	 */
	public String informOnDelete(Locale locale, ICourse course);

	/**
	 * Called if this node is deleted. Do any cleanup work here.
	 * 
	 * @param course The course
	 */
	public void cleanupOnDelete(ICourse course);

	/**
	 * Archive all node user data to the given directory. This might be one file
	 * or multiple files depending on what data is available. The archived data is
	 * not intendet to be imported again. The files should be viewable, e.g. as
	 * XML or excel files.
	 * 
	 * @param locale The users locale
	 * @param course The course
	 * @param exportStream The directory where the exported files should be
	 *          put. This directory must exist prior to calling this method.
	 * @param value of charset property of current user
	 * @return true if any data to be archived was found, false otherwise.
	 */
	public boolean archiveNodeData(Locale locale, ICourse course, ArchiveOptions options, ZipOutputStream out, String charset);

	/**
	 * Export all node user data to the given directory. This might be one file or
	 * multiple files depending on what data is available. The archived data is
	 * intendet to be imported again if the course this node is attached to gets
	 * imported.
	 * 
	 * @param exportDirectory The directory where the exported files should be
	 *          put. This directory must exist prior to calling this method.
	 * @param course
	 */
	public void exportNode(File exportDirectory, ICourse course);

	/**
	 * Import a course node's data. The import directory is the root of the
	 * directory with all the data that the node has written previousely during
	 * the export. The node can provide a Controller if any user intervention is
	 * needed. The controller should send a Event.DONE_EVENT after finishing the
	 * user driven import. If no user driven import is necessary, just return null
	 * right away after finishing all importing tasks.
	 * 
	 * @param importDirectory
	 * @param course
	 * @param owner 
	 * @param locale 
	 * @param withReferences 
	 * @param ureq
	 * @param wControl
	 * @return Controller for user driven import, or null after all import tasks
	 *         have finished.
	 */
	public void importNode(File importDirectory, ICourse course, Identity owner, Locale locale, boolean withReferences);
	
	/**
	 * Remap the node to the context of the course after import.
	 * @param sourceCrourse
	 * @param sourceCourse 
	 */
	public void postCopy(CourseEnvironmentMapper envMapper, Processing type, ICourse course, ICourse sourceCrourse);
	
	/**
	 * Remap the node to the context of the course after import.
	 */
	public void postImport(File importDirectory, ICourse course, CourseEnvironmentMapper envMapper, Processing type);
	
	/**
	 * 
	 */
	public void postExport(CourseEnvironmentMapper envMapper, boolean backwardsCompatible);

	
	/**
	 * Try to copy the configuration of this course node to
	 * the one passed as parameter. Warning, the 2 nodes can
	 * be from different types.
	 * @param courseNode
	 */
	public void copyConfigurationTo(CourseNode courseNode, ICourse course);
	
	/**
	 * Create an instance for the copy process. The copy must have a different
	 * unique ID and may take some of the configuration values configured for this
	 * node.
	 * 
	 * @param isNewTitle
	 * @param course the course in which the copying is happening
	 * @return
	 */
	public CourseNode createInstanceForCopy(boolean isNewTitle, ICourse course, Identity author);

	/**
	 * @return empty list, or list with active condition expressions of the course
	 *         node
	 */
	public List<ConditionExpression> getConditionExpressions();

	/**
	 * explain what the given status description means in the publish environment
	 * 
	 * @param description
	 * @return
	 */
	public StatusDescription explainThisDuringPublish(StatusDescription description);
	
	/**
	 * Return some explanations if an update is planned after publishing
	 * @param cev
	 * @return
	 */
	public List<StatusDescription> publishUpdatesExplanations(CourseEditorEnv cev);

	/**
	 * Update the module configuration to have all mandatory configuration flags
	 * set to usefull default values
	 * 
	 * @param isNewNode true: an initial configuration is set; false: upgrading
	 *          from previous node configuration version, set default to maintain
	 *          previous behaviour
	 *          
	 * This is the workflow:
	 * On every click on a entry of the navigation tree, this method will be called
	 * to ensure a valid configration of the depending module. This is only done in
	 * RAM. If the user clicks on that node in course editor and publishes the course
	 * after that, then the updated config will be persisted to disk. Otherwise
	 * everything what is done here has to be done once at every course start.
	 * // TODO: Every click is too much. Only call this method on course start since changed config will be cached.
	 * If you cache something in course nodes be aware to set such a variable TRANSIENT, 
	 * otherwise the editortree.xml and runstructure.xml of old courses would no longer be compatible. 
	 *  
	 */
	public void updateModuleConfigDefaults(boolean isNewNode);
	
	
	public enum Processing {
		runstructure,
		editor
	}
}