/*
 * DATlib   Copyright (c) 1995-1996 Marcus Meissner &
 *          Friedrich-Alexander Universitaet Erlangen-Nuernberg (FAU), IMMD4
 *          All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by Marcus Meissner
 *    at the Friedrich-Alexander Universitaet Erlangen-Nuernberg (FAU), IMMD4
 *
 * 4. The name of the University or the author may not be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND THE AUTHOR ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR THE AUTHOR BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/* $Id: xplayer.c,v 1.1 1997/03/16 20:27:25 msmeissn Exp $
 *
 * $Log: xplayer.c,v $
 * Revision 1.1  1997/03/16 20:27:25  msmeissn
 * Initial revision
 *
 *
 * xplayer.c: preliminary version of a X-windows player for DATaudio
 *            developed without SUNWguide
 */

#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>

#include <X11/Xlib.h>
#include <xview/xview.h>
#include <xview/frame.h>
#include <xview/panel.h>
#include <xview/notify.h>
#include <xview/canvas.h>
#include <xview/xv_xrect.h>

#include "dataudiolib.h"
#include "xaudio.h"

#define FRAME_FRAME 101

int	quit(Panel_item item);
int	play(Panel_item item);
int	stop(Panel_item item);
int	forward(Panel_item item);
int	backward(Panel_item item);
#ifdef sun
int	open(char *fn,int mode);
#endif
Notify_value write_audio_data(Notify_client client,int xfd);
void c1_repaint(Canvas canvas,Xv_Window paint_window,Display *dpy,Window xwin,Xv_xrectlist *xrects);

int	Audio_fd=-1,DAT_fd=-1;
int	prognr;
int	maxx;
struct	da_time	ptime;
struct	da_time atime;
struct	da_time rxtime;
char	*tape;

int	valid; 

#define	VALID_PNR	1
#define	VALID_PTIME	2
#define	VALID_ATIME	4
#define	VALID_RTIME	8
#define	VALID_RDATE	16

#define	Y_PNR		5
#define	Y_PTIME		30
#define	Y_ATIME		55
#define	Y_RTIME		80
#define	Y_RDATE		105

Notify_client	nclient=10101;

#define	MYGC	DefaultGC(MYDPY,DefaultScreen(MYDPY))

Frame	frame;
Canvas	canvas;

#define	MYDPY	(Display*)xv_get(frame,XV_DISPLAY)
#define	MYWIN	(Window)xv_get(canvas_paint_window(canvas),XV_XID)

int
main(int argc,char **argv) {
	Panel	panel;

	valid=0;
	xv_init(XV_INIT_ARGC_PTR_ARGV,&argc,argv,NULL);
	frame=(Frame)xv_create((int)NULL,FRAME,
		FRAME_LABEL,argv[0],
		XV_WIDTH,250,
		XV_HEIGHT,170,
/*		FRAME_INHERIT_COLORS,TRUE,*/
		NULL
	);
	panel=(Panel)xv_create(frame,PANEL,
		XV_WIDTH,250,
		XV_HEIGHT,20,
		FRAME_INHERIT_COLORS,TRUE,
		NULL
	);
	(void)xv_create(panel,PANEL_BUTTON,
		PANEL_LABEL_STRING,"Quit",
		PANEL_NOTIFY_PROC,quit,
		PANEL_CLIENT_DATA,frame,
		NULL
	);
	(void)xv_create(panel,PANEL_BUTTON,
		PANEL_LABEL_STRING,"<",
		PANEL_NOTIFY_PROC,backward,
		PANEL_CLIENT_DATA,frame,
		NULL
	);
	(void)xv_create(panel,PANEL_BUTTON,
		PANEL_LABEL_STRING,"Play",
		PANEL_NOTIFY_PROC,play,
		PANEL_CLIENT_DATA,frame,
		NULL
	);
	(void)xv_create(panel,PANEL_BUTTON,
		PANEL_LABEL_STRING,"Stop",
		PANEL_NOTIFY_PROC,stop,
		PANEL_CLIENT_DATA,frame,
		NULL
	);
	(void)xv_create(panel,PANEL_BUTTON,
		PANEL_LABEL_STRING,">",
		PANEL_NOTIFY_PROC,forward,
		PANEL_CLIENT_DATA,frame,
		NULL
	);
	canvas=(Canvas)xv_create(frame,CANVAS,
		XV_WIDTH,250,
		XV_HEIGHT,130,
		CANVAS_REPAINT_PROC,c1_repaint,
		CANVAS_X_PAINT_WINDOW,TRUE,
		NULL
	);
	window_fit(panel);
	window_fit(canvas);
	window_fit(frame);
	xv_main_loop(frame);
	return 0;
}


