
//  This file forms part of the GOBLIN C++ Class Library.
//
//  Initially written by Christian Fremuth-Paeger, August 2000
//
//  Copying, compiling, distribution and modification
//  of this source code is permitted only in accordance
//  with the GOBLIN general licence information.

/// \file canvasBuilder.h
/// \brief #canvasBuilder class interface

#ifndef _CANVAS_BUILDER_H_
#define _CANVAS_BUILDER_H_

#include "abstractMixedGraph.h"


/// \addtogroup groupCanvasBuilder
/// @{

/// \brief Builder class interface for displaying a canvas or writing canvas files
///
/// This class partially implements the drawing of graph objects in an unspecified
/// file format of graphical tool kit. The class interface also declares the
/// methods which must be implemented by concrete canvas buiders.

class canvasBuilder : protected managedObject
{
protected:

    const abstractMixedGraph &G; ///< The graph object to be displayed
    goblinController CFG;        ///< The context of the displayed object

    enum {LABEL_BUFFER_SIZE = 256};

    char nodeLabelFormat[LABEL_BUFFER_SIZE]; ///< 
    char arcLabelFormat[LABEL_BUFFER_SIZE];
    char tmpLabelBuffer[LABEL_BUFFER_SIZE];

    char predColour[8];
    char inftyColour[8];
    char nodeColour[8];

    TArc maxNodeColour;
    TArc maxEdgeColour;

    const TFloat* piG; ///< 

    double zoom;

    double minX;
    double maxX;
    double minY;
    double maxY;

    double nodeSize;
    double arrowSize;

    double arcLabelSep;

public:

    canvasBuilder(const abstractMixedGraph &GC) throw(ERRejected);
    virtual ~canvasBuilder() throw();

    unsigned long   Allocated() const throw();

    void            ComputeBoundingBox() throw();
    double          ScaleDisplayParameters(double zoomCalibration,double sizeX, double sizeY) throw();

    TFloat          CX(TNode v) throw()
                        {return G.C(v,0);};
    TFloat          CY(TNode v) throw()
                        {return G.C(v,1);};
    int             RoundToInt(double val) const throw()
                        {return ((val<0) ? int(val-0.5) : int(val+0.5));};
    long            RoundToLong(double val) const throw()
                        {return ((val<0) ? long(val-0.5) : long(val+0.5));};


    /// \brief  Determine the canvas X coordinate value of a layout X coordinate
    ///
    /// \param cx  A layout X coordinate value
    /// \return    The corresponding coordinate canvas value
    long  CanvasCX(double cx) throw();

    /// \brief  Determine the canvas Y coordinate value of a layout Y coordinate
    ///
    /// \param cy  A layout Y coordinate value
    /// \return    The corresponding coordinate canvas value
    long  CanvasCY(double cy) throw();

    /// \brief  Determine the canvas X coordinate value of a layout point
    ///
    /// \param v  A node index ranged [0,1,..,n+ni-1]
    /// \return   The ordinate value of v in the canvas
    long  CanvasCXOfPoint(TNode v) throw(ERRange);

    /// \brief  Determine the canvas Y coordinate value of a layout point
    ///
    /// \param v  A node index ranged [0,1,..,n+ni-1]
    /// \return   The abscissa value of v in the canvas
    long  CanvasCYOfPoint(TNode v) throw(ERRange);

protected:

    /// \brief Applied port mode, depending on the layout model of this graph object
    TPortMode portMode;

public:

    /// \brief  Determine the canvas X coordinate value of a virtual port node
    ///
    /// Arcs are not routed in the canvas between the center points of its two
    /// graph end nodes. Instead, two virtual port nodes are introduced which
    /// occur on the border line of the visualization of the end nodes. This
    /// procedure is necessary for the correct alignment of arrow heads, but
    /// works perfectly only if the graph nodes are visualized by circles.
    ///
    /// \param u  A layout point index ranged [0,1,..,n+ni-1]. This point is
    ///           considered to be the control point adjacent with v on the processed arc
    /// \param v  A graph node index ranged [0,1,..,n-1]
    /// \return   The ordinate value of the virtual port node in the canvas
    long  PortCX(TNode u,TNode v) throw();

