#include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <forms.h>
#include "rtty_f.h"
#include "common.h"
#include "fft.h"

extern FD_rtty_form *fd_rtty_form;

Display *mydisplay;
Window root,mywindow;
GC mygc;
XEvent myevent;
KeySym mykey;
XSizeHints myhint;
Colormap cmap;
XColor color;
int myscreen;
int mypal[7],X,Y,redisp=1;

/*-----------------------------------------------------*/

void draw_osc()
{
	unsigned int i,ix,ixt,si,sc;
	float *pf,m;
	static XPoint dat[1024],odat[1024];

	/* Erasing window */
	if (redisp) XClearWindow(mydisplay,mywindow);

	if (disdp->mode==2) {
		ix=disdp->inp+1;
		pf=disdp->in;
		m=1.0;
		si=1;
	} else if (disdp->mode==3) {
		ix=disdp->outp+1;
		pf=disdp->out;
		m=2.0;
		si=FS/fskdp->dr/20;
	} else return;
	ix&=NDBUF-1;

	/* Waiting for a positive-slope zero-crossing */
	for(i=0;i<NDBUF/2;i++) {
		if(pf[ix]<0 && pf[(ix+1)&NDBUF-1]>0) break;
		ix++; ix&=NDBUF-1;
	}

        /* finding scale factor */
        if (disdp->mode==3) {
                m=0;
                ixt=ix;
                for (i=0;i<X;i++) {
		        if (fabs(pf[ix])>m) m=fabs(pf[ix]);
		        ix+=si; ix&=NDBUF-1;
	        }
                ix=ixt;
                if (m<0.02) m=0.02;
                m=0.5/m;
        }
        /* Computing the new trace */
	for (i=0;i<X;i++) {
		dat[i].x=i;
		dat[i].y=Y/2-Y/2*(pf[ix])*m;
		ix+=si; ix&=NDBUF-1;
	}

	/* Erasing old trace*/
        XSetForeground(mydisplay,mygc,mypal[0]);
	if(!redisp) XDrawLines(mydisplay,mywindow,mygc,odat,X,CoordModeOrigin);

	/* Drawing the new trace */
        XSetForeground(mydisplay,mygc,mypal[disdp->mode]);
	XDrawLines(mydisplay,mywindow,mygc,dat,X,CoordModeOrigin);

        /* Drawing zero line */
        XSetForeground(mydisplay,mygc,mypal[1]);
	XDrawLine(mydisplay,mywindow,mygc,0,Y/2,X,Y/2);

	for (i=0;i<X;i++) odat[i]=dat[i];
	redisp=0;
}
/*-----------------------------------------------------*/

#define NTRACES 16
void draw_eye()
{
	unsigned int i,j,ix,ixt,xl,ox,si;
	float *pf,sc;
	static XPoint dat[NTRACES][1024],odat[NTRACES][1024];

	/* Erasing window */
	if (redisp) XClearWindow(mydisplay,mywindow);

        xl=FS/fskdp->dr;
        si=X/2/xl; if (si<1) si=1;
        ox=(X-xl*si)/2;
        pf=disdp->out;
        ix=disdp->outp+1;
	ix&=NDBUF-1;

        /* Waiting for a positive-slope zero-crossing */
	for(i=0;i<NDBUF/2;i++) {
		if(pf[ix]<0 && pf[(ix+1)&NDBUF-1]>0) break;
		ix++; ix&=NDBUF-1;
	}

        /* Finding scale factor */
        sc=0.0;
        ixt=ix;
        for (j=0;j<NTRACES;j++) {
            for (i=0;i<xl;i++) {
		if (fabs(pf[ix])>sc) sc=fabs(pf[ix]);
		ix++; ix&=NDBUF-1;
            }
	}
        if (sc<0.05) sc=0.05;
        /* Computing new traces */
        ix=ixt;
        for (j=0;j<NTRACES;j++) {
            for (i=0;i<xl;i++) {
		dat[j][i].x=ox+i*si;
		dat[j][i].y=Y/2-Y/4*(pf[ix])/sc;
		ix++; ix&=NDBUF-1;
            }
	}

	/* Erasing old traces */
	if(!redisp) {
            XSetForeground(mydisplay,mygc,mypal[0]);
            for (j=0;j<NTRACES;j++)
                XDrawLines(mydisplay,mywindow,mygc,&odat[j][0],xl,CoordModeOrigin);
        }

	/* Drawing the new traces */
        XSetForeground(mydisplay,mygc,mypal[3]);
        for (j=0;j<NTRACES;j++)
            XDrawLines(mydisplay,mywindow,mygc,&dat[j][0],xl,CoordModeOrigin);

	for (j=0;j<NTRACES;j++) for (i=0;i<xl;i++) odat[j][i]=dat[j][i];

        XSetForeground(mydisplay,mygc,mypal[1]);
	XDrawLine(mydisplay,mywindow,mygc,0,Y/2,X,Y/2);

	redisp=0;
}

