#ifndef UI_HELPER_H
#define UI_HELPER_H
#include "timers.h"
#include "xio.h"

#ifdef SFFE_USING
#include "sffe.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif
#define MAXFILTERS 20
#define AVRGSIZE 50
#define NMESSAGES 5
#define BGCOLOR(uih) uih->palette->index[0]
#define FGCOLOR(uih) uih->palette->index[1]
#define SELCOLOR(uih) uih->palette->index[2]
#define DARKGRAYCOLOR(uih) uih->palette->index[3]
#define LIGHTGRAYCOLOR(uih) uih->palette->index[4]
#define LIGHTGRAYCOLOR2(uih) uih->palette->index[5]
#define NONTRANSPARENTW 1
#define DRAWBORDER 2
#define BORDER_PRESSED 4
#define BORDER_TRANSPARENT 8
#define BORDER_LIGHT 16

struct uih_message {
    char *message[NMESSAGES];
    tl_timer *messagetimer[NMESSAGES];
    int messagetype[NMESSAGES];
    struct uih_window *w[NMESSAGES];
    int pid[NMESSAGES];
    int messagestart;
};
struct uih_line {
    int key;
    int morph;
    int color;
    int posmode;
    number_t x1, y1, x2, y2;
    int mposmode;
    number_t mx1, my1, mx2, my2;
    struct uih_line *next, *prev;
    struct uih_window *w;
};
struct uih_lines {
    struct uih_line *first;
    int morphing;
    int currkey;
};

struct uih_savedcontext {
    xio_file file;
    int mode;
    number_t speedup, maxstep;
    number_t xcenter, ycenter;
    tl_timer *timer;
    tl_timer *synctimer;
    struct fractal_context *fcontext;
    int clearscreen;
    int fastmode, juliamode, fastrotate, autorotate;
    number_t rotationspeed;
    int firsttime;
    int filter[MAXFILTERS];
    int pressed;
    int rotatepressed;
    int cycling;
    int shifted;
    int manualpaletteshift;
    int direction;
    int cyclingspeed;
    int zoomactive;
    int xtextpos, ytextpos;
    int writefailed;
    int nonfractalscreen;
    int color;
};
#define MAXLEVEL 10		/*Maximal include level */
struct uih_playcontext {
    xio_file file;
    xio_file prevfiles[MAXLEVEL + 1];
    int level;
    xio_path directory;
    tl_timer *timer;
    int waittime;
    int playframe;
    int timerin;
    int frametime, starttime;
    int morph;
    int morphtimes[2];
    int morphjulia;
    int morphjuliatimes[2];
    int morphangle;
    int morphangletimes[2];
    vinfo destination;
    vinfo source;
    number_t srcangle, destangle;
    number_t sr, si, dr, di;
    int readfailed;
    int line;
    struct uih_lines lines;
    int morphlinetimes[2];
};
#define SQR(val) (((double)(val))*(val))
#define MORPHVALUE(time,len,starttime,endtime) \
(time)<0?0.0 \
    :(time)>=(len)?1.0 \
        :(time)<(starttime) && (starttime)?(SQR((time)/(double)(starttime))/2*(starttime)/((len)-(starttime)/2-(endtime)/2))\
            :((len)-(time)<(endtime)) && (endtime)?1-(SQR(((len)-(time))/(double)(endtime))/2*(endtime)/((len)-(starttime)/2-(endtime)/2)) \
                :((time)-(starttime)/2)/((double)(len)-(starttime)/2-(endtime)/2)
#ifdef _NEVER_
#define MORPHVALUE(time,len,starttime,endtime) \
                (((time))/((double)(len)))
#endif
#define DOMORPH(time,len,starttime,endtime,startval,endval) \
                ((startval)+((endval)-(startval))*MORPHVALUE(time,len, starttime,endtime))

#define UNDOLEVEL 256
                struct uih_undocontext {
    int last;
    char *undos[256];
};
struct uih_context {
    void (*updatemenus) (struct uih_context *, const char *);
    /*stuff that should be visible from outside */
    number_t speedup, maxstep;	/*zooming speed */

