/*
 * re_data.h
 *
 * A programmers editor
 *
 * Structures to hold the current file contents.
 *
 * HEADER FILE
 *
 * Author: Dario Rodriguez antartica@whereismybit.com
 * This program is licensed under the terms of GNU GPL v2.1+
 */

#include <limits.h>

#ifndef RE_DATA_H
#define RE_DATA_H
#define MAXPLUGINNAME 32

typedef struct question_t {
        int active;
        int is_postload;
        char *id;
        char *title,*titleshort;
        char *body,*bodyshort;
        int nopts;
        char **opts,**optsshort;
        int defaultoption;
        int selectedoption;
} question_t;

typedef struct whatin_t {
        int nlcount;
        int iscontinuation;
} whatin_t;

typedef struct rechunk_t {
        whatin_t whatin;
        int whatin_fresh;
        int useddata;
        unsigned char data[1];
} rechunk_t;

typedef struct undo_t {
        char type;
        long off;
        long len;
        long posorig;
        long posdest;
        int hint_groupedwithnext;
#ifdef REDATA_HASHUNDO
        char prehash[129];
        char posthash[129];
#endif
} undo_t;

typedef struct undostack_t {
        int sizeundo;
        int usedundo;
        undo_t *undo;
        int groupinit;
        long sizebuf;
        long usedbuf;
        char *buf;
} undostack_t;

typedef struct redata_plugin_t {
        int active;
        char name[MAXPLUGINNAME];
        char *questionfilename[PATH_MAX];
        question_t question;
        int (*unregister)(/*redata_t *redata, redata_plugin_t *plugin,char *filename*/);
        int (*wipe)(/*redata_t *redata, redata_plugin_t *plugin,char *filename*/);
        int (*loadquestion)(/*redata_t *redata, redata_plugin_t *plugin,char *filename */);
        int (*postload)(/*redata_t *redata, redata_plugin_t *plugin,char *filename */);
        int (*postsave)(/*redata_t *redata, redata_plugin_t *plugin,char *oldfilename,char *newfilename*/);
        int (*add_or_unadd)(/*redata_t *redata, redata_plugin_t *plugin,undo_t *undo, int is_unadd*/);
        int (*commit)(/*redata_t *redata, redata_plugin_t *plugin,char *filename*/);
        void *userptr;
} redata_plugin_t;

typedef struct redata_t {
        char filename[PATH_MAX];
        int needs_saving;
        /* data */
        long chunkdatasize;
        int sizechunks;
        rechunk_t **chunks;
        long available;
        rechunk_t *tmpchunk;
        long sizeaddnbuf;
        char *addnbuf;
        /* undo */
        undostack_t undostack;
        undostack_t redostack;
        /* plugins */
        int sizeplugins;
        redata_plugin_t plugins[1];
} redata_t;

redata_t *redata_init( int (*pluginregisterfn)(redata_t *redata, redata_plugin_t *slot), ...);
void redata_free(redata_t *redata);
void redata_idleproc(redata_t *redata, char *filename);

int redata_config_chunkdatasize(redata_t *redata, int chunkdatasize);

long redata_getsize(redata_t *redata);
long redata_getused(redata_t *redata);
long redata_getavailable(redata_t *redata);
int redata_getposptr(redata_t *redata, long pos, int *numchunk, int *offset);
int redata_getchar(redata_t *redata, long pos);
int redata_getdata(redata_t *redata, long frompos, long size, char *dest);
 
/* low level stuff */
int redata_wipe(redata_t *redata);
int redata_preallocate(redata_t *redata, long size);
int redata_chunk_insertnew(redata_t *redata, int afterthischunk);
int redata_chunk_deletechunk(redata_t *redata, int chunkno);
int redata_chunk_movedata(redata_t *redata, int chunkfrom, long posfrom, int chunkto, long posto, long size);
int redata_chunk_insertdata(redata_t *redata, int chunkto, long posto, char *buf, long buflen);
int redata_chunk_deletedata(redata_t *redata, int chunkno, long pos, long n);
int redata_chunk_splithere(redata_t *redata, int chunkno, int pos);
int redata_chunk_fillfromnext(redata_t *redata, int chunkno, int n);
int redata_chunk_unfreshnext(redata_t *redata, int chunkno);
int redata_chunk_unfreshrange(redata_t *redata, int fromchunkno, int tochunkno);

int redata_whatin_refresh(redata_t *redata, int chunkno);
int redata_fix_nl(redata_t *redata, int chunkno);
int redata_undobuf_reserve(redata_t *redata, undostack_t *stack, int minavail);
undo_t *redata_undo_new(redata_t *redata, undostack_t *stack, char type);
undo_t *redata_undo_newfromchunks(redata_t *redata, undostack_t *stack, char type, int pos1, int len);
undo_t *redata_undo_newfrombuf(redata_t *redata, undostack_t *stack, char type, char *buf, int buflen);
int redata_undo_movelast(redata_t *redata, undostack_t *from, undostack_t *to);
int redata_undo_removelast(redata_t *redata, undostack_t *stack);
int redata_undo_wipe(redata_t *redata, undostack_t *stack);
int redata_undo_inactivatelast(redata_t *redata, undostack_t *stack);
int redata_undo_reactivatelast(redata_t *redata, undostack_t *stack);
int redata_undo_groupinit(redata_t *redata, undostack_t *stack);
int redata_undo_groupcommit(redata_t *redata, undostack_t *stack);

