/*
 * gaim
 *
 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <gtk/gtk.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/signal.h>
#include <errno.h>
#include "sound.h"
#include "globals.h"
#include "util.h"
#include "dialog.h"

#ifdef ESD_SOUND
#include <esd.h>
#endif


static void play_audio(gchar *soundfile)
{
    int fd;
    struct stat info;	
    char * buf;
    char * audio_device;
    
    fd = open(soundfile,O_RDONLY);
    if (fd <= 0)
    {
#ifdef DEBUG
		fprintf(stderr, "Cannot open file %s\n", soundfile);
#endif
		return;
    }
    fstat(fd, &info);
    buf = alloca(info.st_size);
    read(fd,buf,24);
    read(fd,buf,info.st_size-24);
    close(fd);
#ifdef DEBUG
    fprintf(stderr, "File is %ld bytes\n", info.st_size);
#endif

    audio_device = getenv("AUDIODEV");
    if (audio_device == NULL) {
      /* OK, we're not running on a SunRay */
      audio_device = "/dev/audio";
    }

#ifdef DEBUG
    fprintf(stderr, "sending to %s\n", audio_device);
#endif
    
    fd = open(audio_device, O_WRONLY | O_EXCL);
    if (fd < 0)
		return;
    write(fd, buf, info.st_size-24);
    close(fd);
}

static int can_play_audio()
{
        /* FIXME check for write access and such. */
        return 1;

}



#ifdef ESD_SOUND
/*
** This routine converts from ulaw to 16 bit linear.
**
** Craig Reese: IDA/Supercomputing Research Center
** 29 September 1989
**
** References:
** 1) CCITT Recommendation G.711  (very difficult to follow)
** 2) MIL-STD-188-113,"Interoperability and Performance Standards
**     for Analog-to_Digital Conversion Techniques,"
**     17 February 1987
**
** Input: 8 bit ulaw sample
** Output: signed 16 bit linear sample
** Z-note -- this is from libaudiofile.  Thanks guys!
*/
int _af_ulaw2linear (unsigned char ulawbyte)
{
  static int exp_lut[8] = {0,132,396,924,1980,4092,8316,16764};
  int sign, exponent, mantissa, sample;

  ulawbyte = ~ulawbyte;
  sign = (ulawbyte & 0x80);
  exponent = (ulawbyte >> 4) & 0x07;
  mantissa = ulawbyte & 0x0F;
  sample = exp_lut[exponent] + (mantissa << (exponent + 3));
  if (sign != 0) sample = -sample;
  {
  	return(sample);
  }
}

static int can_play_esd()
{
	return TRUE;
}

int play_esd_file(gchar *soundfile)
{
    int esd_stat;
	int fd;
    struct stat info;	
    char * buf;
	
    
    fd = open(soundfile,O_RDONLY);
    if (fd <= 0)
    {
#ifdef DEBUG
		fprintf(stderr, "Cannot open file %s\n", soundfile);
#endif
		return -1;
    }
    fstat(fd, &info);
    buf = alloca(info.st_size);
    read(fd,buf,info.st_size);
    close(fd);
    esd_stat = esd_play_file(NULL, soundfile, 1);
    if (!esd_stat)
    {
		if (errno == ENOENT)
		{
#ifdef DEBUG
	    	fprintf(stderr, "Everybuddy: File not found - file = \"%s\"\n", soundfile);
#endif
		}
		else
		{
#ifdef DEBUG
	    	fprintf(stderr, "Everybuddy: Esd play file failed with code %d\n", errno);
#endif
		}
    }
    return esd_stat;
}

#else

int can_play_esd()
{
    return FALSE;
}

int play_esd_file(gchar *soundfile)
{
    return FALSE;
}

#endif

/* file_ok 
 *
 * This routine test to see if file can be found and accessed
 * It issues an error message if the file open fails
 * Returns:
 * FALSE - If file open fails
 * TRUE - If file open succeeds
 */

int file_ok(gchar *soundfile)
{
    int fd_stat;
    char message[1024];
    
    if ((fd_stat = open(soundfile, O_RDONLY)) == -1)
    {
		/* find and report the error */
		switch (errno)
		{
			case ENOENT:
	    		g_snprintf(message, 1024, "Sound file \'%s\' Not Found", soundfile);
	   		 	break;
		
			case EACCES:
	    		g_snprintf(message, 1024, "Sound file \'%s\', Access Not Allowed", soundfile);
	    		break;
	    
			default:
	    		g_snprintf(message, 1024, "Error in opening sound file \'%s\', error code = %d", soundfile, errno);
		}
	//	do_error_dialog(message, "Everybuddy: Warning");
		g_warning(message);
		return FALSE;
    }
    return TRUE;
}



void playsoundfile(gchar *soundfile)
{
    
#ifdef _WIN32
    return;
#endif

    int pid;

    if (!file_ok(soundfile))
		return;


    pid = fork();
    if (pid < 0)
	{
		return;
	}
    else if (pid == 0)
    {
		if(can_play_esd())
		{
			if (play_esd_file(soundfile))
			{
	   		 	_exit(0);
			}
		}
		/* handle sound direct to /dev/audio */
		if (can_play_audio())
		{
	   		play_audio(soundfile);
		}
		_exit(0);
	    
    }
    else
	{
		gtk_timeout_add(100, (GtkFunction)clean_pid, NULL);
	}

}

void play_sound(int sound)
{
	if (do_no_sound_when_away && is_away)
	    return;
	switch(sound) 
	{
		case BUDDY_AWAY:
		{
			playsoundfile(BuddyAwayFilename);
		}
		break;
		case BUDDY_ARRIVE:
		{
			playsoundfile(BuddyArriveFilename);
		}
		break;
		case BUDDY_LEAVE:
		{
			playsoundfile(BuddyLeaveFilename);
		}
		break;
		case SEND:
		{
			playsoundfile(SendFilename);
		}
		break;
		case RECEIVE:
		{
			playsoundfile(RecieveFilename);
			break;
		}
		case FIRSTMSG:
		{
		    playsoundfile(FirstMsgFilename);
		    break;
		}
		default:
			return;
    }
}





