#ifndef __RECORDSET_H
#define __RECORDSET_H

#ifndef __ASSOC_H
#include <assoc.h>
#endif

#ifndef __SHEET_H
#include <sheet.h>
#endif

#ifndef __VARIANT_H
#include <variant.h>
#endif

struct TRecordset_column_info : public TObject
{
  TString _name;   // Table.Column
  int _width;
  TFieldtypes _type;
};

///////////////////////////////////////////////////////////
// TRecordset
///////////////////////////////////////////////////////////

enum TRecordsetExportFormat { fmt_unknown, fmt_html, fmt_text, fmt_silk, fmt_campo, fmt_dbf };

class TRecordset : public TObject
{
  TAssoc_array _var;
  TString_array _varnames;
  const TRecordset* _parentset;

protected:
  bool save_as_html(const char* path);
  bool save_as_silk(const char* path);
  bool save_as_text(const char* path);
  bool save_as_campo(const char* path);
  bool save_as_dbf(const char* table, int mode);
  
  void find_and_reset_vars();
  void parsed_text(TString& sql) const;
  TVariant& get_tmp_var() const;
  bool export_dbf(int logicnum);

public: // Absolutely needed methods
  virtual TRecnotype items() const pure;
  virtual bool move_to(TRecnotype pos) pure;
  virtual TRecnotype current_row() const pure;
  virtual void requery() pure;
  bool empty() const { return items() == 0; }
  virtual const TString& query_text() const pure; 

  virtual bool move_first() { return move_to(0); }
  virtual bool move_prev() { return move_to(current_row()-1); }
  virtual bool move_next() { return move_to(current_row()+1); }
  virtual bool move_last() { return move_to(items()-1); }
  virtual bool bof() const { return current_row() == TRecnotype(-1); }
  virtual bool eof() const { return current_row() >= items(); }
  
  virtual unsigned int columns() const pure;
  virtual const TRecordset_column_info& column_info(unsigned int column) const pure;
  virtual const TVariant& get(unsigned int column) const pure;

  virtual const TString_array& variables() const { return _varnames; }
  virtual const TVariant& get_var(const char* name) const;
  virtual bool set_var(const char* name, const TVariant& var, bool create = false);
  virtual bool ask_variables(bool all);

  virtual int find_column(const char* column_name) const;
  virtual const TVariant& get(const char* column_name) const;
  virtual const TToken_string& sheet_head() const;

  // mode = 0|1=append 2=update 3=update|append 4=zap before writing
  virtual bool save_as(const char* path, TRecordsetExportFormat fmt = fmt_unknown, int mode = 0);

  void set_parent(const TRecordset* rs) { _parentset = rs; }
  TRecordset();
  virtual ~TRecordset() { }
};

///////////////////////////////////////////////////////////
// TSQL_recordset
///////////////////////////////////////////////////////////

class TSQL_recordset : public TRecordset
{
  TString _sql;

  TRecnotype _first_row, _pagesize, _items, _current_row;
  TArray _column;
  TArray _page;

protected:
  virtual void reset();
  void parsed_sql_text(TString& sql) const;

public: // TRecordset
  virtual void requery();
  virtual TRecnotype items() const;
  virtual bool move_to(TRecnotype pos);
  virtual TRecnotype current_row() const { return _current_row; }
  virtual unsigned int columns() const;
  virtual const TRecordset_column_info& column_info(unsigned int c) const;
  virtual const TVariant& get(unsigned int column) const;
  const TString& query_text() const { return _sql; }

public:
  void set(const char* sql);

  // Internal use only
  virtual int on_get_items(int argc, char** values, char** columns);
  virtual int on_get_rows(int argc, char** values);
  const TArray* row(TRecnotype n);

  TSQL_recordset(const char* sql);
  virtual ~TSQL_recordset() { }
};

///////////////////////////////////////////////////////////
// TISAM_recordset
///////////////////////////////////////////////////////////

class TISAM_recordset : public TRecordset
{
  TString _use;
  
  TRelation* _relation;
  TCursor* _cursor;
  TArray _column;     // Column infos
  
protected:
  TRelation* relation() const;

  virtual void reset();
  virtual const TVariant& get(int logic, const char* field) const;
  virtual void set_custom_filter(TCursor& cursor) const { }

public:
  TCursor* cursor() const;
  void set(const char* use);
  virtual void requery();
  virtual TRecnotype items() const;
  virtual bool move_to(TRecnotype pos);
  virtual TRecnotype current_row() const;
  virtual unsigned int columns() const;
  virtual const TRecordset_column_info& column_info(unsigned int c) const;
  virtual const TVariant& get(unsigned int column) const;
  virtual const TVariant& get(const char* column_name) const;
  virtual const TString& query_text() const { return _use; }

  TISAM_recordset(const char* use);
  virtual ~TISAM_recordset();
};

///////////////////////////////////////////////////////////
// TRecordset_sheet
///////////////////////////////////////////////////////////

class TRecordset_sheet : public TSheet
{
  TRecordset& _query;

protected:
  virtual void get_row(long r, TToken_string& row);
  virtual long get_items() const;

public:
  TRecordset_sheet(TRecordset& sql);
};

///////////////////////////////////////////////////////////
// Utility
///////////////////////////////////////////////////////////

bool list_custom_files(const char* ext, const char* library, TString_array& files);
bool select_custom_file(TFilename& path, const char* ext, const char* library = NULL);
const TString& logic2table(int logic_num);
int table2logic(const TString& name);
TRecordset* create_recordset(const TString& sql);


#endif