    /// \brief  Determine the canvas Y coordinate value of a virtual port node
    ///
    /// This is the analogue of PortCX() for the canvas abscissa
    ///
    /// \param u  A layout point index ranged [0,1,..,n+ni-1]. This point is
    ///           considered to be the control point adjacent with v on the processed arc
    /// \param v  A graph node index ranged [0,1,..,n-1]
    /// \return   The abscissa value of the virtual port node in the canvas
    long  PortCY(TNode u,TNode v) throw();

    goblinController &Configuration() throw() {return CFG;};

    virtual void    DisplayGraph() throw(ERRejected);

    enum TArrowDir
    {
        ARROW_NONE = 0,
        ARROW_FORWARD  = 1,
        ARROW_BACKWARD = 2,
        ARROW_BOTH     = 3
    };

    enum TLineStyle
    {
        LINE_STYLE_SOLID    = 0,
        LINE_STYLE_DOT      = 1,
        LINE_STYLE_DASH     = 2,
        LINE_STYLE_DASH_DOT = 3,
        LINE_STYLE_ZIG_ZAG  = 8,
        LINE_STYLE_WAVED    = 16
    };

    enum TArcVisibilityMode
    {
        ARC_DISPLAY_HIDE_ALL     = 0,
        ARC_DISPLAY_SUBGRAPH     = 1,
        ARC_DISPLAY_PREDECESSORS = 2,
        ARC_DISPLAY_PRED_SUB     = 3,
        ARC_DISPLAY_SHOW_ALL     = 4
    };

    enum TArcShapeMode
    {
        ARC_SHAPE_POLYGONES = 0,
        ARC_SHAPE_SMOOTH    = 1
    };

    enum TArcWidthMode
    {
        ARC_WIDTH_UNIFORM          = 0,
        ARC_WIDTH_PREDECESSORS     = 1,
        ARC_WIDTH_SUBGRAPH         = 2,
        ARC_WIDTH_FLOW_LINEAR      = 3,
        ARC_WIDTH_FLOW_LOGARITHMIC = 4,
        ARC_WIDTH_EMPTY_FREE_FULL  = 5
    };

    enum TArcStippleMode
    {
        ARC_STIPPLE_OFF          = 0,
        ARC_STIPPLE_PREDECESSORS = 1,
        ARC_STIPPLE_FREE         = 2,
        ARC_STIPPLE_FRACTIONAL   = 3,
        ARC_STIPPLE_COLOURS      = 4,
        ARC_STIPPLE_VOID         = 5,
        ARC_STIPPLE_SUBGRAPH     = 6
    };

    enum TArcColourMode
    {
        ARCS_UNCOLOURED       = 0,
        ARCS_FIXED_COLOURS    = 1,
        ARCS_REPEAT_COLOURS   = 2,
        ARCS_FLOATING_COLOURS = 3,
        ARCS_COLOUR_PRED      = 4
    };

    enum TArrowDisplayMode
    {
        ARROWS_ARC_ORIENTATION   = 0,
        ARROWS_OFF               = 1,
        ARROWS_IMPL_ORIENTATION  = 2,
        ARROWS_FLOW_DIRECTION    = 3,
        ARROWS_LIKE_PREDECESSORS = 4
    };

    enum TArrowPosMode
    {
        ARROWS_AT_ENDS  = 0,
        ARROWS_CENTERED = 1
    };

    enum TNodeShapeMode
    {
        NODE_SHAPE_POINT     = 0,
        NODE_SHAPE_CIRCULAR  = 1,
        NODE_SHAPE_BOX       = 2,
        NODE_SHAPE_BY_COLOUR = 3
    };

    enum TNodeColourMode
    {
        NODES_UNCOLOURED         = 0,
        NODES_COLOUR_BY_DISTANCE = 1,
        NODES_FIXED_COLOURS      = 2,
        NODES_COLOUR_BY_DEMAND   = 3,
        NODES_FLOATING_COLOURS   = 4
    };

    enum TGridDisplayMode
    {
        GRID_DISPLAY_OFF = 0,
        GRID_DISPLAY_ALL = 1
    };

