/* 
 * Copyright (c) 1997 Guylhem Aznar <guylhem@danmark.linux.eu.org>
 * Copyright (C) 1994 Mark Boyns <boyns@sdsu.edu>
 * Copyright (C) 1994 Mark Scott <mscott@mcd.mot.com>
 * Copyright (C) 1994 Szijarto Szabolcs <saby@sch.bme.hu>
 * Copyright (C) 1994 Robert Nation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
 * afterstep includes:
 */
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <unistd.h>
#include <ctype.h>
#include <stdlib.h>
#include "../../configure.h"
#include "../../src/module.h"
#include "../../src/lib/aftersteplib.h"

/*
 * rplay includes:
 */
#ifdef HAVE_RPLAY
#include <rplay.h>
#endif

#define BUILTIN_STARTUP		MAX_MESSAGES
#define BUILTIN_SHUTDOWN	MAX_MESSAGES+1
#define BUILTIN_UNKNOWN		MAX_MESSAGES+2
#define MAX_BUILTIN		3

#define BUFSIZE			512

/* globals */
char *MyName;
int fd_width;
int fd[2];
char audio_play_cmd_line[BUFSIZE], audio_play_dir[BUFSIZE];
time_t audio_delay = 0;		/* seconds */
#ifdef HAVE_RPLAY
int rplay_fd = -1;
#endif

/* prototypes */
void Loop(int *);
void process_message(unsigned long, unsigned long *);
void DeadPipe(int);
void config(char *);
void done(int);
int audio_play(short);

/* define the message table */
char *messages[MAX_MESSAGES + MAX_BUILTIN] =
{
	"toggle_paging",
	"new_page",
	"new_desk",
	"add_window",
	"raise_window",
	"lower_window",
	"configure_window",
	"focus_change",
	"destroy_window",
	"iconify",
	"deiconify",
	"window_name",
	"icon_name",
	"res_class",
	"res_name",
	"end_windowlist",
	"icon_location",
	"map",
/* add builtins here */
	"startup",
	"shutdown",
	"unknown",
};

/* define the sound table  */
char *sound_table[MAX_MESSAGES + MAX_BUILTIN];

#ifdef HAVE_RPLAY
/* define the rplay table */
RPLAY *rplay_table[MAX_MESSAGES + MAX_BUILTIN];
#endif

main(int argc, char **argv)
{
	char *temp, *s;
	char configfile[255];
	char *realconfigfile;

	if ((argc != 6) && (argc != 7)) {
		fprintf(stderr, "%s Version %s should only be executed by afterstep!\n",
			MyName, VERSION);
		exit(1);
	}
	/* Save our program  name - for error messages */
	temp = argv[0];
	s = strrchr(argv[0], '/');
	if (s != NULL)
		temp = s + 1;

	MyName = safemalloc(strlen(temp) + 2);
	strcpy(MyName, "*");
	strcat(MyName, temp);

	/* Dead pipe == AS died */
	signal(SIGPIPE, DeadPipe);

	fd[0] = atoi(argv[1]);
	fd[1] = atoi(argv[2]);

	audio_play_dir[0] = '\0';
	audio_play_cmd_line[0] = '\0';

	/*
	 * Read the sound configuration.
	 */

    sprintf (configfile, "%s/audio", AFTER_DIR);
    realconfigfile = PutHome (configfile);
	config(realconfigfile);

	/*
	 * Play the startup sound.
	 */
	audio_play(BUILTIN_STARTUP);
	SendText(fd, "Nop", 0);
	Loop(fd);
}

/***********************************************************************
 *
 *  Procedure:
 *	config - read the sound configuration file.
 *
 ***********************************************************************/