    /* Informations provided to the user interface: */
    const char *menuroot;
    int display;		/*1 when ui wants to display something */
    int save;		/*1 if save animation is enabled */
    int play;		/*1 if animation replay is active */
    int cycling;		/*1 if cycling is enabled */
    int incalculation;	/*1 if calulcation is currently in process */
    int flags;
    int interrupt;		/*set to interrupt current calculation */

    /*server's callbacks */
    int (*passfunc) (struct uih_context *, int, const char *, float);
    void (*longwait) (struct uih_context *);

    struct uih_undocontext undo;
    /*Filter system state */
    struct image *image;
    struct palette *palette;
    struct fractal_context *fcontext;	/*fractal informations */
    struct queue *queue;
    struct filter *uifilter;	/*user interface layer */
    struct filter *rotatef;	/* Special filters handler by ui_helper: */
    struct filter *zengine;
    struct filter *fixedcolor;
    /*Julia/filter mechanizm */
    struct filter *subwindow, *julia, *smalliter;
    struct filter *filter[MAXFILTERS];

    /*General status variables */
    double mul;		/*speed of last iteration */
    int rotatemode;		/*ROTATE_NONE, ROTATE_CONTINUOUS or ROTATE_NONE */
    number_t rotationspeed;	/*speed of continuous rotation */
    int fastmode;		/*when draw in fast mode */
    int juliamode;
    int fastrotate;
    int uncomplette;	/*1 if image is not complettly caluclated or in animation */
    int dirty;		/*1 if image is inexact */
    int inanimation;	/*1 if uih_update wants to be called soon */
    int fastanimation;	/*1 if animation needs to be fast */
    int palettetype, paletteseed;	/*0 for default palette,1,2 for random */
    int clearscreen;	/*1 when ui want to clear screen */
    int indofractal;	/*1 when caluclation is in the process */
    int xtextpos, ytextpos;	/*possitioning of text */
    int color;		/*Color of text */
    int recalculatemode;	/*informations for user interface */
    int stoppedtimers;	/*1 when timers are stopped */
    int nletters;		/*Number of letters displayed at screen */
    int letterspersec;	/*Number of letters per second user should read */
    char *text[3];		/*Currently displayed text informations: */
    struct uih_window *textwindow[3], *cscreenwindow;
    int textpos[3], textcolor[3];
    const char *errstring;	/*String of last unprocessed error */

    const struct xfont *font;	/*Font used by UI */
    struct uih_window *wtop;
    int wflipped;
    int wdisplayed;

    /*Save variables */
    int todisplayletters;
    struct uih_savedcontext *savec;
    int viewchanged;	/*When to generate setview commands */
    int palettechanged;	/*When to generate setpalette commands */
    int displaytext;	/*When text was displayed in this frame */
    int nonfractalscreen;
    /*waiting variables */
    void (*complettehandler) (void *);	/*Handler to be activated when calculation is complette */
    void *handlerdata;
    /*replay variables */
    struct uih_playcontext *playc;
    int playpos;
    const char *playstring;

    /*For constant framerate */
    struct timeemulator *emulator;
    int emulatedframetime;
    int aliasnum;
    int fixedstep;

    /*zoom/unzoom */
    number_t speed, step;
    number_t xcenter, ycenter;
    int xcenterm, ycenterm;
    int zoomactive;

    /*drag&drop move */
    int pressed;
    number_t oldx, oldy;
    int moved;

    /*drag&drop rotate */
    int rotatepressed;
    number_t oldangle;

    int ddatalost;
    int tbreak;

    int autopilot;		/*for uih side of autopilot */
    int autopilotx, autopiloty, autopilotbuttons;

    /*calculation time variables */
    int interruptiblemode;
    int starttime, endtime;
    int maxtime;

    /*dynamical timeout measuring */
    int times[2][AVRGSIZE];	/*for statistics */
    int timespos, count[2];
    double lastspeed, lasttime;