/**********************************************************************/

void draw_spectrum()
{
	unsigned int i,ix,np,x,x1;
	float fmax;
	static XPoint dat[1024],odat[1024];
	complex a[NSAMPLES];

	fmax=fskdp->spacef+fskdp->markf;

	/* Erasing window */
	if (redisp) XClearWindow(mydisplay,mywindow);

	/* Computing the new trace */
	ix=disdp->inp+1;
	for (i=0;i<NSAMPLES;i++) {
		ix&=NDBUF-1;
		a[i].im=0.0;
		a[i].re=disdp->in[ix++]/128.0;
	}
	r_cosine(a);	/* Raised Cosine (Hanning) window */
	fft(a);		/* FFT transform */
	db(a);		/* Power spectrum (decibels) */
	np=NSAMPLES*fmax/FS;
	for (i=0;i<np;i++) {
		dat[i].x=i*X*FS/NSAMPLES/fmax;
		dat[i].y=(dat[i].y*7-(a[i].re+48)*Y/MINDB)/8;
	}

	/* Erasing old trace*/
        XSetForeground(mydisplay,mygc,mypal[0]);
	if(!redisp) XDrawLines(mydisplay,mywindow,mygc,odat,np,CoordModeOrigin);

        /* Drawing bands */
        XSetForeground(mydisplay,mygc,mypal[5]);
	x1=(2*fskdp->dr)*X/fmax;
        if (fskdp->mode!=CW) {
            x =(fskdp->spacef - fskdp->dr)*X/fmax;
            XFillRectangle(mydisplay,mywindow,mygc, x, 0, x1, Y);
        }
	XSetForeground(mydisplay,mygc,mypal[4]);
	x =(fskdp->markf - fskdp->dr)*X/fmax;
	XFillRectangle(mydisplay,mywindow,mygc, x, 0, x1, Y);

	/* Drawing the new trace */
        XSetForeground(mydisplay,mygc,mypal[6]);
	XDrawLines(mydisplay,mywindow,mygc,dat,np,CoordModeOrigin);

	for (i=0;i<np;i++) odat[i]=dat[i];

	redisp=0;
}

/******************************************************************/

void graph_main()
{

	int i;
	unsigned short col[256];
	char text[10];
        XGCValues xgc;

	mywindow = fl_get_canvas_id(fd_rtty_form->canvasw);
	mydisplay=FL_FormDisplay(fd_rtty_form);
        myscreen=DefaultScreen(mydisplay);

        /* Allocating a private GC to avoid Forms damage ;) */
        /* We select a XOR drawing funtion in order to speed trace erase */
        //xgc.function=GXset;
        //mygc=XCreateGC(mydisplay,mywindow,GCFunction,&xgc);
        mygc=XCreateGC(mydisplay,mywindow,0,0);
	/* Allocating colors for our palette */


        cmap=DefaultColormap(mydisplay,myscreen);
        cmap=XCopyColormapAndFree(mydisplay,cmap);

        color.red=0;
	color.green=0;
	color.blue=0;
	XAllocColor(mydisplay,cmap,&color);
        mypal[0]=color.pixel;
	color.blue=65535;
	XAllocColor(mydisplay,cmap,&color);
	mypal[1]=color.pixel;
	color.blue=0;
	color.green=65535;
	XAllocColor(mydisplay,cmap,&color);
	mypal[2]=color.pixel;
	color.red=65535;
	XAllocColor(mydisplay,cmap,&color);
	mypal[3]=color.pixel;
	color.red=0;
	color.green=32767;
	XAllocColor(mydisplay,cmap,&color);
	mypal[4]=color.pixel;
	color.red=49151;
	color.green=0;
	XAllocColor(mydisplay,cmap,&color);
	mypal[5]=color.pixel;
	color.red=65535;
	color.green=65535;
	color.blue=65535;
	XAllocColor(mydisplay,cmap,&color);
	mypal[6]=color.pixel;


	XGetGeometry(mydisplay,mywindow,&root,&i,&i,&X,&Y,&i,&i);

	for(;;){
            switch(disdp->mode) {
            case 1:     draw_spectrum(); break;
            case 2:
            case 3:     draw_osc(); break;
            case 4:     draw_eye(); break;
            }
	    /* Events seems to be handled by the XForms thread, */
	    /* so, we just ignore them */
	    usleep(100000);	/* Up to 10 frames/sec */
	}
}