void config(char *config_file)
{
	FILE *fp;
	char buf[BUFSIZE];
	char *message;
	char *sound;
	char *p;
	int i, found;
#ifdef HAVE_RPLAY
	char host[128];
	int volume = RPLAY_DEFAULT_VOLUME;
	int priority = RPLAY_DEFAULT_PRIORITY;
#endif

	fp = fopen(config_file, "r");
	if (fp == NULL) {
		done(1);
	}
	/*
	 * Intialize all the sounds.
	 */
	for (i = 0; i < MAX_MESSAGES + MAX_BUILTIN; i++) {
		sound_table[i] = NULL;
#ifdef HAVE_RPLAY
		rplay_table[i] = NULL;
#endif
	}

#ifdef HAVE_RPLAY
	strcpy(host, rplay_default_host());
#endif

	while (fgets(buf, sizeof(buf), fp)) {
		buf[strlen(buf) - 1] = '\0';
		if (buf[0] != '*') {
			continue;
		}
		/*
		 * Search for *ASAudio.
		 */
		if (mystrncasecmp(buf, MyName, strlen(MyName)) == 0) {
			p = strtok(buf, " \t");

			if (mystrcasecmp(p, "*AudioPlayCmd") == 0) {
				p = strtok(NULL, "\n");		/* allow parameters */
				if (p && *p) {
					strcpy(audio_play_cmd_line, p);
				}
			} else if (mystrcasecmp(p, "*AudioDir") == 0) {
				p = strtok(NULL, " \t");
				if (p && *p) {
					strcpy(audio_play_dir, p);
				}
			} else if (mystrcasecmp(p, "*AudioDelay") == 0) {
				p = strtok(NULL, " \t");
				if (p && *p) {
					audio_delay = atoi(p);
				}
			}
#ifdef HAVE_RPLAY
			/*
			 * Check for rplay configuration options.
			 */
			else if (mystrcasecmp(p, "*AudioRplayHost") == 0) {
				p = strtok(NULL, " \t");
				if (p && *p) {
					/*
					 * Check for environment variables like $HOSTDISPLAY.
					 */
					if (*p == '$') {
						char *c1, *c2;
						c2 = host;
						for (c1 = (char *) getenv(p + 1); *c1 && (*c1 != ':'); c1++) {
							*c2++ = *c1;
						}
						*c2 = '\0';
					} else {
						strcpy(host, p);
					}
				}
			} else if (mystrcasecmp(p, "*AudioRplayVolume") == 0) {
				p = strtok(NULL, " \t");
				if (p && *p) {
					volume = atoi(p);
				}
			} else if (mystrcasecmp(p, "*AudioRplayPriority") == 0) {
				p = strtok(NULL, " \t");
				if (p && *p) {
					priority = atoi(p);
				}
			}
#endif
			/*
			 * *Audio <message_type> <audio_file>
			 */
			else {
				message = strtok(NULL, " \t");
				sound = strtok(NULL, " \t");

				if (!message || !*message || !sound || !*sound) {
					continue;
				}
				found = 0;

				for (i = 0; !found && i < MAX_MESSAGES + MAX_BUILTIN; i++) {
					if (mystrcasecmp(message, messages[i]) == 0) {
#ifdef HAVE_RPLAY
						rplay_table[i] = rplay_create(RPLAY_PLAY);
						rplay_set(rplay_table[i], RPLAY_APPEND,
						      RPLAY_SOUND, sound,
						RPLAY_PRIORITY, priority,
						    RPLAY_VOLUME, volume,
							  NULL);
#endif
						sound_table[i] = safemalloc(strlen(sound) + 1);
						strcpy(sound_table[i], sound);
						found++;
					}
				}
			}
		}
	}

	fclose(fp);

#ifdef HAVE_RPLAY
	/*
	 * Builtin rplay support is enabled when FvwmAudioPlayCmd == builtin-rplay.
	 */
	if (mystrcasecmp(audio_play_cmd_line, "builtin-rplay") == 0) {
		rplay_fd = rplay_open(host);
		if (rplay_fd < 0) {
			rplay_perror("rplay_open");
			done(1);
		}
	}
#endif
}

/***********************************************************************
 *
 *  Procedure:
 *	Loop - wait for data to process
 *
 ***********************************************************************/
void Loop(int *fd)
{
	unsigned long header[3], *body;
	char *cbody;
	int body_length, count, count2 = 0, total;
	time_t now, last_time = 0;
	unsigned long code;

	while (1) {
		if ((count = read(fd[1], header, 3 * sizeof(unsigned long))) > 0) {
			/*
			 * Ignore messages that occur during the delay
			 * period.
			 */
			now = time(0);
			if (now < (last_time + audio_delay)) {
				continue;
			}
			last_time = now;

			if (header[0] == START_FLAG) {
				body_length = header[2] - 3;
				body = (unsigned long *)
				    safemalloc(body_length * sizeof(unsigned long));
				cbody = (char *) body;
				total = 0;
				while (total < body_length * sizeof(unsigned long)) {
					if ((count2 = read(fd[1], &cbody[total],
							   body_length * sizeof(unsigned long) - total)) > 0)
						 total += count2;
					else if (count2 < 0)
						DeadPipe(0);
				}

				/*
				 * code will equal the number of shifts in the
				 * base-2 header[1] number.  Could use log here
				 * but this should be fast enough.
				 */
				code = -1;
				while (header[1]) {
					code++;
					header[1] >>= 1;
				}

				/*
				 * Play the sound.
				 */
				if (code >= 0 && code < MAX_MESSAGES) {
					audio_play(code);
				} else {
					audio_play(BUILTIN_UNKNOWN);
				}

				free(body);
			}
		}
		if (count <= 0)
			DeadPipe(1);
	}
}


/***********************************************************************
 *
 *  Procedure:
 *	SIGPIPE handler - SIGPIPE means afterstep is dying
 *
 ***********************************************************************/
void DeadPipe(int nonsense)
{
	done(0);
}

/***********************************************************************
 *
 *  Procedure:
 *	done - common exit point for FvwmAudio.
 *
 ***********************************************************************/
void done(int n)
{
	audio_play(BUILTIN_SHUTDOWN);
	exit(n);
}

/***********************************************************************
 *
 * Procedure:
 *
 *    audio_play - actually plays sound from lookup table
 *
 **********************************************************************/
int audio_play(short sound)
{
	char *realfilename;
	static char buf[BUFSIZE];

#ifdef HAVE_RPLAY
	if (rplay_fd != -1) {
		if (rplay_table[sound]) {
			if (rplay(rplay_fd, rplay_table[sound]) < 0) {
				rplay_perror("rplay");
			}
		}
		return 0;
	}
#endif

	if (sound_table[sound]) {
		memset(buf, (int) NULL, BUFSIZE);

		/*
		 * Don't use audio_play_dir if it's NULL or if the sound file
		 * is an absolute pathname.
		 */
		if (audio_play_dir[0] == '\0' || sound_table[sound][0] == '/') {
			sprintf(buf, "%s %s", audio_play_cmd_line, sound_table[sound]);
		} else {

/* home dir ? */
			realfilename = PutHome( audio_play_dir);
			sprintf(buf, "%s %s/%s", audio_play_cmd_line,
				realfilename, sound_table[sound]);
	            free(realfilename);

		}
		return system(buf);
	}
	return 1;
}
