/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                          CFieldList.cpp  -  description
                             -------------------
    begin                : Wed Dec 15 1999
    copyright            : (C) 1999-2005 by Alexey Parshin
    email                : alexeyp@gmail.com
 ***************************************************************************/

/***************************************************************************
   This library is free software; you can redistribute it and/or modify it 
   under the terms of the GNU Library General Public License as published by
   the Free Software Foundation; either version 2 of the License, or (at 
   your option) any later version.

   This library is distributed in the hope that it will be useful, but 
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library
   General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; if not, write to the Free Software Foundation, 
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.

   Please report all bugs and problems to "alexeyp@gmail.com"
 ***************************************************************************/

#ifndef __CFIELDLIST_H__
#define __CFIELDLIST_H__

#include <sptk3/istring.h>
#include <sptk3/CField.h>
#include <map>
#include <vector>

/// @addtogroup Database Database Support
/// @{

/// @brief The list of CField objects. 
///
/// Is used in CDataSource.
/// Allows to access data fields by the field name or
/// field index.
class SP_EXPORT CFieldList {
   typedef std::map<istring,CField *> CFieldMap;
   typedef std::vector<CField *>      CFieldVector;

   void             		  *m_userData;        ///< User data - any data you want to associate with that field list
   CFieldVector     		   m_list;	          ///< The list of fields
   CFieldVector::iterator  m_fieldStreamItor; ///< The field iterator for the streamed fields reading
   CFieldMap				  *m_index;           ///< The optional field index by name. 0L if field list isn't indexed.

public:

   /// Default constructor
   /// @param indexed bool, if you want to have a field index by name added. Such index speeds up the search of the field by name, but increases the occupied memory.
   CFieldList(bool indexed);

   /// Destructor
   ~CFieldList();

   /// Clears the field list
   void clear();

   /// Returns the nummber of fields in the list
   unsigned size() const { return m_list.size(); }

   /// Adds a new field int the list
   /// @param fname const char *, field name
   /// @returns new field reference
   CField& push_back(const char *fname);

   /// Adds a new field int the list without creating
   /// a new copy of the field.
   /// @param fld CField *, field name
   /// @returns new field reference
   CField& push_back(CField *fld);

   /// Finds a field by the field name
   /// @param fname const char *, field name
   /// @returns CField pointer, or 0L if not found
   CField *      fieldByName(const char * fname) const;

   /// Field access by field index, non-const version
   /// @param index int, field index
   /// @returns field reference
   CField&       operator [] (int index)          { return *(CField *)m_list[index]; }

   /// Field access by field index, const version
   /// @param index int, field index
   /// @returns field reference
   const CField& operator [] (int index) const    { return *(CField *)m_list[index]; }

   /// Field access by field name, non-const version
   /// @param fname const char *, field name
   /// @returns field reference
   CField&       operator [] (const char *fname)  { return *fieldByName(fname); }

   /// Field access by field name, const version
   /// @param fname const char *, field name
   /// @returns field reference
   const CField& operator [] (const char *fname) const { return *fieldByName(fname); }

   /// Field access by field name, non-const version
   /// @param fname const std::string&, field name
   /// @returns field reference
   CField&       operator [] (const std::string& fname)   { return *fieldByName(fname.c_str()); }

   /// Field access by field name, const version
   /// @param fname const std::string&, field name
   /// @returns field reference
   const CField& operator [] (const std::string& fname) const { return *fieldByName(fname.c_str()); }

   /// Sets user data
   void user_data(void *d) { m_userData = d; } 

   /// Returns user data
   void *user_data() const { return m_userData; } 

   /// Sets the field stream iterator to the first field
   void rewind() { m_fieldStreamItor = m_list.begin(); }

   /// Sets the field stream iterator to the next field.
   /// After the last field is reached, the iterator is switched to the first field
   /// @returns current field
   CField& next();
};

/// Streamed field output. The data is read from the current field,
/// and then next field becomes current. The rewind() method is called
/// automatically to reset the field iterator to the first field upon
/// query open() or fetch() method calls.
/// @param fieldList CFieldList&, a list of fields to assign
/// @param data const bool&, a variable to read current field to
SP_EXPORT CFieldList& operator >> (CFieldList& fieldList, bool& data);

/// Streamed field output. The data is read from the current field,
/// and then next field becomes current. The rewind() method is called
/// automatically to reset the field iterator to the first field upon
/// query open() or fetch() method calls.
/// @param fieldList CFieldList&, a list of fields to assign
/// @param data const std::string&, a variable to read current field to
SP_EXPORT CFieldList& operator >> (CFieldList& fieldList, std::string& data);

/// Streamed field output. The data is read from the current field,
/// and then next field becomes current. The rewind() method is called
/// automatically to reset the field iterator to the first field upon
/// query open() or fetch() method calls.
/// @param fieldList CFieldList&, a list of fields to assign
/// @param data int&, a variable to read current field to
SP_EXPORT CFieldList& operator >> (CFieldList& fieldList, int& data);

/// Streamed field output. The data is read from the current field,
/// and then next field becomes current. The rewind() method is called
/// automatically to reset the field iterator to the first field upon
/// query open() or fetch() method calls.
/// @param fieldList CFieldList&, a list of fields to assign
/// @param data double&, a variable to read current field to
SP_EXPORT CFieldList& operator >> (CFieldList& fieldList, double& data);

/// Streamed field output. The data is read from the current field,
/// and then next field becomes current. The rewind() method is called
/// automatically to reset the field iterator to the first field upon
/// query open() or fetch() method calls.
/// @param fieldList CFieldList&, a list of fields to assign
/// @param data CDateTime, a data to assign to current parameter
SP_EXPORT CFieldList& operator >> (CFieldList& fieldList, CDateTime& data);

/// Streamed field output. The data is read from the current field,
/// and then next field becomes current. The rewind() method is called
/// automatically to reset the field iterator to the first field upon
/// query open() or fetch() method calls.
/// @param fieldList CFieldList&, a list of fields to assign
/// @param data const CBuffer&, a variable to read current field to
SP_EXPORT CFieldList& operator >> (CFieldList& fieldList, CBuffer& data);

/// @}

#endif