    /*number_t xsize, ysize; */
    tl_timer *maintimer, *cyclingtimer, *autopilottimer,
    *calculatetimer, *doittimer;
    tl_group *autopilotgroup;

    /*color cycling values */
    int direction;
    int cyclingdirection;
    int stopped;
    int cyclingspeed;

    /*autopilot internal values */
    int x1, y1, c1;
    number_t minsize;
    number_t maxsize;
    int autopilotversion;
    int autime;
    int minlong;
    int interlevel;

    /*saved palettes */
    struct palette *palette2;

    int paletteshift;
    int manualpaletteshift;

    struct uih_message messg;

    /*Used by uih_update to figure out when save undo */
    int lastbuttons;

    int encoding;

    /* performers really don't want text echoed to the screen */
    int inhibittextoutput;

    /* user data */
    void *data;

#ifdef SFFE_USING
    /*User formulas (used in sffe parser) */
    /*sffe *cparser;  user define c evaluation formula, not used now, not used yet */
    sffe *parser;		/* fractal formula */
    sffe *pinit;
#endif

};
typedef void (*uih_getposfunc) (struct uih_context * c, int *x, int *y,
                                int *width, int *height, void *data);
typedef void (*uih_drawfunc) (struct uih_context * c, void *data);
struct uih_window {
    int x, y, width, height;
    uih_getposfunc getpos;
    uih_drawfunc draw;
    struct uih_window *next;
    struct uih_window *previous;
    int savedline, savedpos;
    char *saveddata;
    void *data;
    int flags;
};
typedef struct uih_context uih_context;

#define UIH_SAVEALL 2
#define UIH_SAVEANIMATION 1
#define UIH_SAVEPOS 0

#define UIH_PALETTEDRAW -2
#define UIH_FILTERANIMATION -1
#define UIH_INTERRUPTIBLE 0
#define UIH_ANIMATION 1
#define UIH_NEW_IMAGE 2
#define UIH_UNINTERRUPTIBLE 3
#define FRAMETIME (1000000/FRAMERATE)

#define UIH_TEXTTOP 0
#define UIH_TEXTMIDDLE 1
#define UIH_TEXTBOTTOM 2

#define UIH_TEXTLEFT 0
#define UIH_TEXTCENTER 1
#define UIH_TEXTRIGHT 2

#define RANDOM_PALETTE_SIZE 1
#define FULLSCREEN 2
#define UPDATE_AFTER_PALETTE 4
#define UPDATE_AFTER_RESIZE 8
#define PALETTE_ROTATION 16
#define ASYNC_PALETTE 32
#define ROTATE_INSIDE_CALCULATION 64
#define PALETTE_REDISPLAYS 128
#define SCREENSIZE 256
#define PIXELSIZE 512
#define RESOLUTION 1024

#define BUTTON1 256
#define BUTTON2 512
#define BUTTON3 1024

#define ROTATE_NONE 0
#define ROTATE_MOUSE 1
#define ROTATE_CONTINUOUS 2

#define uih_needrecalculate(context) ((context)->recalculatemode)
#define uih_needdisplay(context) ((context)->display)
#define GETMAX(a,b) ((a)>(b)?(a):(b))
#define uih_newimage(c) ((c)->display=1,((c)->recalculatemode=GETMAX((c)->recalculatemode,UIH_NEW_IMAGE)))
#define uih_animate_image(c) ((c)->display=1,(c)->recalculatemode=GETMAX((c)->recalculatemode,UIH_ANIMATION))

#define uih_updatemenus(uih,c) if(uih->updatemenus!=NULL) uih->updatemenus(uih,c);

extern const struct filteraction *const uih_filters[MAXFILTERS];
extern const int uih_nfilters;

struct uih_context *uih_mkcontext(int flags, struct image *image,
                                  int (*passfunc) (struct uih_context
                                                   *, int,
                                                   const char *,
                                                   float),
                                  void (*longwait) (struct uih_context
                                                    *),
                                  void (*updatemenus) (struct
                                                       uih_context * c,
                                                       const char *));