void
print_7seg(int *px,int *py,int mask) {
	int		x=*px,y=*py;
	XGCValues	xgc;
	unsigned long	fg;
	unsigned long	bg;

	XGetGCValues(MYDPY,MYGC,GCForeground|GCBackground,&xgc);
	fg=xgc.foreground;
	bg=xgc.background;
	/* wie breit? 10
	 * wie hoch ? 20
	 */
	/*  ----1----         
	 * |         |
	 * |         |
	 * |         |
	 * |         |
	 * 2         4
	 * |         |
	 * |         |     |
	 * |         |     |
	 * |         |
	 *  ----8----    
	 * |         |     |
	 * |         |     |
	 * |         |
	 * |         |
	 * 16       32
	 * |         |
	 * |         |
	 * |         |
	 * |         |
	 *  ----64--- 
	 * y
	 */
	
	
#define	MASK(x)	if (mask&x) { xgc.foreground=fg;XChangeGC(MYDPY,MYGC,GCForeground,&xgc);} else { xgc.foreground=bg;XChangeGC(MYDPY,MYGC,GCForeground,&xgc);}
	MASK(1);
		XDrawLine(MYDPY,MYWIN,MYGC,x+1 ,y   ,x+9 ,y   );
	MASK(2);
		XDrawLine(MYDPY,MYWIN,MYGC,x   ,y+1 ,x   ,y+9 );
	MASK(4);
		XDrawLine(MYDPY,MYWIN,MYGC,x+10,y+1 ,x+10,y+9 );
	MASK(8);
		XDrawLine(MYDPY,MYWIN,MYGC,x+1 ,y+10,x+9 ,y+10);
	MASK(16);
		XDrawLine(MYDPY,MYWIN,MYGC,x   ,y+11,x   ,y+21);
	MASK(32);
		XDrawLine(MYDPY,MYWIN,MYGC,x+10,y+11,x+10,y+21);
	MASK(64);
		XDrawLine(MYDPY,MYWIN,MYGC,x+1 ,y+21,x+9 ,y+21);
	xgc.foreground=fg;
	XChangeGC(MYDPY,MYGC,GCForeground,&xgc);
	*px+=12;
}
void
print_dp(int *x,int *y) {

	/* wie breit? 10
	 * wie hoch ? 20
	 */
	/*
	 *
	 *
	 *
	 *
	 *
	 *
	 * |
	 * |
	 *
	 *
	 * |
	 * |
	 *
	 *
	 *
	 *
	 *
	 *
	 *
	 *
	 *
	 */
	*x=(*x)+2;
	XDrawLine(MYDPY,MYWIN,MYGC,*x,*y+6 ,*x,*y+8 );
	XDrawLine(MYDPY,MYWIN,MYGC,*x,*y+11,*x,*y+13);
	*x=(*x)+2;
}

int	nr2mask[10]={
	1|2|4|16|32|64,
	4|32,
	1|4|8|16|64,
	1|4|8|32|64,
	2|4|8|32,
	1|2|8|32|64,
	1|2|16|8|32|64,
	1|4|32,
	1|2|4|8|16|32|64,
	1|2|4|8|32|64,
};

void
print_nr7seg(int *x,int *y,int nr,int res) {
	int	i;

	for (i=1;res--;i=i*10) /*EMPTY*/;
	for (;(i=i/10);) {
		print_7seg(x,y,nr2mask[(nr/i)%10]);
		*x+=2;
		nr=nr-((nr/i)%10)*i;
	}
}

void
print_string(int x,int y,int *maxx,char *s) {
	XFontStruct	*fs;
	XGCValues	gcv;
	int		width;

	XGetGCValues(MYDPY,MYGC,GCFont,&gcv);
	fs=XQueryFont(MYDPY,gcv.font);
	width=XTextWidth(fs,s,strlen(s));
	XDrawString(MYDPY,MYWIN,MYGC,x,y,s,strlen(s));
	if (*maxx<x+width)
		*maxx=x+width;
}

void
print_prognr(int x,int y) {
	if (valid&VALID_PNR) {
		print_nr7seg(&x,&y,prognr,3);
	} else {
		print_7seg(&x,&y,8);
		x+=2;
		print_7seg(&x,&y,8);
		x+=2;
		print_7seg(&x,&y,8);
	}
}

