#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include "conf.h"
#include "dir.h"
#include "err.h"
#include "player.h"
#include "queue.h"


/* Start playing item.
 * The exit functions should realy return error codes
 * but juke work that way that if a player returns an
 * error code. It's asumed to be because it failed to
 * open an audio device and the player is restarted.
 * We don't want that here.
 */

pid_t player_play (struct CONFIG *cfg, struct DIR_INFO *dinfo, int item)
{
  int fd, i, args, format;
  char *path, *arg_list[CFG_ARGS], **s;
  pid_t pid;
  
  format = dinfo->item[item].type - 1;
  args = cfg->format[format].args;
  path = dir_build_path (dinfo, item);
  s = cfg->format[format].arg_list;
  for (i=0; i<args; i++)
    arg_list[i] = *s++;
  
  for (i=0; i<(args-1); i++) {
    if (*(arg_list[i]) == '@')
      arg_list[i] = path;
  }
  
  pid = fork ();
  if (! pid) {
#ifdef SETPGRP_VOID
    if (setpgrp())
#else
    if (setpgrp(0,0))
#endif
      exit (0);
    if ((fd = open ("/dev/null", O_WRONLY)) == -1)
      exit (0);
    dup2 (fd, 1);
    dup2 (fd, 2);
    close (fd);
    if (execvp (arg_list[0], arg_list) == -1)
      exit (0);
  }
  free (path);
  return pid;
}


/* Return status of player.
 * 0-255 player have exited with low 8 bits of exit code as returned.
 * -1 player is running
 */

int player_status (struct PLAYER *p)
{
  int status;
  pid_t rpid;
  
  if (p->pid) {
    rpid = waitpid (p->pid, &status, WNOHANG | WUNTRACED);
    if (!rpid)
      return -1;
    if (rpid == p->pid) {
      if (WIFEXITED (status))
	return (WEXITSTATUS (status));
      else
	return 1;
    }
  }
  return 0;
}


/* Kill the player's process group and wait.
 */

void player_kill (struct PLAYER *p)
{
  if (p->kill) {
    if (p->paused)
      kill (-p->kill, SIGCONT);
    kill (-p->kill, SIGTERM);
    waitpid (-p->kill, 0, 0);
    p->kill = 0;
  }
}


/* Send stop signal to the player's process group.
 */

void player_stop (struct PLAYER *p)
{
  if (p->pid)
    kill (-p->pid, SIGSTOP);
}


/* Send continue signal to the player's process group.
 */

void player_cont (struct PLAYER *p)
{
  if (p->pid)
    kill (-p->pid, SIGCONT);
}