int uih_updateimage(uih_context * c, struct image *img);
void uih_freecontext(uih_context * c);


void uih_callcomplette(uih_context * c);
/*palette functions */
void uih_mkdefaultpalette(uih_context * c);
void uih_mkpalette(uih_context * c);
void uih_savepalette(uih_context * c);
void uih_restorepalette(uih_context * c);
void uih_loadpalette(uih_context * c, struct palette *palette);

/*autopilot handling */
void uih_autopilot_on(uih_context * c);
void uih_autopilot_off(uih_context * c);

/*misc functions */
int uih_update(uih_context * c, int mousex, int mousey,
               int mousebuttons);
const char *uih_save(struct uih_context *c, xio_constpath filename);
void uih_tbreak(uih_context * c);
double uih_displayed(uih_context * c);
void uih_do_fractal(uih_context * c);
void uih_prepare_image(uih_context * c);
void uih_interrupt(uih_context * c);
void uih_stopzooming(uih_context * c);
void uih_setspeedup(uih_context * c, number_t speed);
void uih_setmaxstep(uih_context * c, number_t speed);
void uih_setcomplettehandler(uih_context * c, void (h) (void *),
                             void *d);
void uih_recalculate(struct uih_context *c);
void uih_initstate(struct uih_context *uih);
void uih_screentofractalcoord(uih_context * c, int mousex, int mousey,
                              number_t * re, number_t * im);


/*cycling functions */
void uih_cycling_off(struct uih_context *c);
void uih_cycling_stop(struct uih_context *c);
void uih_cycling_continue(struct uih_context *c);
void uih_setcycling(struct uih_context *c, int speed);
int uih_cycling_on(struct uih_context *c);
int uih_cycling(struct uih_context *c, int mode);

/*fractal context manipulation routines */
void uih_setformula(uih_context * c, int formula);
void uih_setperbutation(uih_context * c, number_t re, number_t im);
void uih_perbutation(uih_context * c, int mousex, int mousey);
void uih_setmaxiter(uih_context * c, int maxiter);
void uih_setbailout(uih_context * c, number_t bailout);
void uih_setincoloringmode(uih_context * c, int mode);
void uih_setoutcoloringmode(uih_context * c, int mode);
void uih_setintcolor(uih_context * c, int mode);
void uih_setouttcolor(uih_context * c, int mode);
void uih_setplane(uih_context * c, int mode);
void uih_setmandelbrot(uih_context * c, int mode, int mousex,
                       int mousey);
void uih_setfastmode(uih_context * c, int mode);
void uih_setguessing(uih_context * c, int range);
void uih_setperiodicity(uih_context * c, int periodicity);
void uih_display(uih_context * c);
void uih_disablejulia(uih_context * c);
int uih_enablejulia(uih_context * c);
int uih_setjuliamode(uih_context * c, int mode);
void uih_setjuliaseed(uih_context * c, number_t zre, number_t zim);

/*filter manipulation */
int uih_enablefilter(uih_context * c, int n);
void uih_disablefilter(uih_context * c, int n);

/*Animation save routines */
int uih_save_enable(struct uih_context *uih, xio_file f, int mode);
void uih_save_disable(struct uih_context *uih);
void uih_saveframe(struct uih_context *uih);
void uih_save_possition(struct uih_context *uih, xio_file f, int mode);

void uih_load(struct uih_context *uih, xio_file f, xio_constpath name);
void uih_loadstr(struct uih_context *uih, const char *data);
void uih_playstr(struct uih_context *uih, const char *data);
void uih_playupdate(struct uih_context *uih);
void uih_replaydisable(struct uih_context *uih);
void uih_skipframe(struct uih_context *uih);
int uih_replayenable(struct uih_context *uih, xio_file f,
                     xio_constpath filename, int animroot);
