//-----------------------------------------------------------
// Copyright Christian Arnault LAL-Orsay CNRS
// arnault@lal.in2p3.fr
// Modified by Grigory Rybkin
// See the complete license in cmt_license.txt "http://www.cecill.info". 
//-----------------------------------------------------------

#ifndef __cmt_symbol_h__
#define __cmt_symbol_h__

#include "cmt_tag.h"
#include "cmt_use.h"
#include "cmt_map.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;
  void show (const Symbol& symbol, const SymbolValue& value, bool& first_definition) const;
  int print (const Symbol& symbol, const SymbolValue& value, bool& first_definition, ostream& out = cout) const;

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

class Symbol;

class ValueBuilder
{
public:
  ValueBuilder ();
  const cmt_string build_and_display (const Symbol& symbol);
  int print (const Symbol& symbol, ostream& out = cout);

  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;
 protected:
  bool m_display_it;
};

class Symbol
{
public:
  typedef cmt_vector<Symbol> SymbolVector;
  typedef cmt_map<cmt_string, Symbol> SymbolMap;

  typedef enum
    {
      SymbolUndefined,
      SymbolAction,
      SymbolAlias,
      SymbolMacro,
      SymbolSetupScript,
      SymbolCleanupScript,
      SymbolSet,
      SymbolPath
    } SymbolType;

  static Symbol* create (const cmt_string& name,
                         CommandType command,
                         Use* use = 0);
  
  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_set ();
  static void all_print (PrintMode mode, ostream& out = cout);
  //static void all_print (PrintMode mode);
  static void all_print_clean (PrintMode mode);
  static void check_all_paths ();

  static int symbol_number ();
  static SymbolVector& symbols ();
  static SymbolMap& symbol_map ();
  static SymbolMap& std_env_vars ();
  static Symbol& symbol (int index);
  static void clear_all ();
  static void expand (cmt_string& text);

  static void filter_path_value (const cmt_string& name, cmt_string& text);

  static bool check_tag_used (const Tag* tag);

  static cmt_string get_env_value (const cmt_string& name);

  static bool get_inhibit_display ();
  static bool set_strip_path (const bool& strip_path);

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 print_clean (PrintMode mode);
  int print (PrintMode mode, ostream& out = cout);
  //int print (PrintMode mode);
  cmt_string build_macro_value (bool display_it = false) const;
  int print_macro (PrintMode mode, ostream& out = cout) const;
  cmt_string clean_macro_value () const;
  cmt_string resolve_macro_value (const cmt_string& tag_name = "") const;
  void show_macro (PrintMode mode, ostream& out = cout);
  //  void show_macro (PrintMode mode);

  ValueBuilder* builder;

  cmt_string name;
  ScopeType scope;
  SymbolType type;

  SymbolValueList::SymbolValueListVector value_lists;

  int selected_value;        /* according to the last selected tag */
  bool printed;

private:

  static bool m_inhibit_display;  // Global inhibitor of any display

};

#endif
