#include "snd.h"
#include "sndclm.h"

static XtInputId clm_id = 0;

void CLM_disconnect(snd_state *ss)
{
  if (clm_id) XtRemoveInput(clm_id);
  ss->to_clm = 0;
}

static void GetClmString (XtPointer clientData, int *fd, XtInputId *id)
{
  get_clm_string((snd_state *)clientData,*fd);
}

static char connected_msg[] = "(print \"Snd connected\")";

int CLM_connect(snd_state *ss)
{
  /* look for CLM fifo -- if found, establish connection and X input callback */
  state_context *sx;
  int fd;
  /* first look for snd_snd fifo -- if already exists, exit.  In RDONLY mode, we have to use NONBLOCK to avoid getting hung */
  fd = open(SND_SND_FIFO,O_RDONLY | O_NONBLOCK,0);
  if (fd != -1)
    {
      close(fd);
      return(-1);
    }
  sx = ss->sgx;
  ss->from_clm = open(CLM_SND_FIFO,O_RDWR,0);
  if (ss->from_clm != -1)
    {
      ss->to_clm = open(SND_CLM_FIFO,O_RDWR,0);
      clm_id = XtAppAddInput(sx->mainapp,ss->from_clm,(XtPointer)XtInputReadMask,GetClmString,(XtPointer)ss);
      /* now tell CLM we're here (it is waiting...) */
      write(ss->to_clm,connected_msg,strlen(connected_msg)+1);
    }
  else 
    {
      ss->to_clm = 0;
      clm_id = 0;
    }
  return(0);
}

static XtInputId snd_id = 0;
static char snd_buffer[256];

static void GetSndString (XtPointer clientData, int *fd, XtInputId *id)
{
  int bytes;
  bytes=read(*fd,snd_buffer,256);
  snd_buffer[bytes] = '\0';
  /* for now, assume it's an open command -- we could expand this indefinitely... */
  snd_open_file(snd_buffer,(snd_state *)clientData);
}

int SND_connect(snd_state *ss)
{
  /* look for existing snd fifo (for snd to snd remote control) */
  /* if not found, create and open for reading */
  /* if found, do nothing (i.e. only one Snd has this open for reading) */
  /* return 0; no fifo created (someone else has it)
   *        err: some fifo error occurred
   *        -1: fifo opened for reading
   */
  state_context *sx;
  int fd,err;
  fd = open(SND_SND_FIFO,O_RDWR,0);
  if (fd == -1)
    {
      sx = ss->sgx; 
      err = mkfifo(SND_SND_FIFO,0777);
      if (err) return(err);
      ss->from_snd = open(SND_SND_FIFO,O_RDWR,0);
      snd_id = XtAppAddInput(sx->mainapp,ss->from_snd,(XtPointer)XtInputReadMask,GetSndString,(XtPointer)ss);
      return(-1);
    }
  else close(fd);
  return(0);
}

void SND_disconnect(snd_state *ss)
{
  if (snd_id) XtRemoveInput(snd_id);
  if (ss->from_snd) 
    {
      close(ss->from_snd);
      remove(SND_SND_FIFO);
      /* if user calls out of Snd, this file remains on /tmp with user's umask making it undeletable by others */
      /* so under the CCRMA switch (see sndclm.h) this is written to /zap instead */
    }
  ss->from_snd = 0;
}

void check_for_remote_possibility(int argc, char **argv)
{
  /* run through argv looking for -remote,
   *  if found, look for snd_snd fifo,
   *  if found, write next arg to it and exit snd
   */
  int i,fd;
  for (i=1;i<argc;i++)
    {
      if (strcmp(argv[i],"-remote") == 0)
	{
	  fd = open(SND_SND_FIFO,O_RDWR,0);
	  if (fd != -1)
	    {
	      write(fd,argv[i+1],strlen(argv[i+1])+1);
	      close(fd);
	      exit(0);
	    }
	  break; /* no need to go on -- we're going to have to run the full Snd in any case */
	}
    }
}

/* now the "clm is awaiting snd data" dialog */

static Widget clm_fd = NULL;

static void clm_help_callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss = (snd_state *)clientData;
  snd_help(ss,
	   "CLM Snd",
"CLM is awaiting a response from Snd.  If\n\
you click 'ok', the current changed data will\n\
be sent.  Click 'cancel' to cancel the\n\
transaction.\n\
");
}

void cleanup_clm_dialog(snd_state *ss)
{
  if ((clm_fd) && (XtIsManaged(clm_fd)))
    {
      write(ss->to_clm,":cancel",8);
      XtUnmanageChild(clm_fd);
    }
}

static void clm_cancel_callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss = (snd_state *)clientData;
  write(ss->to_clm,":cancel",8);
}

static void clm_ok_callback(Widget w,XtPointer clientData,XtPointer callData) 
{
  snd_state *ss = (snd_state *)clientData;
  write(ss->to_clm,":ok",4);
}

void start_clm_dialog(snd_state *ss, char *msg)
{
  Arg args[20];
  int n;
  XmString xmstr1,xmstr2,xmstr3,xmstr4,titlestr;
  if (!clm_fd)
    {
      /* create dialog */
      n=0;
      xmstr1=XmStringCreateLocalized(msg);
      xmstr2=XmStringCreateLocalized(snd_string_Ok);
      xmstr3=XmStringCreateLocalized(snd_string_Cancel);
      xmstr4=XmStringCreateLocalized(snd_string_Help);
      titlestr = XmStringCreateLocalized(snd_string_CLM);
      XtSetArg(args[n],XmNmessageString,xmstr1); n++;
      XtSetArg(args[n],XmNokLabelString,xmstr2); n++;
      XtSetArg(args[n],XmNcancelLabelString,xmstr3); n++;
      XtSetArg(args[n],XmNhelpLabelString,xmstr4); n++;
      XtSetArg(args[n],XmNdialogTitle,titlestr); n++;
#if RESIZE_DIALOG
      XtSetArg(args[n],XmNresizePolicy,XmRESIZE_GROW); n++;
      XtSetArg(args[n],XmNnoResize,FALSE); n++;
#endif
#if UNSET_TRANSIENT
      XtSetArg(args[n],XmNtransient,FALSE); n++;
#endif
      clm_fd = XmCreateMessageDialog(main_PANE(ss),"clm",args,n);
#if UNSET_TRANSIENT
      add_dialog(ss,clm_fd);
#endif
      XmStringFree(xmstr1);
      XmStringFree(xmstr2);
      XmStringFree(xmstr3);
      XmStringFree(xmstr4);
      XmStringFree(titlestr);
      XtUnmanageChild(XmMessageBoxGetChild(clm_fd,XmDIALOG_SYMBOL_LABEL));
      XtAddCallback(clm_fd,XmNhelpCallback,clm_help_callback,ss);
      XtAddCallback(clm_fd,XmNcancelCallback,clm_cancel_callback,ss);
      XtAddCallback(clm_fd,XmNokCallback,clm_ok_callback,ss);
#if MANAGE_DIALOG
      XtManageChild(clm_fd);
#endif
      if (!(ss->using_schemes)) map_over_children(clm_fd,set_main_color_of_widget,(void *)ss);
    }
  else
    {  
      xmstr1=XmStringCreateLocalized(msg);
      XtVaSetValues(clm_fd,XmNmessageString,xmstr1,NULL);
      XmStringFree(xmstr1);      
    }
  if (!(XtIsManaged(clm_fd))) XtManageChild(clm_fd);
}
