#ifndef __SHEET_H
#define __SHEET_H

#ifndef __ARRAY_H
#include <array.h>
#endif

#ifndef __STRINGS_H
#include <strings.h>
#endif

#ifndef __WINDOW_H
#include <window.h>
#endif

#ifndef __RELATION_H
class TCursor;
#endif

#ifndef __MASKFLD_H
class   TEdit_field;
#endif

// @C
// class TSheet : public TScroll_window
// @END

class TSheet : public TScroll_window
{
  // @DPRIV
  enum { MAX_BUT = 8, MAX_COL = 128 };
  TArray _page;

  byte _columns;
  byte _size[MAX_COL], _type[MAX_COL];
  long _curr, _last_update;

  short _visible_rows;

  bool _checkable;
  bool _check_enabled;
  TBit_array _checked;

  WINDOW _button[MAX_BUT];
  KEY    _key[MAX_BUT];
  byte _buttonmask;

protected:
  // @FPROT
  bool head_on() const { return _columns > 1; }
  bool buttons_on() const { return *_button != NULL_WIN; }
  short visible_rows() const { return _visible_rows; }
  virtual short reserved_rows() const;
  void build_page(long first = -1);

  PNT log2dev(long x, long y) const;
  virtual void handler(WINDOW win, EVENT* ep);
  virtual bool on_key(KEY);
  virtual void update();
  virtual void open();

  void set_first(long n);
  bool is_visible(long n) const { return n >= first() && n < first()+visible_rows(); }

  int width() const;
  int row_to_page(long n) const;
  int row_to_win(long n) const;

  long first() const { return origin().y; }
  bool update_row(long n);
  void invert_row(long n);

  void set_row(const TToken_string& row, byte n);

  virtual void repos_buttons() const;

  virtual void page_build(long first, byte num) pure;

  void print();
public:
  // @FPUB
  TSheet(short x, short y, short dx, short dy,
         const char* title, const char* head, byte buttons = 0,
         long first = 0L, WINDOW parent = NULL_WIN);
  void add_button(short id, const char* caption, KEY key = K_ESC);

  virtual long items() const pure;
  virtual TToken_string& row(long s = -1);

  long selected() const { return _curr; }
  void select(long n);

  bool checked(long n) const { return _checked[n]; }
  void check(long n, bool on = TRUE);
  void uncheck(long n) { check(n, FALSE); }
  void enable_check(bool yn = TRUE) { _check_enabled = yn; }
  void disable_check() { enable_check(FALSE); }
  bool one_checked() const { return _checked.first_one() != -1; }
  long checked() const { return _checked.ones(); }
};

class TArray_sheet : public TSheet
{
  TArray _data;

protected:

  virtual void page_build(long first, byte num);

  TArray& data() const { return (TArray&)_data; }
  TToken_string& data(long n) const { return (TToken_string&)_data[(int)n]; }

public:
  TArray_sheet(short x, short y, short dx, short dy, const char* caption,
               const char* head, byte buttons = 0, WINDOW parent = NULL_WIN);
  virtual long items() const { return _data.items(); }
  long add(const TToken_string& s);
  long add(TToken_string* s);
  long insert(const TToken_string& s, long n);
  virtual TToken_string& row(long s = -1) { return (s < 0) ? data(selected()) : data(s); }
  bool destroy(int i = -1) { uncheck(-1); return _data.destroy(i, TRUE); }
};


class TCursor_sheet : public TSheet
{
  TArray _fields;       // Array of TRecfield
  long _records;

protected:
  TCursor* _cursor;

  virtual void page_build(long first, byte rows);

public:
  TCursor_sheet(TCursor* cursor, const char* fields,
                const char* title, const char* head, byte buttons = 0);
  virtual ~TCursor_sheet() {}
  virtual long items() const { return _records; }
  virtual KEY run();
};


class TBrowse_sheet : public TCursor_sheet
{
  TEdit_field* const _field;

protected:
  virtual void handler(WINDOW win, EVENT* ep);
  virtual short reserved_rows() const;
  virtual void repos_buttons() const;
  virtual bool on_key(KEY k);
  TEdit_field& field() { return *_field; }

public:
  TBrowse_sheet(TCursor* cursor, const char* fields,
                const char* title, const char* head, byte buttons, 
                TEdit_field* f, TToken_string* siblings = NULL);
  virtual ~TBrowse_sheet() {}
  virtual KEY run();
};


#endif