void
print_time(int x,int y,struct da_time *xtime,int valmask) {
	if (!(valid&valmask)) {
		print_dp(&x,&y);
		x+=2;
#define PRINT_MINUS(x,y) print_7seg(x,y,8);(*x)+=2;
		PRINT_MINUS(&x,&y);
		PRINT_MINUS(&x,&y);
		x+=5;
		PRINT_MINUS(&x,&y);
		PRINT_MINUS(&x,&y);
		print_dp(&x,&y);
		PRINT_MINUS(&x,&y);
		PRINT_MINUS(&x,&y);
		print_dp(&x,&y);
		PRINT_MINUS(&x,&y);
		PRINT_MINUS(&x,&y);
	} else {
		print_dp(&x,&y);
		x+=2;
		print_nr7seg(&x,&y,xtime->indexnr,2);
		x+=5;
		print_nr7seg(&x,&y,xtime->hour,2);
		print_dp(&x,&y);
		print_nr7seg(&x,&y,xtime->minute,2);
		print_dp(&x,&y);
		print_nr7seg(&x,&y,xtime->second,2);
	}
}

void
print_programtime(int x,int y) {
	print_time(x,y,&ptime,VALID_PTIME);
}


void
print_abstime(int x,int y) {
	print_time(x,y,&atime,VALID_ATIME);
}

void
print_runtime(int x,int y) {
	print_time(x,y,&rxtime,VALID_RTIME);
}

void
my_repaint() {
	XClearWindow(MYDPY,MYWIN);
	maxx=0;
	print_string(10,Y_PNR,&maxx,"Programnr: ");
	print_string(10,Y_PTIME,&maxx,"Programtime: ");
	print_string(10,Y_ATIME,&maxx,"Absolutetime: ");
	print_string(10,Y_RTIME,&maxx,"Recordtime: ");
	print_string(10,Y_RDATE,&maxx,"Recorddate: ");
	print_prognr(maxx,Y_PNR);
	print_programtime(maxx,Y_PTIME);
	print_abstime(maxx,Y_ATIME);
	print_runtime(maxx,Y_RTIME);
	/*print_recorddate(maxx,Y_RDATE); */
}

void
c1_repaint(Canvas canvas,Xv_Window paint_window,Display *dpy,Window xwin,Xv_xrectlist *xrects) {
	my_repaint();
}

int
backward(Panel_item item) {
	int	pnr;
	struct	da_locate	daloc;

	if (!tape) tape=getenv("TAPE");
	if (!tape) tape=DEFAULTAUDIOTAPE;
	if (DAT_fd==-1) {
		DAT_fd=da_open(tape,O_RDONLY);
		return;
	}
	da_control(DAT_fd,DA_GET_PROGNR,(long)&pnr);
	pnr--;
	daloc.type=DA_LOC_PROGNR;
	daloc.nextop=DA_LOC_NEXTOP_READ;
	daloc.u.prognr=pnr;
	da_control(DAT_fd,DA_LOCATE,(long)&daloc);
	return XV_OK;
}

int
forward(Panel_item item) {
	int	pnr;
	struct	da_locate	daloc;

	da_control(DAT_fd,DA_GET_PROGNR,(long)&pnr);
	pnr++;
	daloc.type=DA_LOC_PROGNR;
	daloc.nextop=DA_LOC_NEXTOP_READ;
	daloc.u.prognr=pnr;
	da_control(DAT_fd,DA_LOCATE,(long)&daloc);
	return XV_OK;
}

int
quit(Panel_item item) {
	Frame	frame=(Frame)xv_get(item,PANEL_CLIENT_DATA);
	xv_destroy_safe(frame);
	return XV_OK;
}

void
cb_samplerate(int fd,enum da_cb_type type,union da_callback_data *data) {
	if (Audio_fd==-1)
		Audio_fd=audio_open(O_WRONLY);
	audio_change_attribs(Audio_fd,data->samplerate,16,1);
}

void
cb_prognr(int fd,enum da_cb_type type,union da_callback_data *data) {
	if (!data)
		valid&=~VALID_PNR;
	else {
		valid|=VALID_PNR;
		prognr=data->prognr;
	}
	print_prognr(maxx,Y_PNR);
}


void
cb_progtime(int fd,enum da_cb_type type,union da_callback_data *data) {
	if (data==NULL)
		valid&=~VALID_PTIME;
	else {
		memcpy(&ptime,&(data->time),sizeof(ptime));
		valid|=VALID_PTIME;
	}
	print_programtime(maxx,Y_PTIME);
}

