// file: vtable.h
// author: Andrew Hynek
// contents: a value table (VTable) class
#ifndef __vtable_h__
#define __vtable_h__
class File;
class VTable
{
  static const int MAX_SECTION_LENGTH = 32;
  static const int MAX_FIELD_LENGTH = 32;
  static const int MAX_LINE_LENGTH = 256;
  struct field
  {
    char name[MAX_FIELD_LENGTH];
    char line[MAX_LINE_LENGTH];
    char *multiline;
    field() : multiline(NULL)
    {
      *name = '\0';
      *line = '\0';
    }
    ~field();
    field &operator=(const field &two)
    {
      // do a deep copy
      strcpy(name, two.name);
      strcpy(line, two.line);
      if (two.multiline) {
        if (!multiline) {
          multiline = new char[strlen(two.multiline)+1];
          strcpy(multiline, two.multiline);
        } else if (strcmp(multiline, two.multiline)) {
          delete [] multiline;
          multiline = new char[strlen(two.multiline)+1];
          strcpy(multiline, two.multiline);
        }
      } else if (multiline) {
        delete [] multiline;
        multiline = NULL;
      }
      return (*this);
    }
  };
  struct section
  {
    char name[MAX_SECTION_LENGTH]; // NULL for top
    section *parent;
    section *sub_tab;
    int sub_cnt;
    int sub_size;
    field *field_tab;
    int field_cnt;
    int field_size;
    section() : parent(NULL),
        sub_tab(NULL), sub_cnt(0), sub_size(0),
        field_tab(NULL), field_cnt(0), field_size(0)
    {
      *name = '\0';
    }
    ~section();
    section &operator=(const section &two)
    {
      strcpy(name, two.name);
      parent = two.parent;
      if (two.sub_tab && two.sub_cnt > 0) {
        sub_size = two.sub_size;
        sub_cnt = two.sub_cnt;
        if (sub_tab)
          delete [] sub_tab;
        sub_tab = new section[sub_size];
        for (int i = 0; i < sub_cnt; i++)
          sub_tab[i] = two.sub_tab[i];
      } else {
        sub_cnt = 0;
        sub_size = 0;
        if (sub_tab) {
          delete [] sub_tab;
          sub_tab = NULL;
        }
      }
      if (two.field_tab && two.field_cnt > 0) {
        field_size = two.field_size;
        field_cnt = two.field_cnt;
        if (field_tab)
          delete [] field_tab;
        field_tab = new field[field_size];
        for (int i = 0; i < field_cnt; i++)
          field_tab[i] = two.field_tab[i];
      } else {
        field_cnt = 0;
        field_size = 0;
        if (field_tab) {
          delete [] field_tab;
          field_tab = NULL;
        }
      }
      return (*this);
    }
  };
  section top;
public:
  int  NumSections() const;
  int  NumSubsections(const char *sect);
  int  NumFields(const char *sect_name);
  bool DoesSectionExist(const char *sect);
  bool DoesFieldExist(const char *where);
  // returns the number of fields successfully parsed
  int Parse(File *in);
  int GetInt(const char *where, int defawlt);
  long GetLong(const char *where, long defawlt);
  // assumes lookup_tab is "\n"-terminated, returns index of string in tab
  int LookupInt(const char *where, const char **lookup_tab, int defawlt);
  const char *GetString(const char *where, const char *defawlt);
  float GetFloat(const char *where, float defawlt);
  // returns a pointer (don't delete) to field name of nth field in section
  const char *GetIndexField(const char *sect_name, int n);
  // like GetIndexField, but for subsection names
  const char *GetIndexSection(const char *sect_name, int n);
  // returns the int of the nth field in section
  int GetIndexInt(const char *sect_name, int n, int defawlt);
  const char *GetIndexString(const char *sect_name, int n,
                             const char *defawlt);
  // float GetIndexFloat();
  // bool AddInt(const char *where, int n);
  // bool AddString(const char *where, const char *str);
  // bool AddFloat(const char *where, float f);
private:
  static void separate(const char *where,
                       char section[MAX_SECTION_LENGTH],
                       char field[MAX_FIELD_LENGTH]);
  void resize_subsection_tab(section *ptr, int empty = 5);
  void resize_field_tab(section *ptr, int empty = 5);
  field *find_field(const char *where);
  section *find_section(const char *sect);
  section *look_for_section(section *ptr, const char *name);
  int count_subsections(const section *ptr) const;
};
#endif // ifndef __vtable_h__