
/**********************************************************//**
 **
 ** @file data/Store/tablecursor.h
 **
 ** Copyright (C) 2010  Xpace, LLC.  All rights reserved
 **
 ** www.xpace.net
 **
 **************************************************************/


#if !defined XPACE_TABLECURSOR_H
#define XPACE_TABLECURSOR_H

#include "base/types.h"
#include "base/sharedimpl.h"

#include "base/config.h"

#include "data/translate_node.h"

namespace Xpace
{
  class RefListCursor;

  class XPACE_EXPORT TableCursor : public Configurable
  {
  public : 
    /// @param c the Table's Configuration
    /// @param readOnly if true, open for reading only
    /// @throw File_Cant_Open
    /// @throw File_Cant_Read
    explicit TableCursor
      (const Configuration& c,
       StoreAccess access = SA_readOnly);  

	TableCursor
	  (const String& name,
	   const String& dt,
	   const String& di,
	   const String& dd,
	   StoreAccess access = SA_readOnly,
     bool overwrite = false,
	   bool test = false);

    /// @return true iff the table is empty
    bool operator!
      ()
	    const;

    /// @return the table's name
    String getName
      ()
      const;

    /// append another table to this one
    /// @param the table to append
    /// @return true iff the table was appended successfully
    bool append
      (TableCursor&);

    /// add a column with this Configuration to the table
    /// @param c the new column's Configuration
    /// @retval added true if added, false if the column already existed or on error
    /// @return the column number, ~0 on error
    uint addColumn
      (const Configuration& c,
       bool* added = 0);

	  uint addColumn
	    (const String& name,
	     DerivedDataType type,
       bool* added = 0);

    /// Get a column's configuration
    /// @param col the column number
    /// @return the column's Configuration
    const Configuration& getColumnConfig
      (uint col)
      const;

    /// Get a column from a column name
    /// @param the column name
    /// @return the column number, ~0 if not found
    uint getColumnNumber
      (const String& name)
      const;

    /// @return the number of rows in the table
    uint64 getRowCount
      ()
      const;

    /// @return the number of columns in the table
    uint getColumnCount
      ()
      const;

    /// @param row move cursor to this row
    /// @return true if successful, false (and don't move) if not
    bool moveToRow
      (uint64 row);

    /// append a row to the table, making it current
    /// @return true if successful, false (and don't move) if not
    bool addRow
      ();

    /// get a Source
    const Source<uint>& get 
      ()
      const;

    /// Can't open a Table
    class cantOpen : public Exception
    {
    public:
      /// @param config the configuration of the table
      /// @param reason why it couldn't be opened (e.g., File_Cant_Open)
      cantOpen
        (const String name,  
         const Configuration& config,
         const Exception reason = Exception());
    };

    struct Location
    {
      Location
        (uint64 r = 0,
         uint c = 0) :
          row(r),
          col(c)
      {
      }
      uint64 row;
      uint col;
    };

    class Sink : public Xpace::Sink<const Location&>
    {
    public:
      /// may be called to order columns
      /// @param config the column's Configuration
      /// @return the column's number, ~0 = don't care
      virtual uint getColumnNum
        (const Configuration& /*config*/)
      {
        return ~0u;
      }
    };

	  /// @return a writer for this table
	  std::auto_ptr<Sink> getSink
	    ();

    /// Starting from current position, call a Sink for each cell in row/column order
    /// @param act called for each cell
    /// @param columns if not empty, return these columns in this order
    /// @param rows call for this many rows
    /// @return true iff act always returned true, false otherwise
    bool forEach
      (Sink* act,
       const std::vector<uint>& columns = std::vector<uint>(),
       uint64 rows = ~0);

    DECLARE_CACHED_IMPL_BASE(TableCursor, Configurable)
  };
};

#endif