    /// Font types as expected in the *.fig file format
    enum TXFigFontType
    {
        FONT_TIMES_ROMAN = 0,
        FONT_TIMES_ITALIC = 1,
        FONT_TIMES_BOLD = 2,
        FONT_TIMES_BOLD_ITALIC = 3,
        FONT_AVANTGARDE_BOOK = 4,
        FONT_AVANTGARDE_BOOK_OBLIQUE = 5,
        FONT_AVANTGARDE_DEMI = 6,
        FONT_AVANTGARDE_DEMI_OBLIQUE = 7,
        FONT_BOOKMAN_LIGHT = 8,
        FONT_BOOKMAN_LIGHT_ITALIC = 9,
        FONT_BOOKMAN_DEMI = 10,
        FONT_BOOKMAN_DEMI_ITALIC = 11,
        FONT_COURIER = 12,
        FONT_COURIER_OBLIQUE = 13,
        FONT_COURIER_BOLD = 14,
        FONT_COURIER_BOLD_OBLIQUE = 15,
        FONT_HELVETICA = 16,
        FONT_HELVETICA_OBLIQUE = 17,
        FONT_HELVETICA_BOLD = 18,
        FONT_HELVETICA_BOLD_OBLIQUE = 19,
        FONT_HELVETICA_NARROW = 20,
        FONT_HELVETICA_NARROW_OBLIQUE = 21,
        FONT_HELVETICA_NARROW_BOLD = 22,
        FONT_HELVETICA_NARROW_BOLD_OBLIQUE = 23,
        FONT_NEW_CENTURY_SCHOOLBOOK_ROMAN = 24,
        FONT_NEW_CENTURY_SCHOOLBOOK_ITALIC = 25,
        FONT_NEW_CENTURY_SCHOOLBOOK_BOLD = 26,
        FONT_NEW_CENTURY_SCHOOLBOOK_BOLD_ITALIC = 27,
        FONT_PALATINO_ROMAN = 28,
        FONT_PALATINO_ITALIC = 29,
        FONT_PALATINO_BOLD = 30,
        FONT_PALATINO_BOLD_ITALIC = 31,
        FONT_SYMBOL = 32,
        FONT_ZAPF_CHANCERY_MEDIUM_ITALIC = 33,
        FONT_ZAPF_DINGBATS = 34
    };


    /// \brief  Extract the layout parameters from the attribute pool
    void ExtractParameters() throw();

protected:

    /// \brief Applied arc width mode
    TArcWidthMode arcWidthMode;

    /// \brief Minimum arc width value
    int arcWidthMin;

    /// \brief Maximum arc width value
    int arcWidthMax;

    /// \brief Applied arc stipple mode
    TArcStippleMode arcStippleMode;

    /// \brief Applied arc display mode
    TArcVisibilityMode arcVisibilityMode;

    /// \brief Applied arc shape mode
    TArcShapeMode arcShapeMode;

    /// \brief Applied arc colour mode
    TArcColourMode arcColourMode;

    /// \brief Applied arrow display mode
    TArrowDisplayMode arrowDisplayMode;

    /// \brief Applied arrow position mode
    TArrowPosMode arrowPosMode;

    /// \brief Arrow size, as percents of the default value
    double arrowSizeRel;

    /// \brief Arc postscript font type as required by xfig / fig2dev
    TXFigFontType arcFontType;

    /// \brief Arc font size, as percents of the default value
    double arcFontSize;

    /// \brief Applied node shape mode
    TNodeShapeMode nodeShapeMode;

    /// \brief Applied node colour mode
    TNodeColourMode nodeColourMode;

    /// \brief Node size, as percents of the default value
    double nodeSizeRel;

    /// \brief Node postscript font type as required by xfig / fig2dev
    TXFigFontType nodeFontType;

    /// \brief Node font size, as percents of the default value
    double nodeFontSize;

    /// \brief Applied grid display mode
    TGridDisplayMode gridDisplayMode;

    /// \brief Spacing between arc label and line display
    double fineSpacing;

    /// \brief Spacing between adjacent bend control points
    double bendSpacing;

    /// \brief Spacing between adjacent graph nodes
    double nodeSpacing;

public:

