/************************** * * * * * * * * * * * * ***************************
    Copyright (c) 1999-2005 Ryan Bobko
                       ryan@ostrich-emulators.com

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

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.     
*************************** * * * * * * * * * * * * **************************/

#ifndef _QHACCTABLE_H
#define _QHACCTABLE_H

#include "qhaccconstants.h"
#include "resultset.h"
#include "tableops.h"

#include <map>
#include <vector>
#include <memory>
using namespace std;

class compo;
class QHaccDB;
class TableGet;
class TableSelect;
class TableUpdate;
class QHaccTableIndex;

class QHaccTable : public QHaccResultSet {
 public:
	QHaccTable( int cols =0, const ColType * =0, const char * name =0, 
							uint =5, uint =5, uint maxfree =8 );
	QHaccTable( const QHaccTable& );
	QHaccTable( const QHaccResultSet& );
	QHaccTable& operator=( const QHaccTable& );
	QHaccTable& operator=( const QHaccResultSet& );
	virtual ~QHaccTable();

	void clear();

	auto_ptr<QHaccResultSet> getWhere( vector<TableSelect>,
																		 uint& retrows ) const;
	auto_ptr<QHaccResultSet> getWhere( const TableSelect&, uint& retrows ) const;
	auto_ptr<QHaccResultSet> getWhere( const TableGet&, vector<TableSelect>,
																		 uint& retrows ) const;
	TableRow getWhere( const TableSelect& ) const;

	/** 
	 * @return the primary key column. This can be -1 if no pk is set
	 */
	int idcol() const;

	TableCol max( int column );
	TableCol min( int column );
	
	void deleteWhere( const TableSelect& );

	void updateWhere( const TableSelect&, const TableUpdate& );
	void updateWhere( const TableSelect&, const TableRow& );

	/**
	 * Drop any index on the given column. If none exists, do nothing
	 * @param col The column
	 */
	void dropIndexOn( int col );

	/**
	 * Add an index on column @p col.
	 * @param col The column to index
	 * @param i An index of the given column. If @p col was previously
	 * indexed, * @p i is pointer to the existing index. If @p col was not
	 * already indexed, @p i is a pointer to a newly-created index.
	 */
	void addIndexOn( int col );

	/**
	 * Add an index on column @p col.
	 * @param col The column to index
	 * @param subcol The secondary column to index
	 * @param i An index of the given columns. If a suitable index already
	 * exists, @p i is pointer to the existing index. If not, @p i is a
	 * pointer to a newly-created index.
	 */
	void addIndexOn( int col, int subcol );

	/**
	 * Does this table contain this tablerow?
	 * @param col The column to search
	 * @param value The TableCol to look for
	 * @param i The index of the found TableRow
	 * @return True, if the row value was found, else False
	 */
	bool contains( int col, const TableCol& value, uint& i ) const;
	
	/**
	 * Set the name of this table
	 * @param name The new name of the table
	 */
	void setName( QString name );

	/**
	 * Get the name of this table
	 */ 
	const QString& getName() const;

	/**
	 * Set the primary key (for duplicate checking)
	 */
	void setPK( int col );
	
	static const int DUPLKEY;
	static const int NOTFOUND;

 protected:
	void istartLoad( uint =0 );
	void istopLoad();
	void iresize();
	void iadd( uint );

	virtual int verifyRow( const TableRow& ) const;
	const char * newerror( int code ) const;

	static const int INITINIT, INITGROW, INITFREE;
	static const char * ERRORS[];

 private:
	uint maxFree;
	QString name;
	QHaccTableIndex ** indexes;
	bool loading;
	QHaccTableIndex * pki;

	vector<uint> igetWhere( const TableSelect& ) const;

	bool getIndexOn( int pos, QHaccTableIndex *& ) const;
	bool getIndexOn( int pos, int spos, QHaccTableIndex *& ) const;

	bool idebug( int, std::ostream *& ) const;
	bool ierror( int, std::ostream *& ) const;

	void reindex();
	void remake();
};


class compo {
 public:
  bool operator()( const TableRow * x, const TableRow * y ) const;
};

class QHaccTableIndex {
 public:
	QHaccTableIndex( QHaccResultSet *, int, ColType, int =-1, ColType =CTNULL );
	QHaccTableIndex& operator=( const QHaccTableIndex& );
	QHaccTableIndex( const QHaccTableIndex& ); // don't allow publicly
	virtual ~QHaccTableIndex();
	
	/**
	 * Convert the given array position from this index's sorting to the
	 * parent table's index position.
	 * @param idx The array location of this index
	 * @return The parent table's array index
	 */
	uint at( uint idx ) const;
	uint operator[]( uint ) const;

	/**
	 * @param t The TableCol in question
	 * @return The index where column value of @p t starts
	 */
	uint starts( const TableCol& t ) const;

	/**
	 * @param t The TableCol in question
	 * @return The index where column value of @p t ends
	 */
	uint ends( const TableCol& t ) const;

	bool contains( const TableCol& ) const;
	bool contains( const TableCol&, uint& idx ) const;

	/**
	 * Populate the given table with unique data for this index's sort field
	 * @return a vector with indexes of unique rows
	 */
	vector<uint> unique() const;

	/**
	 * What column does this index sort on?
	 * @param i The column in question
	 * @return True, if this index sorts on @p i
	 */
	bool sorts( int i ) const;
	bool sorts( int i, int j ) const;
	int  sorts() const;
	void sorts( int&, ColType&, int&, ColType& ) const;

	TableCol max() const;
	TableCol min() const;

	void reindex();
	void remake();

	void newvalat( uint datapos );
	void remvalat( uint datapos );

 private:
	vector<uint> lookup;
	QHaccResultSet * data;
	int field, subfield;
	ColType ftype, subtype;

	// we'll use a multimap to do the sorting for us
	multimap<const TableRow *, uint, compo> mapper;
	
	void init( QHaccResultSet *, int, ColType, int, ColType );
	
	const TableRow& dat( uint ) const;
};

#endif
