// $Id$
// Store information about all displayed display expressions

// Copyright (C) 1995 Technische Universitaet Braunschweig, Germany.
// Written by Dorothea Luetkehaus <luetke@ips.cs.tu-bs.de>.
// 
// This file is part of DDD.
// 
// DDD is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
// 
// DDD is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public
// License along with DDD -- see the file COPYING.
// If not, see <http://www.gnu.org/licenses/>.
// 
// DDD is the data display debugger.
// For details, see the DDD World-Wide-Web page, 
// `http://www.gnu.org/software/ddd/',
// or send a mail to the DDD developers <ddd@gnu.org>.

#ifndef _DDD_DispGraph_h
#define _DDD_DispGraph_h

//-----------------------------------------------------------------------------
// The `DispGraph' class keeps all displayed display expressions
//-----------------------------------------------------------------------------

// Misc includes
#include "strclass.h"
#include "bool.h" 
#include "Graph.h" 
#include "HandlerL.h"
#include "LineGraphE.h"
#include "PosGraphN.h"
#include "GraphNPA.h"
#include "DispNodeM.h"

//-----------------------------------------------------------------------------

enum Displaying {Both, Enabled, Disabled};

// Event types
const unsigned DispGraph_Empty = 0;          // DispGraph is empty
const unsigned NoEnabled  = DispGraph_Empty + 1;
const unsigned NoDisabled = NoEnabled + 1;

const unsigned DispGraph_NTypes = NoDisabled + 1;

class DispGraph: public Graph {
public:
    DECLARE_TYPE_INFO

private:
    DispNodeMap  idMap;
    HandlerList  handlers;
    bool         no_enabled;
    bool         no_disabled;

public:
    static bool hide_inactive_displays;

    // Constructor
    DispGraph();

    // Clear all nodes
    void clear();
    
    // Destructor
    ~DispGraph();

    int count_all ()             const { return idMap.length(); }
    int count_all (Displaying e) const;
    int count_selected() const;
    bool has_enabled() const { return !no_enabled; }
    bool has_disabled() const { return !no_disabled; }


    void addHandler (unsigned    type,
		     HandlerProc proc,
		     void*       client_data = 0);

    void removeHandler (unsigned    type,
			HandlerProc proc,
			void        *client_data = 0);
    void callHandlers();


    // Insert a new display DN named DISP_NR dependent on DEPENDS_ON.
    // Return new display number, or 0 iff failure.
    int insert(int disp_nr, DispNode* dn, int depends_on = 0);

    // Make DISP_NR an alias of ALIAS_DISP_NR.  Suppress
    // ALIAS_DISP_NR.  Return true iff changed.
    bool alias (Widget w, int disp_nr, int alias_disp_nr);

    // Un-alias ALIAS_DISP_NR.  Unsuppress ALIAS_DISP_NR.  Return true
    // iff changed.
    bool unalias (int alias_disp_nr);

    // (In)activate display NODE.  Return true iff changed.
    bool make_active (DispNode *node);
    bool make_inactive (DispNode *node);

    // (Un)cluster display NODE into CLUSTER
    void cluster(DispNode *node, int cluster);
    inline void uncluster(DispNode *node)
    {
	cluster(node, 0);
    }

    // Determine default positions for NEW_NODE
    BoxPoint default_pos(DispNode *new_node, Widget w, 
			 int depends_on = 0) const;

    // Delete DISP_NR; return false if non-existent
    bool del (int disp_nr);

    // Return node of display DISP_NR
    DispNode* get (int disp_nr) const { return idMap.get (disp_nr); }

    // Return number of display NAME
    int get_by_name(const string& name) const;

    // Return number of node NODEPTR
    int get_nr(BoxGraphNode *nodeptr) const;

    // Return true iff display has a display numbered DISP_NR
    bool contains (int disp_nr) const { return idMap.contains (disp_nr); }
    
    // Return first/next node; return 0 if non-existent
    DispNode* first (MapRef& ref, Displaying e = Both) const;
    DispNode* next  (MapRef& ref, Displaying e = Both) const;

    // Return first/next node number; return 0 if non-existent
    int first_nr (MapRef& ref, Displaying e = Both) const;
    int next_nr  (MapRef& ref, Displaying e = Both) const;

    // Print graph to OS
    void print(std::ostream& os, const GraphGC& gc = GraphGC()) const
    {
	Graph::print(os, gc);
    }

    // Print plots to FILENAME
    void print_plots(const string& filename, 
		     const GraphGC& gc = GraphGC()) const;

    // Refresh title settings
    bool refresh_titles() const;

protected:
    BoxPoint adjust_position (DispNode *new_node,
			      Widget w,
			      BoxPoint pos,
			      const BoxPoint& offset,
			      BoxPoint grid) const;

    // Add a new alias edge
    void add_alias_edge(Widget w, int alias_disp_nr,
			GraphNode *from, GraphNode *to,
			EdgeAnnotation *anno);

    // Remove node or edge from memory as well as from graph
    void delete_node(GraphNode *node);
    void delete_edge(GraphEdge *edge);

private:
    static void disp_node_disabledHP(void *, void *, void *);

    // Alias edge routing stuff
    // True iff R->P1 and R->P2 have the same angle
    static bool same_angle(const BoxPoint& r,
			   const BoxPoint& p1, const BoxPoint& p2);

    // True iff NODE is attached to an edge with the same angle as P
    static bool has_angle(PosGraphNode *node, const BoxPoint& p);

    void add_edge(DispNode *from, DispNode *to);
    
    void add_direct_alias_edge(Widget w, int alias_disp_nr, 
			       GraphNode *from, GraphNode *to,
			       EdgeAnnotation *anno);
    void add_routed_alias_edge(Widget w, int alias_disp_nr, 
			       PosGraphNode *from, PosGraphNode *to,
			       EdgeAnnotation *anno);

    bool is_hidden(Widget w, const BoxPoint& p) const;
    static BoxPoint rotate_offset(const BoxPoint& p, int angle);

    // Check whether P1 and P2 are okay as hint positions for FROM and TO
    bool hint_positions_ok(Widget w,
			   PosGraphNode *from, PosGraphNode *to,
			   const BoxPoint& p1, const BoxPoint& p2) const;

    // Find all hints in edges leading to NODE; store them in HINTS
    static void find_hints_to(GraphNode *node, GraphNodePointerArray& hints);

    // Find all hints in edges coming from NODE; store them in HINTS
    static void find_hints_from(GraphNode *node, GraphNodePointerArray& hints);

    // Hide/Unhide all alias edges of NODE according to its status
    void update_alias_edges(DispNode *node);
};

#endif // _DDD_DispGraph_h
// DON'T ADD ANYTHING BEHIND THIS #endif
