
/**********************************************************//**
 **
 ** @file index/index.h
 **
 ** Copyright (C) 2010  Xpace, LLC.  All rights reserved
 **
 ** www.xpace.net
 **
 **************************************************************/

#ifndef XPACE_INDEX_H
#define XPACE_INDEX_H

#include "base/types.h"
#include "base/sharedimpl.h"
#include "base/config.h"
#include "util/file.h"
#include "index/collator/collator.h"
#include "index/reflist/reflist.h"

namespace Xpace
{
  /// An index
  class XPACE_EXPORT Index : public Configurable
  {
  public :
    /// create an empty, unconfigured index
    Index
      ();

    /// create an empty index 
    /// @param config use this configuration
    explicit Index
      (const Configuration& config);        

    /// read an index
    /// @param config use this configuration
    /// @param indexFile read from this file
    /// @param oRoot file position of index root
    /// @param refCount number of refs in the index's universe
    Index
      (const Configuration& config,
       File* indexFile,
       File::Position oRoot,
       uint64 refCount = 0);

    #ifdef XPACE_REFLIST_H
    /// @param query a query string
    /// @param recCount for NOT searches
    /// @return a RefListCursor into the result
    RefListCursor eval
      (String query,
       uint64 recCount = 0)
      const;
    
    #ifdef QDOM_H
    /// @param query a search tree
    /// @param recCount for NOT searches
    /// @return a RefListCursor into the result
    RefListCursor eval
      (QDomNode query,
       uint64 recCount = 0)
      const;
    #endif
    #endif

    /// @return this index's Collator
    const Collator& getCollator
      ()
      const;

    /// sort this index; could take a while
    /// status callback
    struct sortStatus
    {
      virtual ~sortStatus
        () 
      {
      };

      sortStatus
        () :
          interval(0)
      {
      };

      /// @return true to continue, false to stop
      virtual bool operator()
        ()
      { 
        return true; 
      };
      uint64 interval;   ///< call operator() this often
    };
    /// @param st status callback
    bool makeSorted
      (sortStatus* st = 0);

    /// @return true iff the index is empty
    bool operator!
      ()
	    const;
    
    /// @return true iff the index has term counts
    bool hasCounts
      ()
      const;

    /// write this index; could take a while
    /// status callbackj
    struct writeStatus
    {
      writeStatus
        () :
          interval(0)
      {
      };

      virtual ~writeStatus
        () 
      { 
      };

      /// @param term the term being written
      /// @param offset file offset to wich we're writing
      /// @return true to continue, false to stop
      virtual bool operator()
        (uint64 termNum,
         String term,
  	     File::Position offset)
      = 0;
	    File::Distance interval;  ///< call after writing this many bytes
    };
    /// @param file write to this file (at current position)
    /// @param st status callback
    /// @return file position of index root
    File::Position write
      (File* file,
       writeStatus* st = 0);

    /// merge a list of indexes
    /// @param file merge to this file
    /// @param list merge these indexes
    /// @return file position of index root
    static
    File::Position merge
      (File* file,
       std::vector<Index>& list);

    /// index term iterator
    class XPACE_EXPORT Iter
    {
    public :
      /// @return a string representation (from a Collator) of this index term
	    String getStr
	      ()
	      const;

      /// get a key
      /// @return this index key
      const Key getKey
        ()
        const;

      /// @return the list of references for this index term
	    RefListCursor getRefList
        ()
        const;

      /// @return the list of all references for all index terms in the interval [*this, end)
	    RefListCursor getRefList
	      (const Iter& end)
        const;

      /// @return true if the iterator is past the end of the index's term list
      bool operator!
        ()
        const;

      /// @param delta move the iterator this far in the index list
      /// @return true if move successful, false (and don't move) if not
      bool move
        (int64 delta);
      /// the distance between two iterators
      /// @param rhs the other iterator
      /// @return the distance
      int64 diff
        (const Iter& rhs)
        const;

    private :
      DECLARE_IMPL(Iter)
      friend class Index;
      friend class RLC_Index;
    };

