
/**********************************************************//**
 **
 ** @file data/Store/scursor.h
 **
 ** Copyright (C) 2010  Xpace, LLC.  All rights reserved
 **
 ** www.xpace.net
 **
 **************************************************************/


#ifndef XPACE_SCURSOR_H
#define XPACE_SCURSOR_H

#include <vector>

#include "base/types.h"
#include "base/sharedimpl.h"
#include "base/config.h"

namespace Xpace 
{
  class XPACE_EXPORT SCursor : public Configurable
  {
  public:
    explicit SCursor
      (const Configuration&);

    // ------------------------------ class tree --------------

    /// return the configuration of current node
    const Configuration& getNodeConfig
      ()
      const;
    /// Return id for this node, relative to parent
    uint getID
      ()
	  const;

    class classTreeNodeInfo
    {
    public:
      classTreeNodeInfo
        (void*);
      classTreeNodeInfo& operator=
        (void*);
      operator void*
        ()
        const;
    private :
       void* p;
    };

    class classTreeDoThis
    {
    public:
      virtual ~classTreeDoThis
        ()
      { 
      }

      virtual bool operator()
        (const String& path,
         const Configuration& config,
         std::vector<uint>& ids,
         classTreeNodeInfo* info)
      = 0;
    };
    bool classTreeTraverse
      (classTreeDoThis*);

    classTreeNodeInfo getClassTreeNodeInfo
      ();

    // ------------------------------ sequential access -------

	  enum SStatus 
    {
		  Continue,       ///< in the middle of content
		  Parent,         ///< end of this content and children, parent next
		  Child,          ///< a child of some type starts here
		  Sibling,        ///< end of this content and children, sibling next
	  };

    /// getContent will return a chunk of content stopping at the first of
    ///   (a) a maximum buffer size, or 
    ///   (b) the nearest parent/child boundary.
    /// The status returned indicates which of these happened
    ///   Continue for the (a)
    ///   one of the other enumeration values for (b).  
    /// @retval result descriptor for content bytes, which will remain stable until
    ///     the next operation on this object.  result may be null.
    /// @return resulting status
    SStatus getContent
      (BytesRef* result);
    SStatus getContent
      (String* result);
    SStatus getContent
      (int64* result);

    /// move to next (depth-first) node
    SStatus next
      ();

    // ------------------------------ random access -----------

    /// Axes along which we can move, relatively or absolutely
    enum Axis 
    {
      BytesRel,       ///< within the current content, relative
      BytesAbs,       ///< within the current content, absolute
      SiblingRel,     ///< across the current level, relative
      SiblingAbs,     ///< across the current level, absolute
      HierarchyRel,   ///< up and down the tree, relative
      HierarchyAbs    ///< up and down the tree, absolute
    };

    /// Get the current position and extent 
    /// @param axis measurement is relative to this - all interpreted as absolute
    /// @retval current NULL, or receiver of current position
    /// @retval last NULL, or receiver of maximum position
    /// @return true if success, false if incapable of providing requested info
    bool getPosition
      (Axis axis,
       uint64* current,
       uint64* last = 0)
    const;

    /// Move to another position
    /// @param axis movement using this direction and unit
    /// @param distance absolute or relative coordinate to move to.
    ///     (- is earlier or towards the root)
    /// @return true on successful seek, false if incapable
    /// @note the initial position on entering a child is at its start,  
    /// Descending more than one child will only be successful if there is no other content
    ///   before each child. – not sure we need this restriction
    bool move
      (Axis axis,
       int64 distance);

    /// Move to a child or sibling position by name.
    /// @param childNotSibling if true, move down hierarchy, else move to a sibling
    /// @param name name of the element, blank for any element
    /// @param instance which of elements of this name to move to; negative for (prev) sibling
    /// @return true if the requested move was possible, otherwise the current
    ///    position is unchanged.
    bool move
      (bool childNotSibling,
       const String& name,
       int instance = 0);

    /// Traverse a subtree, calling nodeDoThis::operator() for each node
    struct nodeDoThis
    {
      virtual ~nodeDoThis() 
      { 
      }

      /// @param pos node positon relative to siblings of same name
      /// @content, if any
      /// @info Class Tree node info, if any 
      virtual bool operator()
        (std::vector<uint64>& pos,
         const BytesRef content,
         void* info)
      = 0;
    };
    bool traverse
      (nodeDoThis&);

    DECLARE_IMPL_BASE(SCursor,Configurable);

    class cantOpen : public Exception
    {
    public :
      cantOpen
        (const String name,  
         const Configuration& config,         
         const Exception reason = Exception());
    };
  };

} // namespace Xpace

#include "data/store/scursor_impl.h"

#endif

