/*
 * Copyright (C) 2010 eXo Platform SAS.
 *
 * 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 org.exoplatform.portal.mop.navigation;

import java.util.List;

import org.exoplatform.portal.mop.SiteKey;
import org.exoplatform.portal.mop.SiteType;

/**
 * <p>
 * The navigation service takes care of managing the various portal navigations and their nodes. In order to manage an efficient
 * loading of the nodes, a {@link Scope} is used to describe the set of nodes that should be retrieved when a loading operation
 * is performed.
 * </p>
 *
 * <p>
 * The node operations does not provide a model per se, but instead use the {@link NodeModel} interface to plug an API model.
 * Various node operations are quite complex and any API in front of this service would need to perform a manual, error prone
 * and tedious synchronization. Instead the model interface allows the navigation service to operate directly on an existing
 * model.
 * </p>
 *
 * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
 * @version $Revision$
 */
public interface NavigationService {

    /**
     * Find and returns a navigation, if no such site exist, null is returned instead.
     *
     * @param key the navigation key
     * @return the matching navigation
     * @throws NullPointerException if the key is null
     * @throws NavigationServiceException anything that would prevent the operation to succeed
     */
    NavigationContext loadNavigation(SiteKey key) throws NullPointerException, NavigationServiceException;

    /**
     * Find and returns navigations of a given type. Method use discretion is advised
     *
     * @param type the navigation type
     * @return all navigations matching type
     * @throws NullPointerException if the key is null
     * @throws NavigationServiceException
     */
    List<NavigationContext> loadNavigations(SiteType type) throws NullPointerException, NavigationServiceException;

    /**
     * Create, update a navigation. When the navigation state is not null, the navigation will be created or updated depending
     * on whether or not the navigation already exists.
     *
     * @param navigation the navigation
     * @throws NullPointerException if the key is null
     * @throws IllegalArgumentException if the navigation is already destroyed
     * @throws NavigationServiceException anything that would prevent the operation to succeed
     */
    void saveNavigation(NavigationContext navigation) throws NullPointerException, IllegalArgumentException,
            NavigationServiceException;

    /**
     * Destroy a navigation.
     *
     * @param navigation the navigation
     * @return true if the navigation was destroyed
     * @throws NullPointerException if the navigation is null
     * @throws IllegalArgumentException if the navigation is destroyed
     * @throws NavigationServiceException anything that would prevent the operation to succeed
     */
    boolean destroyNavigation(NavigationContext navigation) throws NullPointerException, IllegalArgumentException,
            NavigationServiceException;

    /**
     * Load a navigation node from a specified navigation. The returned context will be the root node of the navigation.
     *
     * @param model the node model
     * @param navigation the navigation
     * @param scope the scope
     * @param listener the optional listener
     * @param <N> the node generic type
     * @return the loaded node
     * @throws NullPointerException if any argument is null
     * @throws NavigationServiceException anything that would prevent the operation to succeed
     */
    <N> NodeContext<N> loadNode(NodeModel<N> model, NavigationContext navigation, Scope scope,
            NodeChangeListener<NodeContext<N>> listener) throws NullPointerException, NavigationServiceException;

    /**
     * <p>
     * Save the specified context state to the persistent storage. The operation takes the pending changes done to the tree and
     * attempt to save them to the persistent storage. When conflicts happens, a merge will be attempted however it can lead to
     * a failure.
     * </p>
     *
     * @param context the context to save
     * @param listener the optional listener
     * @throws NullPointerException if the context argument is null
     * @throws NavigationServiceException anything that would prevent the operation to succeed
     */
    <N> void saveNode(NodeContext<N> context, NodeChangeListener<NodeContext<N>> listener) throws NullPointerException,
            NavigationServiceException;

    /**
     * <p>
     * Update the specified <code>context</code> argument with the most recent state. The update operation will affect the
     * entire tree even if the <code>context</code> argument is not the root of the tree. The <code>context</code> argument
     * determines the root from which the <code>scope</code> argument applies to.
     * </p>
     *
     * <p>
     * The update operation compares the actual tree and the most recent version of the same tree. When the
     * <code>scope</code> argument is not null, it will be used to augment the tree with new nodes. During the
     * operation, any modification done to the tree wil be reported as a change to the optional <code>listener</code> argument.
     * </p>
     *
     * <p>
     * The update operates recursively by doing a comparison of the node intrisic state (name or state) and its structural state
     * (the children). The comparison between the children of two nodes is done thanks to the Longest Common Subsequence
     * algorithm to minimize the number of changes to perform. The operation assumes that no changes have been performed on the
     * actual tree.
     * </p>
     *
     * @param context the context to update
     * @param scope the optional scope
     * @param listener the optional node change listener
     * @param <N> the node generic type
     * @throws NullPointerException if the context argument is null
     * @throws NavigationServiceException anything that would prevent the operation to succeed
     * @throws IllegalArgumentException if the context argument has pending changes
     */
    <N> void updateNode(NodeContext<N> context, Scope scope, NodeChangeListener<NodeContext<N>> listener)
            throws NullPointerException, IllegalArgumentException, NavigationServiceException;

    /**
     * <p>
     * Rebase the specified <code>context</code> argument with the most recent state. The rebase operation will affect the
     * entire tree even if the <code>context</code> argument is not the root of the tree. The <code>context</code> argument
     * determines the root from which the <code>scope</code> argument applies to.
     * </p>
     *
     * <p>
     * The rebase operation compares the actual tree and the most recent version of the same tree. When the
     * <code>scope</code> argument is not null, it will be used to augment the tree with new nodes. During the
     * operation, any modification done to the tree wil be reported as a change to the optional <code>listener</code> argument.
     * </p>
     *
     * <p>
     * The rebase operates in a similar way of the update operation, however it assumes that it can have pending changes done to
     * the tree (i.e changes that have not been saved). Actually a rebase operation with no changes will do the same than an
     * update operation. The rebase operation attempts to bring the most recent changes to the tree, by doing a rebase of the
     * pending operations on the actual tree. When conflicting changes exist, a merge will be attempted, however it could fail
     * and lead to a non resolvable situation.
     * </p>
     *
     * @param context the context to rebase
     * @param scope the optional scope
     * @param listener the option node change listener @throws NullPointerException if the context argument is null
     * @param <N> the node generic type
     * @throws NullPointerException if the context argument is null
     * @throws NavigationServiceException anything that would prevent the operation to succeed
     */
    <N> void rebaseNode(NodeContext<N> context, Scope scope, NodeChangeListener<NodeContext<N>> listener)
            throws NullPointerException, NavigationServiceException;
}
