#ifndef __BLOP_GROB_H__
#define __BLOP_GROB_H__

#include "length.h"
#include "terminal.h"
#include <vector>

namespace blop
{
    class pad;
    class container;

    /*
      grob == GRaphical OBject
      This is meant to be the base class for all graphical objects
    */


    class grob
    {
	friend class container;
    private:
	container *parent_;
	std::string name_;
        bool autodel_;

    protected:

	virtual bool parent(container *p);

	    // When a grob is added into a container, the container
	    // calls this function to notify the grob about being
	    // added into a container. Derived classes can overload
	    // this function to make additional bookkeeping, but
	    // they should always call grob::parent(...) as well.
	    // If the function returns false (as in the case of
	    // the 'canvas'), it means that this object can not
	    // be added into a container, and the container will not
	    // store a reference to this object

	int print_me_;

	    // indicates status:
	    // 0 ==> do not print this object, do not specialize its lengths
	    // 1 ==> do not print, but calculate lengths
	    // 2 ==> print

	static length &default_x_unit_();
	static length &default_y_unit_();
	static bool default_use_parent_x_unit_, default_use_parent_y_unit_;

	length x_unit_, y_unit_, parent_cwidth_, parent_cheight_;

	bool modified_;

	var layer_;

    public:

	string name() const {return name_;}
	void   name(const string &s) {name_ = s;}
	virtual bool modified() const { return modified_; }
	virtual void modified(bool f) { modified_ = f;    }

	// ---------- Returns the parent of this grob  ------------------------------------

	virtual container       *parent()       { return parent_; }
        virtual const container *parent() const { return parent_; }


	static void default_x_unit(length l);
	static void default_y_unit(length l);
	static void default_unit(length);
	enum { use_parent = 100 };
	static void default_x_unit(int);
	static void default_y_unit(int);
	static void default_unit(int);

	length x_unit();
	length y_unit();
	grob &x_unit(length);
	grob &x_unit(int);
	grob &y_unit(length);
	grob &y_unit(int);
	grob &unit(length);
	grob &unit(int);

	// --------------------------------------------------------------------------------
	// This member function should make all necessary preparations,
	// which are needed for the object to be drawn (axes have to
	// calculate their ranges, lengths have to be registered, etc)
	// The different graphical objects, depending on their type,
	// will need different sets of lengths in order to be
	// drawn onto a terminal. These lengths will have to be
	// specialized (see length.h). In order to specialize all
	// needed lengths, they should be registered (length::register_me())
	// This member function should call length::register_me() on
	// the lengths, which are needed for it to be drawn.
	
	virtual void prepare_for_draw() = 0;


	
	// --------------------------------------------------------------------------------
	// grobs can be contained in containers. Sine grobs can be 
	// created as automatic variables also (when their destructor
	// is automatically called when they scope expires), containers
	// do not deallocate these objects when they are cleared.
	// However, when creating grobs dynamically (operator new),
	// one's task is easier if containers deallocate the
	// objects. 
	// Containers (when deleted or cleared) will deallocate
	// those grobs in them, which have autodel=true 
	// autodel is false by default
	
        grob &autodel(bool b) { autodel_ = b; return *this; }
	bool autodel() const  { return autodel_; }

	// ---------- change layer --------------------------------------------------------

	virtual grob      &layer(const var &l)  { layer_ = l; return *this; }
	virtual const var &layer() const { return layer_; }


	grob();


	// --------------------------------------------------------------------------------
	// The destructor scans all existing containers (every container
	// is registered behind the scenes), and removes the currently 
	// destroyed grob from all containers, so you never have to worry,
	// that a container holds a reference to an unexisting grob.

	virtual ~grob();



	virtual void print(terminal *) = 0;


	// --------------------------------------------------------------------------------
	// switch on or off the object (that is, the object will
	// be printed or not)

	virtual void on ()       {print_me_ = 2;}   // object will be printed
	virtual void invisible() {print_me_ = 1;}   // object not printed, but lengths calculated
	virtual void off()       {print_me_ = 0;}   // not printed, no lengths are calculated
	virtual int  visibility() const { return print_me_; } 


	virtual void print_hierarchy(int level=0);
    };


}



#endif