#ifndef __TREE_H
#define __TREE_H

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

class TTree;
class TImage;

#define SCAN_PRE_ORDER           1
#define SCAN_IN_ORDER            2
#define SCAN_POST_ORDER          4
#define SCAN_IGNORING_UNEXPANDED 8
#define SCAN_IGNORING_LEAVES     16

typedef bool (*NODE_HANDLER)(TTree& tree, void* jolly, word flags);

// classe per un albero navigabile in una direzione 
// (depth first o breadth first)
class TTree : public TObject
{ 
protected:
  TAssoc_array _expanded;
  TArray _image;
  // helpers for image(bool)
  TImage* get_res_image(short id) const;  
  TImage* get_res_icon(short id) const;

protected:
  virtual void node2id(const TObject* node, TString& id) const pure;

public:  
  virtual bool goto_root() pure;
  virtual bool goto_firstson() pure;
  virtual bool goto_rbrother() pure; 
  virtual bool goto_node(const TString &id) pure;
  virtual TObject* curr_node() const pure;
  
  virtual bool has_root() const;
  virtual bool has_father() const;
  virtual bool has_son() const;
  virtual bool has_lbrother() const;
  virtual bool has_rbrother() const;

  virtual bool goto_father();
  virtual bool goto_lbrother();
  
  virtual bool add_son(TObject* obj = NULL) { return false; }
  virtual bool add_son(const TObject& obj) { return false; }
  virtual bool add_brother(TObject* obj = NULL) { return false; }
  virtual bool add_brother(const TObject& obj) { return false; }
  virtual bool add_rbrother(TObject* obj = NULL) { return false; }
  virtual bool add_rbrother(const TObject& obj) { return false; }
  virtual bool add_lbrother(TObject* obj = NULL) { return false; }
  virtual bool add_lbrother(const TObject& obj) { return false; }
  virtual bool kill_node() { return false; }

  virtual void curr_id(TString& id) const { node2id(curr_node(), id); }
  virtual bool get_description(TString& desc) const { curr_id(desc); return desc.not_empty(); }

  virtual bool expand();
  virtual bool shrink();
  virtual bool expanded() const;
  virtual bool shrunk() const { return !expanded(); }
  virtual bool expand_all();
  virtual bool shrink_all();
  virtual TImage* image(bool selected) const;
  virtual bool enabled() const { return true; }
  bool disabled() const { return !enabled(); }
  virtual bool marked() const { return false; } // Colored background

  virtual bool scan_depth_first(NODE_HANDLER nh, void* jolly, word flags = SCAN_PRE_ORDER);
  virtual bool scan_breadth_first(NODE_HANDLER nh, void* jolly, word flags = SCAN_PRE_ORDER);
    
  TTree() {}
  virtual ~TTree() {}
};


// classe per un albero navigabile in due direzioni
class TBidirectional_tree : public TTree
{  
public:
  virtual bool goto_node(const TString &id);
  virtual bool scan_depth_first(NODE_HANDLER nh, void* jolly, word flags = SCAN_PRE_ORDER);
  virtual bool scan_breadth_first(NODE_HANDLER nh, void* jolly, word flags = SCAN_PRE_ORDER);

  TBidirectional_tree() {}
  virtual ~TBidirectional_tree() {}
};

class TObject_tree : public TBidirectional_tree
{
  struct TTree_node : public TObject
  { 
    bool _expanded;
    TTree_node *_father, *_son, *_rbrother, *_lbrother;
    TObject* _obj;
    
    TTree_node() : _expanded(false), _father(NULL), _son(NULL), _rbrother(NULL), _lbrother(NULL), 
                   _obj(NULL) { }
    
    virtual ~TTree_node() { if (_obj) delete _obj; }
  };
  TTree_node *_root, *_current;

  bool create_root();  // Internal use only

protected:
  virtual void node2id(const TObject* node, TString& id) const;
  
public: // TTree  
  virtual bool goto_root();
  virtual bool goto_firstson();
  virtual bool goto_rbrother(); 
  virtual bool has_root() const { return _root != NULL; }
  virtual bool has_son() const { return _current && _current->_son; }
  virtual bool has_rbrother() const { return _current && _current->_rbrother; }
  virtual TObject* curr_node() const { return _current ? _current->_obj : NULL; }
  
  virtual bool add_son(TObject* obj = NULL);
  virtual bool add_son(const TObject& obj);
  virtual bool add_brother(TObject* obj = NULL);
  virtual bool add_brother(const TObject& obj);
  virtual bool add_rbrother(TObject* obj = NULL);
  virtual bool add_rbrother(const TObject& obj);
  
  virtual void curr_id(TString& id) const { node2id(_current, id); }
  virtual bool get_description(TString& str) const;
  virtual bool goto_node(const TString &id);
  
  virtual bool expand();
  virtual bool shrink();
  virtual bool expanded() const;
   
public: // TBidirectional_tree  
  virtual bool has_father() const { return _current && _current->_father; }
  virtual bool has_lbrother() const { return _current && _current->_lbrother; }
  virtual bool goto_father();
  virtual bool goto_lbrother();
  virtual bool add_lbrother(TObject* obj = NULL);
  virtual bool add_lbrother(const TObject& obj);

public:      
  bool set_object(TObject* obj);
  bool set_object(const TObject& obj);
  virtual bool kill_node();
  
  TObject_tree();
  virtual ~TObject_tree();
};

///////////////////////////////////////////////////////////
// TString_tree
///////////////////////////////////////////////////////////

class TString_tree : public TObject_tree
{
public:  // TTree
  virtual bool get_description(TString& str) const;

public: // TString_tree 
  virtual bool add_son(const char* str) 
  { return TObject_tree::add_son(new TString(str)); }
  
  virtual bool add_brother(const char* str) 
  { return TObject_tree::add_brother(new TString(str)); }

  virtual bool add_rbrother(const char* str) 
  { return TObject_tree::add_rbrother(new TString(str)); }

  virtual bool add_lbrother(const char* str) 
  { return TObject_tree::add_lbrother(new TString(str)); }
};

#endif //__TREE_H