#ifndef __cmt_symbol_h__
#define __cmt_symbol_h__

#include "cmt_tag.h"
#include "cmt_use.h"

class SymbolValue
{
public:
  typedef cmt_vector<SymbolValue> SymbolValueVector;

  SymbolValue ();
  ~SymbolValue ();

  Tag* tag;
  cmt_string text;         /* A symbol value is created only if */
                           /* its text is non empty */
  int selected;
};

class SymbolValueList
{
public:
  typedef cmt_vector<SymbolValueList> SymbolValueListVector;

  int select_first (const cmt_string& tag_name = "") const;
  int select_last () const;

  CommandType command_type;
  Use* use;
  SymbolValue::SymbolValueVector values;
  bool is_reflexive;
  bool discarded;
};

class Symbol;

class ValueBuilder
{
public:
  virtual const cmt_string& build (const Symbol& symbol,
                                   const cmt_string& tag_name = "") = 0;
  virtual const cmt_string& clean (const Symbol& symbol,
                                   const cmt_string& tag_name = "") = 0;
};

class Symbol
{
public:
  typedef cmt_vector<Symbol> SymbolVector;

  static Symbol* create (const cmt_string& name,
                         CommandType command,
                         ScopeType scope);
  static Symbol* find (const cmt_string& name);
  static void action (const CmtSystem::cmt_string_vector& words,
                      CommandType command_type,
                      Use* use);
  static int is_selected (const cmt_string& name);
  static void all_print (PrintMode mode);
  static void all_print_clean (PrintMode mode);
  static int symbol_number ();
  static SymbolVector& symbols ();
  static Symbol& symbol (int index);
  static void clear_all ();
  static void expand (cmt_string& text);

public:
  Symbol ();
  ~Symbol ();
  bool value_is_reflexive (const cmt_string& text) const;
  void add_value_to_list (CommandType command_type,
                          Use* use,
                          Tag* tag,
                          const cmt_string& text);

  int valid (PrintMode mode);
  int print_clean (int tabs, PrintMode mode);
  int print (int tabs, PrintMode mode);
  cmt_string build_macro_value () const;
  cmt_string clean_macro_value () const;
  cmt_string resolve_macro_value (const cmt_string& tag_name = "");
  void show_macro (PrintMode mode);

  ValueBuilder* builder;

  cmt_string name;          /* The original symbol's name */
  ScopeType scope;          /* copy of the current scope  */
  CommandType command;      /* symbol's type              */

  SymbolValueList::SymbolValueListVector value_lists;

  int selected_value;        /* according to the last selected tag */
};

#endif