    void        DisplayArc(TArc) throw();
    TArrowDir   ArrowDirections(TArc a) throw();
    void        DisplayArrow(TArc,TNode,TNode) throw();
    void        DisplayArcLabel(TArc a,TNode u,TNode v,TArrowDir displayedCenteredArrows) throw();
    void        ComposeArcLabel(TArc a,ofstream& expFile) throw();
    char*       ArcLabel(TArc,int) throw(ERRejected);
    void        ComposeNodeLabel(TNode v,ofstream& expFile) throw();
    char*       NodeLabel(TNode,int) throw(ERRejected);
    char*       ArcLegenda(int) throw(ERRejected);
    char*       NodeLegenda(char*,int) throw(ERRejected);

    /// \brief  Indices for adressing colours with a special meaning
    enum {
        PRED_COLOUR    = 0, ///< Index representing the colour used for predecessor arcs
        INFTY_COLOUR   = 1, ///< Colour index indicating unreachable nodes (dist == InfFloat)
        NO_COLOUR      = 2, ///< Colour index matching the node colour NoNode
        OUTLINE_COLOUR = 3, ///< Index representing the colour used for outlining
        GRID_COLOUR    = 4, ///< Index representing the colour used for grid lines and the bounding box
        ZERO_COLOUR    = 5, ///< Colour index matching the node and / or edge colour 0
        MAX_COLOUR     = 25 ///< First colour index exeeding the colour table
    };

    /// \brief Translate a node colour index to a string representing fixed colours
    ///
    /// \param c  An internal node colour index
    /// \return   A 6 digit hexadecimal RGB string
    char*       FixedNodeColour(TIndex c) throw();

    /// \brief Translate an edge colour index to a string representing fixed colours
    ///
    /// \param c  An internal edge colour index
    /// \return   A 6 digit hexadecimal RGB string
    char*       FixedEdgeColour(TIndex c) throw();

    /// \brief Translate a colour index to a string representing floating colours
    ///
    /// \param c            A colour to be translated
    /// \param maxColour    The maximal representable colour index
    /// \param undefColour  The default colour for unhandled colour indices
    /// \return             A 6 digit hexadecimal RGB string
    char*       SmoothColour(TIndex c,TIndex maxColour,TIndex undefColour) throw();


    // *************************************************************** //
    //                Prototypes                                       //
    // *************************************************************** //

    virtual void  WriteArc(TArc,TNode,TNode,TLineStyle,int,TArrowDir,TIndex colourIndex,int) throw();

    void  WriteArcSegment(vector<double>& cx,vector<double>& cy,TLineStyle lineStyle,
            int width,TArrowDir displayedArrows,TIndex colourIndex,int depth) throw();

    virtual void  WritePolyLine(vector<double>& cx,vector<double>& cy,TLineStyle lineStyle,
                    int width,TArrowDir displayedArrows,TIndex colourIndex,int depth) throw() = 0;

    void  WriteStraightLine(double cx1,double cy1,double cx2,double cy2,TLineStyle lineStyle,
            int width,TArrowDir displayedArrows,TIndex colourIndex,int depth) throw();

    virtual void    WriteArrow(TArc a,long xtop,long ytop,double dx,double dy) throw() = 0;
    virtual void    WriteArcLabel(TArc a,long xm,long ym) throw() = 0;
    virtual void    DisplayNode(TNode) throw() = 0;
    virtual void    DisplayLegenda(long xm,long ym,long radius) throw() = 0;

    void  DisplayGrids() throw();

};


/// \brief    Colour table lookup operation
///
/// Colour indices exeeding the table are translated to some grey RGB colour.
///
/// \param c  An internal colour index
/// \return   An 24 bit RGB colour
unsigned long  RGBColour(TIndex c) throw();


inline long canvasBuilder::CanvasCX(double cx) throw()
{
    return long((nodeSpacing+cx-minX)*zoom);
}


inline long canvasBuilder::CanvasCY(double cy) throw()
{
    return long((nodeSpacing+cy-minY)*zoom);
}


inline long canvasBuilder::CanvasCXOfPoint(TNode v) throw(ERRange)
{
    return long(CanvasCX(G.C(v,0)));
}


inline long canvasBuilder::CanvasCYOfPoint(TNode v) throw(ERRange)
{
    return long(CanvasCY(G.C(v,1)));
}


extern const char* unixFontType[];


/// @}

#endif