void
cb_abstime(int fd,enum da_cb_type type,union da_callback_data *data) {
	if (data==NULL)
		valid&=~VALID_ATIME;
	else {
		memcpy(&atime,&(data->time),sizeof(atime));
		valid|=VALID_ATIME;
	}
	print_abstime(maxx,Y_ATIME);
}


char    *wds[16]={
	"Mon","Tue","Wed","Thu","Fri","Sat","Sun",
	"---","---","---","---","---","---","---","---","---",
};
char    *mons[19]={
	"---",/*0*/
	"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep",/* 1-9*/
	"Oct","Nov","Dec",/* 10 - 12 */
};

void
cb_recorddate(int fd,enum da_cb_type type,union da_callback_data *data) {
#if 0
	if (data==NULL)
		sprintf(rdate,"Recorddate   : --- --- -- --:--:-- --");
	else {
/* Tue Dec 12 21:24:12 MET 1995 */
		sprintf(rdate,"Recorddate   : ");
		strcat(rdate,wds[data->date.weekday]);
		strcat(rdate," ");
		strcat(rdate,mons[data->date.month]);
		strcat(rdate," ");
		l2s(data->date.day,2,JunkS);
		strcat(rdate,JunkS);
		strcat(rdate," ");
		l2s(data->date.hour,2,JunkS);
		strcat(rdate,JunkS);
		strcat(rdate,":");
		l2s(data->date.minute,2,JunkS);
		strcat(rdate,JunkS);
		strcat(rdate,":");
		l2s(data->date.second,2,JunkS);
		strcat(rdate,JunkS);
		strcat(rdate," ");
		l2s(data->date.year,2,JunkS);
		strcat(rdate,JunkS);
	}
	print_runtime(maxx,Y_RDATE);
#endif
}

void
cb_runtime(int fd,enum da_cb_type type,union da_callback_data *data) {
	if (data==NULL)
		valid&=~VALID_RTIME;
	else {
		memcpy(&rxtime,&(data->time),sizeof(rxtime));
		valid|=VALID_RTIME;
	}
	print_runtime(maxx,Y_RTIME);
}

int
play(Panel_item item) {
	if (!tape) tape=getenv("TAPE");
	if (!tape) tape=DEFAULTAUDIOTAPE;
	if (DAT_fd==-1) {
		DAT_fd=da_open(tape,O_RDONLY);
		if (DAT_fd==-1) {
			fprintf(stderr,"play():da_open:Could not open ");
			perror(tape);
		}
	}
	if (Audio_fd==-1) {
		Audio_fd=audio_open(O_WRONLY);
		if (Audio_fd==-1) {
			perror("audio_open");
			return;
		}
	}
	notify_set_output_func(nclient,write_audio_data,Audio_fd);
	xv_set(item,PANEL_INACTIVE,TRUE,NULL);
	da_add_callback(DAT_fd,DA_CB_PROGNR,0,cb_prognr);
	da_add_callback(DAT_fd,DA_CB_SAMPLERATE,0,cb_samplerate);
	da_add_callback(DAT_fd,DA_CB_PROGTIME,DA_CB_SECONDS,cb_progtime);
	da_add_callback(DAT_fd,DA_CB_ABSTIME,DA_CB_SECONDS,cb_abstime);
	da_add_callback(DAT_fd,DA_CB_RUNTIME,DA_CB_SECONDS,cb_runtime);
	da_add_callback(DAT_fd,DA_CB_RECORDDATE,DA_CB_MINUTES,cb_recorddate);
	return XV_OK;
}

Notify_value
write_audio_data(Notify_client client,int xfd) {
	unsigned char	buf[2000];
	int		curleft;
	int		res;

	if (!tape) tape=getenv("TAPE");
	if (!tape) tape=DEFAULTAUDIOTAPE;
	if (DAT_fd==-1) {
		DAT_fd=da_open(tape,O_RDONLY);
		if (DAT_fd==-1) {
			fprintf(stderr,"write_audio_data():da_open:Could not open ");
			perror(tape);
			return NOTIFY_DONE;
		}
	}
	da_read(DAT_fd,buf,2000);
	curleft=0;
	while (curleft!=2000) {
		res=audio_write(xfd,buf+curleft,2000-curleft);
		if (res==-1)
			break;
		curleft+=res;
	}
	return NOTIFY_DONE;
}

int 
stop(Panel_item item) { 
	if (Audio_fd!=-1)
		notify_remove_output_func(nclient,write_audio_data,Audio_fd);
	if (DAT_fd!=-1)
		da_close(DAT_fd);
	if (Audio_fd!=-1 && (Audio_fd != fileno(stdout)))
		close(Audio_fd);
	return XV_OK;
}