/* high level stuff */
int redata_loadquestions_setup(redata_t *redata, char *filename);
question_t *redata_loadquestions_getnext(redata_t *redata);
int redata_loadquestions_reply(redata_t *redata, question_t *question, int selectedoption);
int redata_loadquestions_wipe(redata_t *redata);

int redata_load(redata_t *redata, char *filename, char **errordesc);
int redata_save(redata_t *redata, char *filename, char **errordesc);

int redata_needssaving(redata_t *redata);
int redata_needssaving_reset(redata_t *redata);

int redata_op_add(redata_t *redata, long pos, char *buf, long buflen, undostack_t *fromhere);
int redata_op_addn(redata_t *redata, long pos, char character, long n, undostack_t *fromhere);
int redata_op_del(redata_t *redata, long pos, long size, undostack_t *fromhere);
int redata_op_move(redata_t *redata, long posorig, long size, long posdest, undostack_t *fromhere);
int redata_op_undo(redata_t *redata, long *newcursorpos);
int redata_op_redo(redata_t *redata, long *newcursorpos);

int redata_data_compare(redata_t *redata, long pos, char *buf, long buflen);

int redata_compact(redata_t *redata);

int redata_hash(redata_t *redata, char *resbuf129bytes);
int redata_filehash(redata_t *redata, char *filename, char *resbuf129bytes);
int redata_memhash(redata_t *redata, char *buf, long buflen, char *resbuf129bytes);
undostack_t *redata_getstack(redata_t *redata, undo_t *undo);

char *redata_generic_genname(char *filename,char *prefix, char *postfix, char *buf, int bufsize);

/* search */
long redata_searchforward(redata_t *redata, long posini, char *str, int len);
long redata_searchbackwards(redata_t *redata, long posini, char *str, int len);
int redata_memcmp(redata_t *redata, long pos, char *str, int len);

int redata_getutf8char(redata_t *redata, long pos, char *buf, int len, int *usedbuf);
int redata_getprevutf8char(redata_t *redata, long pos, char *buf, int len, int *usedbuf);
int redata_getsubstr(redata_t *redata, long posini, long posend, char *buf, int len, int *usedbuf);

/* utf8 convenience functions */

/* calculate the number of utf8-charaters in buffer */
int redata_generic_utf8len(char *ptr, int size);

/* calculate the number of utf8-charaters in buffer ignoring incomplete multibytechars at start and end */
int redata_generic_utf8lenincomplete(char *ptr, int size, int *nstartincomplete,int *nendincomplete, int *nendrequired
);

/* return a pointer to the "n"th ("col"th) utf8-character in buffer */
char *redata_generic_utf8col(char *ptr, int size, int col);
/* returns the len in bytes of the character starting at ptr (zero on error)*/
int redata_generic_utf8charlen(char *ptr, int maxsize);
/* returns true if it's the first byte of an UTF char */
int redata_generic_utf8isstartbyte(int candidate);


/* line convenience funtions */
/* get pointer to full line (if it doesn't fit in a chunk, is_continuation is 1 and/or doesn't have an ending nl */
int redata_line_rawinfo(redata_t *redata, long pos, long *startpos, char **startptr, int *len, int *is_continuation);
/* get the startpos of line, even if it doesn't fit in one chunk */
int redata_line_realstart(redata_t *redata, long pos, long *startpos);
/* get the endpos of line, even if it doesn't fit in one chunk */
int redata_line_realend(redata_t *redata, long pos, long *endpos);
/* get pos of previous line real start */
int redata_line_prevrealstart(redata_t *redata, long pos, long *startpos);
/* get pos of next line real start */
int redata_line_nextrealstart(redata_t *redata, long pos, long *startpos);
/* advance "n" cols */
int redata_line_inccol(redata_t *redata, long pos, int ncolrequest, long *newpos, int *ncoldone);
/* get the line/col of a pos (col is calculated using the utf8 convenience functions) */
int redata_pos2linecol(redata_t *redata, long pos, int *line, int *col);
/* get the pos of that line/col (calculated using the utf8 convenience functions) */
int redata_linecol2pos(redata_t *redata, int line, int colrequest, long *pos, int *coldone);

int redata_line_total(redata_t *redata);
int redata_line_getendstr(redata_t *redata, int line, char *buf, int sizebuf);
int redata_line_getendstrtrimmed(redata_t *redata, int line, char *buf, int sizebuf, char *trimchars);
int redata_line_getsize(redata_t *redata, int line); /* includes the \n */
int redata_line_getstartstr(redata_t *redata, int line, char *buf, int sizebuf);
int redata_line_getstartstrtrimmed(redata_t *redata, int line, char *buf, int sizebuf, char *trimchars);

#endif