    /// @return the number of terms in the index
    uint64 getTermCount
      ()
      const;

    /// find a key in the index

    Iter begin
      ()
      const;

    /// @param key find this String
    /// @param found fillin true if key is found
    /// @return Iter corresponding to the key
    Iter begin
      (const String& key,
 	     bool* found = 0)
      const;

    /// @param key find this int64
    /// @retval found fillin true if key is found
    /// @return Iter corresponding to the key
    Iter begin
      (int64 key,
 	     bool* found = 0)
      const;

    /// @param key find this Key
    /// @retval found fillin true if key is found
    /// @return Iter corresponding to the key
    Iter begin
      (const BytesRef& key,
       bool* found = 0)
      const;

    // search for a key, adding if it's not there

    /// @param key find/add this String
    /// @param added fillin true if key was added
    /// @return Iter corresponding to the key
    Iter beginAdd
      (const String& key,
	     bool* added);

    /// @param key find/add this int64
    /// @param added fillin true if key was added
    /// @return Iter corresponding to the key
    Iter beginAdd
      (int64 key,
	     bool* added);

    /// @param key find/add this Key
    /// @param found fillin true if key was added
    /// @return Iter corresponding to the key
    Iter beginAdd
      (const BytesRef& key,
	     bool* added);

    /// @return the iter one past the end
    Iter end
      ()
      const;

    /// traverse each term, or each reference, in an interval of terms

    /// callback
    class forEachAct
    {
    public:
      virtual ~forEachAct
        () 
      { 
      }

      /// called for each term 
      /// @param key the term's key
      /// @param count the count (if stored in the Index) of references to the key 
      /// @return true to continue, false to stop
      virtual bool term
        (const Key& key,
         uint64 count)
      = 0;
      /// called for each ref
      /// @param ref a pointer to the first element in the ref list
      /// @param len the number of elements in the ref
      /// @return true to continue, false to stop
      virtual bool ref
        (uint64 *const /*ref*/,
         uint /*len*/)
      {
        return true;
      }
    };

    /// traverse each term in the range [begin, end)
    /// @param begin start here
    /// @param end end here
    /// @param act call this for each term
    /// @param refList if != 0, call act only for terms in this refList
    /// @return true if completed, false if stopped by callback
    bool forEachTerm
      (Iter& begin,
       Iter& end,
       forEachAct* act,
       const RefListCursor* refList = 0)
      const;
    /// @param start start at the start'th term
    /// @param count for this many terms
    bool forEachTerm
      (uint64 start,
       uint64 count,
       forEachAct* act,
       const RefListCursor* refList = 0)
      const;
    bool forEachTerm
      (forEachAct* act,
       const RefListCursor* refList = 0)
      const
    {
      return forEachTerm(0, ~uint64(0), act, refList);
    }

    /// traverse each ref in each term in the range [begin, end)
    /// @param begin start here
    /// @param end end here
    /// @param act call this for each term, and each ref
    /// @return true if completed, false if stopped by callback
    bool forEachRef
      (Iter& begin,
       Iter& end,
       forEachAct* act)
      const;
    /// @param start start at the start'th term
    /// @param count for this many terms
    /// @return true if completed, false if stopped by callback
    bool forEachRef
      (uint64 start,
       uint64 count,
       forEachAct* act)
      const;
    bool forEachRef
      (forEachAct* act)
      const
    {
      return forEachRef(0, ~uint64(0), act);
    }

    #ifdef XPACE_RESULT_H
    /// Get a range of terms 
    /// @param begin starting at this term
    /// @param count (at most) this many terms
    /// @param includeCounts if there are counts in the index, include them in the result
    /// @return the result, filled with the terms
    TableResult getTerms
      (uint64 begin,
       uint64 count,
       bool includeCounts)
    const;
    #endif

  private :
    File::Position write_temp
      (File*,
       writeStatus*);	 

    friend class indexListImpl;
    friend class ReadIndex;
    DECLARE_IMPL_NAME(Index, load)
    ADD_IMPL_NAME(Index, read)
  };
};

#endif
