// #################################
//
//           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 prescribblearea_hpp
#define prescribblearea_hpp

#include <FL/Fl_Box.H>
#include <FL/Fl_Pixmap.H>

#include <iostream>
#include <string>
#include <functional>

#include <X11/Xlib.h>
#include <FL/x.H>


#include "prescribble.hpp"
#include "presaction.hpp"

/**
 * class for doing X specific stuff.
 * Except for the ctor and dtor, all these methods
 * may only be used in a context where the X specific
 * parts of FLTK are valid.
 * That is, in draw() methods, after window()->make_current()
 * and similar
 */
class PresXServer {
public:
//    Display *m_display;
//    GC m_gc;
    Pixmap m_pixmap;
//    Fl_Pixmap* m_pPixmap;
//    int m_screen;

    float m_scale;
    Point2D m_upperLeft;

public:
    PresXServer();
    ~PresXServer();

    void create(int,int);
    void splatAt(int, int, 
                 int width=256, int height=256, 
                 int src_x = 0, int src_y = 0);


    void zoom(bool in);
    void zoom(Point2D, Point2D);
    void restrain();
    void moveUpperLeft(Point2D diff);

    void set_fl_matrix();
    void reset_fl_matrix();

    Point2D translateFromScreen( Point2D screenPos );
    Point2D translateToScreen(   Point2D worldPos );


//    static PresXServer m_theXServer;
};









class PresConfig;
class PrescribbleArea;


/**
 * configuration for prescribble
 */
struct PresConfig : PresNoteConfig {
    bool horizlines;
    bool vertlines;
    
    int  horizlinespace;
    int  vertlinespace;

    int pointrange;  
    std::string filename;
    bool quietSaveOnExit;
    bool quietLoadOnEntry;

    bool onlyCheatRedrawDuringMouseDown;

    bool allowZipUsage;
    char *unzipTmpFile;
    char *zipExtension;
    


    PresConfig();
    void sanitize();

  
};


//============== CALLBACKS ================0

struct CallbackBase {
    virtual void callback();
    static void cb( Fl_Widget *w, void *data);
};



struct PresArea_Callback : public CallbackBase {
    PrescribbleArea *m_pThat;
    std::mem_fun1_t<int,PrescribbleArea,void*>  m_fptr;
    void *m_data;

    PresArea_Callback( PrescribbleArea *a_pThat,
                      int (PrescribbleArea::*a_pFunc)(void*),
                      void *a_data = 0);

    void callback();

};




//================
class MouseStrokeReciever {
public:
    virtual int mousePush(    Point2D ) = 0;
    virtual int mouseDrag(    Point2D ) = 0;
    virtual int mouseRelease( Point2D ) = 0;
};


class MouseStrokeAdapter : public MouseStrokeReciever
{
protected:
    PrescribbleArea *m_pArea;
public:
    MouseStrokeAdapter( PrescribbleArea *a_area );

};






class StrokeBox : public MouseStrokeAdapter
{
protected:
    Point2D m_first, m_last;
public:
    StrokeBox( PrescribbleArea *a_area );

    virtual int mousePush(    Point2D ) ;
    virtual int mouseDrag(    Point2D ) ;
    virtual int mouseRelease( Point2D ) ;
};


class StrokeEraser : public StrokeBox
{
protected:
    PresComplexAction *m_pActions;
    Point2D m_prev;
    int m_width;
public:
    StrokeEraser( PrescribbleArea *a_area );

    virtual int mousePush(    Point2D ) ;
    virtual int mouseDrag(    Point2D ) ;
    virtual int mouseRelease( Point2D ) ;

 //   void setNote( PrescribbleNote *a_note);
};


class StrokeDeleter : public StrokeEraser
{
public:
    StrokeDeleter( PrescribbleArea *a_area );

    virtual int mouseDrag(    Point2D ) ;
};

class StrokeFlattener : public StrokeEraser
{
public:
    StrokeFlattener( PrescribbleArea *a_area );

    virtual int mouseDrag(    Point2D ) ;
};



class ScrollStroke : public MouseStrokeAdapter
{
    Point2D m_prev, m_curr;
public:
    ScrollStroke( PrescribbleArea *a_area );

    virtual int mousePush(    Point2D ) ;
    virtual int mouseDrag(    Point2D ) ;
    virtual int mouseRelease( Point2D ) ;

};

class ZoomStroke : public StrokeBox
{
public:
    ZoomStroke( PrescribbleArea *a_area );

//    virtual int mousePush(    Point2D ) ;
//    virtual int mouseDrag(    Point2D ) ;
    virtual int mouseRelease( Point2D ) ;

};


class EllipseStroke : public StrokeBox
{
public:
    EllipseStroke( PrescribbleArea *a_area );

//    virtual int mousePush(    Point2D ) ;
//    virtual int mouseDrag(    Point2D ) ;
    virtual int mouseRelease( Point2D ) ;

};




class NewStrokeEraser : public StrokeBox
{
public:
    NewStrokeEraser( PrescribbleArea *a_area );

    virtual int mouseRelease( Point2D ) ;
};





class PrescribbleArea : public Fl_Box, 
                        public virtual PrescribbleStroke::DrawingContext,
                        public virtual MouseStrokeReciever
{
protected:

    PrescribbleNote *m_pCurrentNote;

    Point2D prevPos, currPos;
    bool mouseIsDown;
    bool dirty;

    bool m_addGuideLines;
    int m_guideLineSpacing;

    bool m_addVerticalGuideLines;
    int m_verticalGuideLineSpacing;

    Fl_Color m_guideLineColor;

    PresConfig m_config;

    MouseStrokeReciever *m_pMouseStrokeReciever;

    StrokeEraser     m_draggingStrokeEraser;
    NewStrokeEraser  m_strokeEraser;
    StrokeDeleter m_strokeDeleter;
    StrokeBox     m_strokeBox;

    ScrollStroke  m_scrollstroke;
    ZoomStroke    m_zoomstroke;
    EllipseStroke m_ellipsestroke;

public:
    PresXServer m_theXServer;


    PresArea_Callback m_cleaner, m_undoer, m_redoer, m_redrawer,
        m_eraser, m_dragEraser, m_eraserDel, m_setDrawMode, m_setBoxMode,
        m_setScrollMode, m_setZoomMode, m_setEllipseMode;

    PrescribbleNoteListener *m_pListener;

public:

    PrescribbleArea( PrescribbleNote *note,
                     int x1, int y1, int x2, int y2, 
                     PresConfig &a_config, 
                     PrescribbleNoteListener *listener = 0);



    void draw ();

    int addLine();

    // mouse stroke reciever
    int mousePush(Point2D p);
    int mouseDrag(Point2D p);
    int mouseRelease(Point2D p);

    virtual int handleKeyboard();
    virtual int handle( int event );

    void setDirty( bool a_state = true );


    int redrawArea(void*);
    int cleanArea(void*);
    int undoStroke(void*);
    int redoStroke(void*);

    void updateUndoRedoFeedback();

    int setDrawMode(void*);
//    int setNormalDrawMode(void*);
//    int eraseStroke(void*);
//    int eraseDelStroke(void*);

    int resetStrokeMode(void*);

    void zoom(int);

    void drawLine( Point2D, Point2D );


    void setCurrentNote( PrescribbleNote *a_pNote );

    PrescribbleNote *getCurrentNote();

};









#endif
