// #################################
//
//           Prescribble
//
//        (C)opyright 2001 
//           by Kent Dahl 
//
//        MenThal@bigfoot.com
//  http://www.bigfoot.com/~MenThal/
//
//    Released under the GPL 
//     (Gnu Public License)
//
//       Use at own risk. 
//
// ##################################

#ifndef prescribble_hpp
#define prescribble_hpp

/*
 * -+* Prescribble *+-
 * 
 * by Kent Dahl ( MenThal@bigfoot.com )
 *
 * Jot down illegible notes for your self, quickly and easily without
 * arguing with a HWR engine or cryptic input.
 *
 * "Prescribble: Just as illegible as the prescription from your doctor!"
 * "Prescribble: So hard to read, you'll need prescription glasses!"
 *
 * A FLTK based program for the Agenda VR3.
 * 
 */

#include <vector>

class PresAction;

struct Point2D{
    typedef int CoordValue;
    CoordValue x, y;

    Point2D(int a_x =0, int a_y=0);

    bool isWithinRange( Point2D dst, int range = 0 );
    unsigned int manhattan(Point2D);

    void writeto( ostream & out );

    Point2D operator+(const Point2D&);

};



struct Rect2D{
    Point2D ul; // upper left
    Point2D br; // bottom right

    enum CollisionType { NONE=0, OVERLAP, OUTSIDE, INSIDE };

    Rect2D();
    Rect2D( Point2D a, Point2D b );

    void fenceIn( Point2D );

    bool isValid() const;
    bool isWithin( Point2D ) const;
    CollisionType collides( Rect2D ) const;

    int width() const;
    int height() const;

};

/**
 * drawing context for callback when deciding how the lines are to be drawn.
 * May also be used as means of iterating over all the line segments.
 */
class PresStrokeDrawingContext {
public:
    virtual void drawLine( Point2D, Point2D ) = 0;
};


/**
 * a single graphical stroke stored in vector graphic form.
 */
class PrescribbleStroke {
public:
    typedef std::vector<Point2D> Point2DVector;
    typedef std::vector<PrescribbleStroke*> StrokePtrVector;
    typedef PresStrokeDrawingContext DrawingContext;

    Point2DVector m_points;
    Rect2D m_boundingRect;


    void add( Point2D p);

    const Rect2D getBoundingRect() const 
        { return m_boundingRect; }


    StrokePtrVector clippingAway( Rect2D , bool keepInside = false);


    void drawAllLines( DrawingContext &a_context );    

    void writeto( ostream & out );

};



struct PresNoteConfig {
    unsigned int m_maxRedoStrokes;
    unsigned int m_eraseRange;

    bool m_experimental; // turns on experimental features


    PresNoteConfig(unsigned int max, unsigned int range )
        : m_maxRedoStrokes(max), m_eraseRange(range),
        m_experimental(false){}
};


class PrescribbleNoteListener {
public:
    virtual void updateRedoStatus(bool) = 0;
    virtual void updateUndoStatus(bool) = 0;
};


class PrescribbleNote {
//protected:
public:
    typedef std::vector<PrescribbleStroke*> StrokePtrVector;
    typedef PrescribbleStroke::DrawingContext DrawingContext;

    typedef PresAction Action;
    typedef std::vector<Action*> ActionList;

    StrokePtrVector m_strokes;
    StrokePtrVector m_deletedStrokes;

    ActionList m_undoableActions, m_redoableActions;

    PrescribbleStroke *m_pCurrentStroke;

    PresNoteConfig &m_config;


    PrescribbleNoteListener *m_pListener;
public:


    struct FindResult {
        bool found; // only use result if this is true
        StrokePtrVector::iterator foundStroke;
        PrescribbleStroke::Point2DVector::iterator foundPoint;
        unsigned int manhattan;
        Point2D searchPoint;
    };


    PrescribbleNote( PresNoteConfig &a_config, 
                     PrescribbleNoteListener *a_pListener = 0);
    ~PrescribbleNote();

    void beginStroke( Point2D p );

    void continueStroke( Point2D p);
    void endStroke( Point2D p );

    PrescribbleStroke *lastStroke();

    void undoStroke();
    void redoStroke();

    void undoAction();
    void redoAction();
    void   doAction( Action & );

    bool anyRedosLeft();
    bool anyUndosLeft();


    bool       requestEraseAt( Point2D );
    FindResult findPoint(      Point2D );


    void add(    PrescribbleStroke &a_stroke );
    void remove( PrescribbleStroke &a_stroke );


    Action* erase(      StrokePtrVector::iterator &it );
    void erasePoint(      PrescribbleNote::FindResult &found );
    Action* splitAtPoint( PrescribbleNote::FindResult &found );

    Action* eraseRectAction( Rect2D, DrawingContext* a_context = 0 );
    void    eraseRect(       Rect2D );

    void writeto( ostream & out );
    void cleanOut();

    void drawAllLines( DrawingContext &a_context );
    void drawLastStroke( DrawingContext &a_context );

    void updateListeners();
 

};




/**
 * namespace for XML-ish tag names
 */
class Pres {
public:
static const char *NOTEBOOK_TAG_BEGIN;//= "<notebook>";
static  const char *NOTE_TAG_BEGIN ;//= "<note>";
static  const char *STROKE_TAG_BEGIN ;//= "<stroke>";

static  const char *NOTEBOOK_TAG_END ;//= "</notebook>";
static  const char *NOTE_TAG_END ;//="</note>";
static  const char *STROKE_TAG_END ;//= "</stroke>";
};



#endif
