/*
 * JBoss, Home of Professional Open Source
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package org.jboss.cache.optimistic;

import org.jboss.cache.CacheSPI;
import org.jboss.cache.Fqn;
import org.jboss.cache.Node;
import org.jboss.cache.NodeSPI;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Represents a type of {@link org.jboss.cache.Node} that is to be copied into a {@link TransactionWorkspace} for optimistically locked
 * nodes.  Adds versioning and dirty flags over conventional Nodes.
 * <p/>
 * Typically used when the cache mode configured is {@link org.jboss.cache.config.Configuration.NodeLockingScheme#OPTIMISTIC}
 *
 * @author Manik Surtani (<a href="mailto:manik@jboss.org">manik@jboss.org</a>)
 * @author Steve Woodcock (<a href="mailto:stevew@jofti.com">stevew@jofti.com</a>)
 * @since 1.3.0
 */
public interface WorkspaceNode<K, V> extends Node<K, V>
{
   /**
    * Returns 2 Sets - a set of children added (first set) and a set of children removed.
    *
    * @return a merged map of child names and Nodes
    */
   List<Set<Fqn>> getMergedChildren();

   /**
    * Retrieves the data version of the in-memory node.
    *
    * @return A data version
    */
   DataVersion getVersion();

   /**
    * Sets the data version of this workspace node.
    *
    * @param version a {@link org.jboss.cache.optimistic.DataVersion} implementation.
    */
   void setVersion(DataVersion version);

   /**
    * A node is considered modified if it's data map has changed.  If children are added or removed, the node is not
    * considered modified - instead, see {@link #isChildrenModified()}.
    *
    * @return true if the data map has been modified
    */
   boolean isModified();

   /**
    * A convenience method that returns whether a node is dirty, i.e., it has been created, deleted or modified.
    * Noe that adding or removing children does not constitute a node being dirty - see {@link #isChildrenModified()}
    *
    * @return true if the node has been either created, deleted or modified.
    */
   boolean isDirty();

   /**
    * Attempts to merge data changed during the current transaction with the data in the underlying tree.
    *
    * @return a merged map of key/value pairs.
    */
   Map<K, V> getMergedData();

   /**
    * Retrieves a reference to the underlying {@link NodeSPI} instance.
    *
    * @return a node
    */
   NodeSPI<K, V> getNode();

   /**
    * Retrieves a TransactionWorkspace instance associated with the current transaction, which the current WorkspaceNode instance
    * lives in.
    *
    * @return a TransactionWorkspace.
    */
   TransactionWorkspace getTransactionWorkspace();

   /**
    * @return true if the instance was created in the current transaction; i.e., it did not exist in the underlying data tree.
    */
   boolean isCreated();

   /**
    * Marks the instance as having been created in the current transaction.
    */
   void markAsCreated();

   /**
    * Creates a child node.
    *
    * @param child_name Object name of the child to create
    * @param parent     A reference to the parent node
    * @param cache      CacheSPI instance to create this node in
    * @param version    DataVersion to apply to the child.  If null, {@link DefaultDataVersion#ZERO} will be used.
    * @return a NodeSPI pointing to the newly created child.
    */
   NodeSPI createChild(Object child_name, NodeSPI<K, V> parent, CacheSPI<K, V> cache, DataVersion version);

   /**
    * Tests whether versioning for the WorkspaceNode instance in the current transaction is implicit (i.e., using {@link org.jboss.cache.optimistic.DefaultDataVersion}
    * rather than a custom {@link org.jboss.cache.optimistic.DataVersion} passed in using {@link org.jboss.cache.config.Option#setDataVersion(DataVersion)})
    *
    * @return true if versioning is implicit.
    */
   boolean isVersioningImplicit();

   /**
    * Sets whether versioning for the WorkspaceNode instance in the current transaction is implicit (i.e., using {@link org.jboss.cache.optimistic.DefaultDataVersion}
    * rather than a custom {@link org.jboss.cache.optimistic.DataVersion} passed in using {@link org.jboss.cache.config.Option#setDataVersion(DataVersion)})
    *
    * @param b set to true if versioning is implicit, false otherwise.
    */
   void setVersioningImplicit(boolean b);

   /**
    * @return true if the instance has been deleted in the current transaction.
    */
   boolean isDeleted();

   /**
    * Marks the node as being deleted (or not) in the current transaction.  This is not recursive, child nodes are not affected.
    *
    * @param marker true if the node has been deleted, false if not.
    */
   void markAsDeleted(boolean marker);

   /**
    * Same as {@link #markAsDeleted(boolean)} except that the option to recurse into children is provided.
    *
    * @param marker    true if the node has been deleted, false if not.
    * @param recursive if true, child nodes (and their children) are marked as well.
    */
   void markAsDeleted(boolean marker, boolean recursive);

   /**
    * Overrides {@link Node#getChild(Object)} to return a {@link org.jboss.cache.NodeSPI} rather than a {@link org.jboss.cache.Node}
    *
    * @param o node name
    * @return a child node
    */
   NodeSPI<K, V> getChild(Object o);

   /**
    * Overrides {@link Node#getChild(Fqn)} to return a {@link org.jboss.cache.NodeSPI} rather than a {@link org.jboss.cache.Node}
    *
    * @param f node fqn
    * @return a child node
    */
   NodeSPI<K, V> getChild(Fqn f);

   /**
    * Adds a given WorkspaceNode to the current node's child map
    *
    * @param workspaceNode
    */
   void addChild(WorkspaceNode<K, V> workspaceNode);

   /**
    * @return true if children have been added to or removed from this node.  Not the same as 'dirty'.
    */
   boolean isChildrenModified();

   /**
    * @return true if the child map has been loaded from the underlying data structure into the workspace.
    */
   boolean isChildrenLoaded();

   /**
    * @return teur if this node has been resurrected, i.e., it was deleted and re-added within the same transaction
    */
   boolean isResurrected();

   /**
    * Marks a node as resurrected, i.e., deleted and created again within the same transaction
    *
    * @param resurrected
    */
   void markAsResurrected(boolean resurrected);
}
