/*
 * recenteditor.c
 *
 * A programmers editor
 *
 * Author: Dario Rodriguez dario@softhome.net
 * This program is licensed under the terms of GNU GPL v2.1+
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
#include <signal.h>

#include "re_data.h"
#include "re_ui.h"
#include "ext/socklib.h"

typedef struct re_t {
        redata_t *redata;
        reui_t *ui;
        int flag_newfile;
        char filename[PATH_MAX];
        int x, y, w, h; // contents rect
} re_t;

volatile int flag_sigint;
volatile int flag_sigpipe;


static int setsignal(int num, void (*sighandler)(int));
static void sighandler_sigint(int num);
static void sighandler_sigpipe(int num);


re_t *re_init(void);
void re_free(re_t *re);

int re_setfilename(re_t *re, char *filename);
int re_processkey(re_t *re, SDL_Event *event);
int re_drawcontents(re_t *re);


int
main(int argc, char *argv[])
{
        re_t *re;
        int do_exit;
        SDL_Event event;
        sselect *ssel;
        if(argc!=2 || strcmp(argv[argc-1],"--help")==0) {
                fprintf(stderr,"Syntax: %s filename\n",argv[0]);
                return(1);
        }
        if((re=re_init())==NULL) {
                fprintf(stderr,"ERROR: couldn't init structs.\n");
                return(2);
        }
        if((ssel=sselect_init())==NULL) {
                fprintf(stderr,"ERROR: couln't init internal data.\n");
                re_free(re),re=NULL;
                return(2);
        }
        if(re_setfilename(re,argv[argc-1])!=0) {
                fprintf(stderr,"ERROR: filename too long.\n");
                re_free(re),re=NULL;
                return(2);
        }
        if((redata_load(re->redata,re->filename,NULL,NULL))!=0)
                re->flag_newfile=1;
        else
                re->flag_newfile=0;
#warning TESTS
        {
                char buf[129];
                redata_hash(re->redata,buf);
                fprintf(stderr,"%s %s\n",buf,re->filename);
        }
#warning TODO
        reui_title(re->ui,re->filename);
        flag_sigint=flag_sigpipe=0;
        setsignal(SIGINT,sighandler_sigint);
        setsignal(SIGPIPE,sighandler_sigpipe);
        do_exit=0;
        if((ssel=sselect_init())==NULL) {
                fprintf(stderr,"ERROR: filename too long.\n");
                re_free(re),re=NULL;
                return(2);
        }
        reui_scr2renderer(re->ui,0,0,re->ui->w,re->ui->h);
        re->x=0,re->y=re->ui->fontheight,re->w=re->ui->w,re->h=re->ui->h-re->y;
        reui_fill(re->ui,0,0,re->ui->w,re->ui->fontheight,(unsigned char *) "\x00\x00\xff\xff");
        reui_printf(re->ui,0,0,(unsigned char *) "\xff\xff\x00\xff","Fichero: %s",re->filename);
        re_drawcontents(re);
        while(do_exit==0 && flag_sigint==0) {
                if(re->ui->rendererdirty)
                        reui_present(re->ui);
                sselect_wait(ssel,100);
                SDL_PumpEvents();
                while(SDL_PeepEvents(&event,1,SDL_GETEVENT,SDL_FIRSTEVENT,SDL_LASTEVENT)>0) {
                        switch(event.type) {
                                case SDL_QUIT:
                                        do_exit=1;
                                        break;
                                case SDL_KEYDOWN:
                                        re_processkey(re,&event);
                                        break;
                                case SDL_WINDOWEVENT:
                                        if(event.window.event==SDL_WINDOWEVENT_SHOWN
                                          || event.window.event==SDL_WINDOWEVENT_EXPOSED) {
                                                re->ui->rendererdirty=1;
                                        }
                                        break;
                                default:
                                        break;
                        }
                }
        }
        sselect_free(ssel),ssel=NULL;
        re_free(re),re=NULL;
        return(0);
}

static int
setsignal(int num, void (*sighandler)(int))
{
        struct sigaction sa;
        sa.sa_handler=sighandler;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags=0;
        return(sigaction(num,&sa,0));
}

static void
sighandler_sigint(int num)
{
        flag_sigint=1;
}

static void
sighandler_sigpipe(int num)
{
        flag_sigpipe=1;
}


re_t *
re_init(void)
{
        re_t *re;
        if((re=malloc(sizeof(re_t)))==NULL)
                return(NULL); /* insuf. mem. */
        memset(re,0,sizeof(re_t));
        if((re->redata=redata_init(NULL))==NULL) {
                re_free(re),re=NULL;
                return(NULL); /* insuf. mem. */
        }
        if((re->ui=reui_init())==NULL) {
                re_free(re),re=NULL;
                return(NULL); /* video init error */
        }
        return(re);
}

void
re_free(re_t *re)
{
        if(re==NULL)
                return; /* all done */
        if(re->ui!=NULL)
                reui_free(re->ui),re->ui=NULL;
        if(re->redata!=NULL)
                redata_free(re->redata),re->redata=NULL;
        free(re),re=NULL;
        return;
}

int
re_setfilename(re_t *re, char *filename)
{
        if(re==NULL || filename==NULL)
                return(-1);
        strncpy(re->filename,filename,sizeof(re->filename));
        re->filename[sizeof(re->filename)-1]='\0';
        if(strcmp(filename,re->filename)!=0)
                return(-1); /* filename too long */
        return(0);
}

int
re_processkey(re_t *re, SDL_Event *event)
{
#warning TODO
        return(-1);
}


int
re_drawcontents(re_t *re)
{
        int numchunk;
        long offset;
        rechunk_t *chunk;
        unsigned char *ptr,*end;
        int y;
        reui_fill(re->ui,re->x,re->y,re->w,re->h,(unsigned char *) "\xdf\xdf\xdf\xff");
        if(redata_getposptr(re->redata,0,&numchunk,&offset)==-1)
                return(-1);
        chunk=re->redata->chunks[numchunk];
        /* iterate on lines */
        for(y=re->y,ptr=chunk->data+offset,end=memchr(ptr,'\n',chunk->useddata-(ptr-chunk->data)),
          end=(end==NULL)?chunk->data+chunk->useddata:end;ptr!=NULL && y<(re->y+re->h);
          y+=re->ui->fontheight,ptr=(end!=(chunk->data+chunk->useddata))?end+1:NULL,
          end=(ptr==NULL)?NULL:memchr(ptr,'\n',chunk->useddata-(ptr-chunk->data)),
          end=(end==NULL)?chunk->data+chunk->useddata:end) {
                reui_write(re->ui,re->x,y,(unsigned char *) "\x00\x00\x00\xff",ptr,end-ptr);
        }
#warning TODO
        return(-1);
}