void uih_command(struct uih_context *uih, const char *command);
void uih_playtutorial(struct uih_context *c, const char *name);

/* Easy to use functions for handling save/load*/
void uih_loadfile(struct uih_context *uih, xio_constpath d);
void uih_playfile(struct uih_context *c, xio_constpath d);
void uih_loadexample(struct uih_context *c);
void uih_savepngfile(struct uih_context *c, xio_constpath d);
void uih_saveposfile(struct uih_context *c, xio_constpath d);
char *uih_savepostostr(struct uih_context *c);
void uih_savecfg(struct uih_context *c);
void uih_saveanimfile(struct uih_context *c, xio_constpath d);
void uih_update_lines(uih_context * c);


/*timer functions */
void uih_stoptimers(uih_context * c);
void uih_resumetimers(uih_context * c);
void uih_slowdowntimers(uih_context * c, int time);

/*text output functions */
void uih_clearscreen(uih_context * c);
void uih_settextpos(uih_context * c, int x, int y);
void uih_text(uih_context * c, const char *text);
void uih_letterspersec(uih_context * c, int n);

/*image rotation functions */
int uih_fastrotate(uih_context * c, int mode);
int uih_fastrotateenable(uih_context * c);
void uih_fastrotatedisable(uih_context * c);
void uih_angle(uih_context * c, number_t angle);
void uih_rotatemode(uih_context * c, int mode);
void uih_rotate(uih_context * c, int mode);
void uih_rotationspeed(uih_context * c, number_t speed);

/*Catalog functions */
int uih_loadcatalog(uih_context * c, const char *name);
void uih_freecatalog(uih_context * c);

void uih_registermenus(void);
void uih_registermenus_i18n(void);
void uih_registermenudialogs_i18n(void);
void uih_unregistermenus(void);

/*Windows :)*/
struct uih_window *uih_registerw(struct uih_context *uih,
                                 uih_getposfunc getpos,
                                 uih_drawfunc draw, void *data,
                                 int flags);
void uih_removew(struct uih_context *uih, struct uih_window *w);
void uih_clearwindows(struct uih_context *uih);
void uih_drawwindows(struct uih_context *uih);
void uih_drawborder(struct uih_context *uih, int x, int y, int width,
                    int height, int flags);
void uih_setline(struct uih_context *uih, struct uih_window *w,
                 int color, int x1, int y1, int x2, int y2);
struct uih_window *uih_registerline(struct uih_context *uih, int color,
                                    int x1, int y1, int x2, int y2);


/*Messages*/
void uih_scrollup(uih_context * c);
void uih_clearmessages(uih_context * c);
int uih_message(uih_context * c, const char *message);
int uih_error(uih_context * c, const char *error);
void uih_rmmessage(uih_context * c, int pid);
void uih_printmessages(uih_context * c);

/*Constant framerate functions*/
void uih_emulatetimers(uih_context * c);
void uih_constantframetime(uih_context * c, int time);
void uih_noconstantframetime(uih_context * c);

/*undo and redo*/
void uih_saveundo(uih_context * c);
void uih_undo(uih_context * c);
void uih_redo(uih_context * c);

void uih_setfont(uih_context * c);

/*animation rendering*/
int uih_renderanimation(struct uih_context *gc, const char *basename,
                        const xio_constpath animation, int width,
                        int height, float pixelwidth,
                        float pixelheight, int frametime, int type,
                        int antialiasing, int slowmode,
                        int letterspersec, const char *catalog,
                        int motionvectors, int iframedist2);
int uih_renderimage(struct uih_context *gc1, xio_file af,
                    xio_constpath path, struct image *img,
                    int antialias, const char *catalog, int noise);

void uih_initmessages(uih_context * c);
void uih_destroymessages(uih_context * c);
void uih_inittext(uih_context * c);
void uih_destroytext(uih_context * c);

void uih_inhibittextsw(uih_context * c);
int uih_inhibittextselected(uih_context * c);

#ifdef __cplusplus
}
#endif
#endif
