
/**********************************************************//**
 **
 ** @file data/Store/tablecursor_impl.h
 **
 ** Copyright (C) 2010  Xpace, LLC.  All rights reserved.
 **
 **************************************************************/


#if !defined XPACE_TABLE_CURSOR_IMPL_H
#define XPACE_TABLE_CURSOR_IMPL_H

#include <vector>
#include <map>

#include <QtCore/QSharedPointer>

#include "util/file.h"
#include "data/data.h"
#include "data/store/tablecursor.h"

namespace Xpace
{
  class TableCursor::Impl : public SharedImpl
  {
  public :
    static
    Impl* create
      (const Configuration&,
       StoreAccess access = SA_readOnly);

    virtual ~Impl
      ()
    {
    }

    virtual bool operator!
      ()
	    const
    = 0;

    virtual String getName
      ()
      const
    = 0;

    virtual uint addColumn
      (const Configuration&,
       bool* added = 0);

    virtual const Configuration& getColumnConfig
      (uint col)
     const;

    virtual uint getColumnNumber
      (const String& name)
      const;

    virtual uint64 getRowCount
      ()
      const
    = 0;
    virtual uint getColumnCount
      ()
      const;

    virtual uint64 getCurRow
      ()
      const
    = 0;

    virtual bool moveToRow
      (uint64)
    = 0;

    virtual bool addRow
      ()
    {
      return false;
    }

    virtual const Source<uint>& get
      ()
      const
    = 0;

    // for each cell in a row
    virtual bool rowForEach
      (uint64 row,   // report this row #
       TableCursor::Sink* act,
       const std::vector<uint>& cols = std::vector<uint>())
    = 0;

    virtual bool forEach
      (Sink* act, 
       const std::vector<uint>& cols = std::vector<uint>(),
       uint64 count = ~0)
    {
      for (uint64 row(getCurRow()), r(0); (r < count) && moveToRow(row); ++row)
        if (!rowForEach(r, act, cols))
          return false;
      return true;
    }

    virtual bool append
      (TableCursor::Impl*)
    {
      return false;
    }

	virtual std::auto_ptr<Sink> getSink
	  ()
	{
	  return std::auto_ptr<Sink>(0);
	}

    class sharedConfigs;
  protected:
    Impl
      (const Configuration& = Configuration(),
       StoreAccess access = SA_readOnly);

    bool read_only;

    QSharedPointer<sharedConfigs> configs;
  };

  // ================================ CONFIGS =================

  class TableCursor::Impl::sharedConfigs
  {
  public:
    static
    QSharedPointer<sharedConfigs> create
      (const Configuration&,
       StoreAccess access);

    ~sharedConfigs
      ();

    void save
      ();

    uint addColumn
      (const Configuration&,
       bool readOnly,
       bool* added);

    uint getColumnCount
      ()
      const;

    const String& getTableName
      ()
      const
    {
      return table_name;
    }

    const Configuration& getTableConfig
      ()
      const
    {
      return table_config;
    }

    const Configuration& getColumnConfig
      (uint col)
      const;

    const std::vector<DerivedDataType>& getColumnTypes
      ()
    {
      return column_types;
    }

    String& getColumnName
      (uint col)
      const;

    uint getColumnNumber
      (const String& name)
      const;

  private:
    sharedConfigs
      (const Configuration&,
       StoreAccess access);
    sharedConfigs
      (const sharedConfigs&);
    sharedConfigs& operator=
      (const sharedConfigs&);

    Configuration table_config;
    String dt_name;
    String table_name;
    std::vector<Configuration> column_configs;
    std::vector<DerivedDataType> column_types;
    std::map<String, uint> column_names;

    bool dirty;

    void set_column_configs
      ();
  };

  // ==========================================================
  // ==========================================================
  // ==========================================================

  inline
  bool TableCursor::operator!
    ()
    const
  {
    const Impl* i(impl());
    return !i || !*i;
  }

  inline
  String TableCursor::getName
    ()
    const
  {
    return impl()->getName();
  }

  // ================================ COLUMN COUNT ============

  inline uint TableCursor::Impl::sharedConfigs::getColumnCount
    ()
    const
  {
    return narrow_to<uint, size_t>(column_configs.size());
  }

  inline uint TableCursor::Impl::getColumnCount
    ()
    const
  {
    return configs->getColumnCount();
  }

  inline
  uint TableCursor::getColumnCount
    ()
    const
  {
    return impl()->getColumnCount();
  }

  // ================================ COLUMN CONFIG ===========

  inline 
  const Configuration& TableCursor::Impl::sharedConfigs::getColumnConfig
    (uint col)
    const
  {
    static Configuration empty;
    return (col < column_configs.size()) ? column_configs[col] : empty;
  }

  inline
  const Configuration& TableCursor::Impl::getColumnConfig
    (uint col)
   const
  {
    return configs->getColumnConfig(col);
  }

  inline
  const Configuration& TableCursor::getColumnConfig
    (uint column)
    const
  {
    return impl()->getColumnConfig(column);
  }

  // ================================ COLUMN NUMBER ===========

  inline 
  uint TableCursor::Impl::sharedConfigs::getColumnNumber
    (const String& name)
    const
  {
    std::map<String, uint>::const_iterator col(column_names.find(name));
    return (col == column_names.end()) ? ~0 : col->second;
  }

  inline
  uint TableCursor::Impl::getColumnNumber
    (const String& name)
   const
  {
    return configs->getColumnNumber(name);
  }

  inline 
  uint TableCursor::getColumnNumber
    (const String& name) 
    const
  {
    return impl()->getColumnNumber(name);
  }

  // ================================ NON-CONFIGS =============

  inline
  uint64 TableCursor::getRowCount
    ()
    const
  {
    return impl()->getRowCount();
  }

  inline
  bool TableCursor::moveToRow
    (uint64 row)
  {
    return impl()->moveToRow(row);
  }
   
  inline
  bool TableCursor::addRow
    ()
  {
    return impl()->addRow();
  }

  inline
  const Source<uint>& TableCursor::get
    ()
    const
  {
    return impl()->get();
  }

  inline
  bool TableCursor::append
    (TableCursor& src)
  {
    return impl()->append(src.impl());
  }
};

#endif
