/*
 * Copyright (C) 1998 Sasha Vasko <sashav@sprintmail.com>
 * Copyright (c) 1996 by Alfredo Kojima
 *
 * 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.
 *
 */

/*
 * Todo: 
 * realtime audio mixing
 * replace the Audio module 
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>
#include <X11/StringDefs.h>
#include "../../include/aftersteplib.h"
#define AUDIO_DEVICE		"/dev/audio"

typedef struct LList
  {
    struct LList *next;
    struct LList *prev;
    int data;
    int timestamp;
  }
LList;

typedef struct SoundEntry
  {
    char *data;
    int size;
  }
SoundEntry;

/* timeout time for sound playing in seconds */
#define PLAY_TIMEOUT 1

/* table of audio data (not filenames) */
SoundEntry **SoundTable;

int LastSound = 0;
char *SoundPlayer;

/* unused but needed by libafterstep */
Display *dpy;			/* which display are we talking to */
int screen;
/* end unused */

char *MyName;
LList *PlayQueue = NULL, *OldestQueued = NULL;

int InPipe;

/*
 * Register --
 *      makes a new sound entry
 */
void
Register (char *sound_file, int code)
{
  int file;
  struct stat stat_buf;

  if (sound_file[0] == '.' && sound_file[1] == 0)
    {
      SoundTable[code] = (SoundEntry *) safemalloc (sizeof (SoundEntry));
      SoundTable[code]->size = -1;
      return;			/* dummy sound */
    }
  if (stat (sound_file, &stat_buf) < 0)
    {
      fprintf (stderr, "%s: sound file %s not found\n", MyName,
	       sound_file);
      return;
    }
  SoundTable[code] = (SoundEntry *) safemalloc (sizeof (SoundEntry));
  if (SoundPlayer != NULL)
    {
      SoundTable[code]->data = safemalloc (strlen (sound_file));
      SoundTable[code]->size = 1;
      strcpy (SoundTable[code]->data, sound_file);
      return;
    }
  SoundTable[code]->data = safemalloc (stat_buf.st_size);
  file = open (sound_file, O_RDONLY);
  if (file < 0)
    {
      fprintf (stderr, "%s: can't open sound file %s\n", MyName, sound_file);
      free (SoundTable[code]->data);
      free (SoundTable[code]);
      SoundTable[code] = NULL;
      return;
    }
  SoundTable[code]->size = read (file, SoundTable[code]->data, stat_buf.st_size);
  if (SoundTable[code]->size < 1)
    {
      fprintf (stderr, "%s: error reading sound file %s\n", MyName,
	       sound_file);
      free (SoundTable[code]->data);
      free (SoundTable[code]);
      close (file);
      SoundTable[code] = NULL;
      return;
    }
  close (file);
}

/*
 * PlaySound --
 *      plays a sound
 */

void
PlaySound (int sid)
{
  if ((sid < LastSound) && (SoundTable[sid]->size <= 0))
    return;
  if ((sid >= LastSound) || (sid < 0) || SoundTable[sid] == NULL)
    {
      fprintf (stderr, "%s: request to play invalid sound received\n",
	       MyName);
      return;
    }
  if (SoundPlayer != NULL)
    {
      pid_t child;

      child = fork ();
      if (child < 0)
	return;
      else if (child == 0)
	{
	  execlp (SoundPlayer, SoundPlayer, SoundTable[sid]->data, NULL);
	}
      else
	{
	  while (wait (NULL) < 0);
	}
      /*
         sprintf(cmd,"%s %s",SoundPlayer,SoundTable[sid]->data);
         system(cmd);
       */
      return;
    }
#if 0
  audio = open (AUDIO_DEVICE, O_WRONLY | O_NONBLOCK);
  if ((audio < 0) && errno == EAGAIN)
    {
      sleep (1);
      audio = open (AUDIO_DEVICE, O_WRONLY | O_NONBLOCK);
      if (audio < 0)
	return;
    }
  write (audio, SoundTable[sid]->data, SoundTable[sid]->size);
  close (audio);
  audio = -1;
#endif
}

void
DoNothing (int foo)
{
  signal (SIGUSR1, DoNothing);
}

/*
 * HandleRequest --
 *       play requested sound
 * sound -1 is a quit command
 * 
 * Note:
 *      Something not good will happed if a new play request 
 * arrives before exiting the handler
 */
void
HandleRequest (int foo)
{
  int sound, timestamp;
/*    
   signal(SIGUSR1, DoNothing);
 */
  read (InPipe, &sound, sizeof (sound));
  read (InPipe, &timestamp, sizeof (timestamp));
  if (sound < 0)
    {
      printf ("exitting ASSound..\n");
      exit (0);
    }
  if ((clock () - timestamp) < PLAY_TIMEOUT)
    PlaySound (sound);
#if 0
  tmp = safemalloc (sizeof (LList));
  tmp->data = sound;
  tmp->timestamp = clock ();
  tmp->next = PlayQueue;
  if (PlayQueue == NULL)
    {
      OldestQueued = tmp;
      tmp->prev = NULL;
    }
  else
    {
      PlayQueue->prev = tmp;
    }
  PlayQueue = tmp;
  signal (SIGUSR1, HandleRequest);
#endif
}

/*
 * Program startup.
 * Arguments:
 * argv[1] - pipe for reading data 
 * argv[2] - the name of the sound player to be used. ``-'' indicates 
 *      internal player.
 * argv[3]... - filenames of sound files with code n-3
 */
int
main (int argc, char **argv)
{
  int i;
  char *s;

  signal (SIGUSR1, HandleRequest);

  /* Record the program name for error messages */
  s = strrchr (argv[0], '/');
  if (s != NULL)
    s = s + 1;
  else
    s = argv[0];

  MyName = s;

  if (argc < 4)
    {
      fprintf (stderr, "%s can only be started by an AfterStep module\n",
	       MyName);
      exit (1);
    }
  SoundPlayer = argv[2];
  if (SoundPlayer[0] == '-' && SoundPlayer[1] == 0)
    {
      SoundPlayer = NULL;
      printf ("%s:need a sound player.\n", MyName);
    }
  SoundTable = (SoundEntry **) safemalloc (sizeof (SoundEntry *) * (argc - 3));
  for (i = 3; i < argc; i++)
    {
      Register (argv[i], i - 3);
    }
  LastSound = i - 3;
  InPipe = atoi (argv[1]);
  while (1)
    {
#if 0
      LList *tmp;
      while (OldestQueued != NULL)
	{
	  if ((clock () - OldestQueued->timestamp) < PLAY_TIMEOUT)
	    PlaySound (OldestQueued->data);
	  tmp = OldestQueued->prev;
	  free (OldestQueued);
	  OldestQueued = tmp;
	}
      pause ();
#endif
      HandleRequest (0);
    }
  return 0;
}

void
DeadPipe (int nonsense)
{
  exit (0);
}
