#include "snd.h"

void remove_backup_file(snd_state *ss)
{
  remove(ss->backup_file);
}

static int remove_temp_files(chan_info *cp, void *ptr)
{
  free_sound_list(cp);
  free_mix_list(cp);
  return(0);
}

void snd_exit_cleanly(snd_state *ss)
{  
  cleanup_clm_dialog(ss);
  if (dac_is_running()) close_dac();
  if (ss->to_clm)
    {
      close(ss->from_clm);
      close(ss->to_clm);
    }
  SND_disconnect(ss);
  if (ss->remember_state) 
    save_snd_state(ss); 
  else remove_backup_file(ss);
  map_over_chans(ss,remove_temp_files,NULL);
  cleanup_region_temp_files();
  cleanup_group_temp_files(ss);
  cleanup_recording();
}

#define SAVE_BUF_SIZE 1024
static char save_buf[SAVE_BUF_SIZE];

static void save_snd_state_options (snd_state *ss, int fd)
{ /* for save options menu choice (.snd) -- independent of .snd-backup -- mostly saving snd_state info */
  time_t ts;
  sprintf(save_buf,";;; snd: ");
  write(fd,save_buf,strlen(save_buf));
  time(&ts);
  strftime(save_buf,SAVE_BUF_SIZE,"%a %d-%b-%y %H:%M %Z",localtime(&ts));
  write(fd,save_buf,strlen(save_buf));
  write(fd,"\n",1);
  sprintf(save_buf,"(%s)\n(%s)\n(%s)\n(%s)\n(%s)\n(%s)\n(%s)\n",
	  (ss->peaking) ? "show-peaks" : "hide-peaks",
	  (ss->zero_visible) ? "show-y-zero" : "hide-y-zero",
	  (ss->marks_visible) ? "show-marks" : "hide-marks",
	  (ss->dBing) ? "fft-dB" : "fft-linear",
	  (ss->logxing) ? "fft-log-freq" : "fft-linear-freq",
	  (ss->graph_style == graph_dots) ? "dots" : "lines",
	  (ss->subsampling) ? "subsampling-on" : "subsampling-off");
  write(fd,save_buf,strlen(save_buf));
  sprintf(save_buf,"(setf window-width %d)\n(setf window-height %d)\n(setf remember-state %d)\n",
	  snd_window_width(ss),snd_window_height(ss),ss->remember_state);
  write(fd,save_buf,strlen(save_buf));
  sprintf(save_buf,"(setf fft-size %d)\n(setf fft-window %d)\n(fft-style %d)\n(setf sono_max %f)\n",
	  ss->global_fft_size,
	  ss->global_fft_window,
	  ss->fft_style,
	  ss->sonogram_cutoff);
  write(fd,save_buf,strlen(save_buf));
  sprintf(save_buf,"(focus-style %d)\n(%s)\n(%s)\n(setf color-scale %f)\n(setf color-inverted %d)\n(setf color-cutoff %f)\n",
	  ss->zoom_focus_anchor,
	  (ss->fit_data) ? "fit-data" : "dont-fit-data",
	  (ss->cursor_talks) ? "verbose-cursor" : "silent-cursor",
	  ss->color_scale,
	  ss->color_inverted,
	  ss->color_cutoff);
  write(fd,save_buf,strlen(save_buf));
  sprintf(save_buf,"(setf spectro-hop %d)\n(setf spectro-xangle %f)\n(setf spectro-yangle %f)\n(setf spectro-zangle %f)\n",
	  ss->spectro_hop,ss->spectro_xangle,ss->spectro_yangle,ss->spectro_zangle);
  write(fd,save_buf,strlen(save_buf));
  sprintf(save_buf,"(setf spectro-xscl %f)\n(setf spectro-yscl %f)\n(setf spectro-zscl %f)\n(setf wavo-hop %d)\n(setf wavo-trace %d)\n",
	  ss->spectro_xscl,ss->spectro_yscl,ss->spectro_zscl,ss->wavo_hop,ss->wavo_trace);
  write(fd,save_buf,strlen(save_buf));
  sprintf(save_buf,"(setf dot-size %d)\n(setf sono-color %d)\n(setf spectro-color %d)\n(setf combine-channels %d)\n",
	  ss->dot_size,ss->sonogram_color,ss->spectrogram_color,ss->global_combining);
  write(fd,save_buf,strlen(save_buf));
  sprintf(save_buf,"(setf line-size %d)\n(setf revdecay %f)\n(setf overwrite-check %d)\n(setf wavo-state %d)\n",
	  ss->editor_line_size,ss->reverb_decay,ss->ask_before_overwrite,ss->wavo);
  write(fd,save_buf,strlen(save_buf));
}

static int open_restart_file(char *name, int append)
{
  int fd;
  char *str;
  str = name;
  if ((*str) == '~')
    {
      strcpy(save_buf,getenv("HOME"));
      strcat(save_buf,++str);
      str=save_buf;
    }
  if (append)
    {
      if ((fd = open(str,O_RDWR,0)) == -1)
	fd = creat(str,0666);
      else
	lseek(fd,0L,2); /* go to the end */
    }
  else
    fd = creat(str,0666);
  return(fd);
}

int open_snd_init_file (snd_state *ss)
{ /* needed also by keyboard macro saver */
  return(open_restart_file(ss->init_file,TRUE));
}

void save_snd_options (snd_state *ss)
{
  int fd;
  fd = open_snd_init_file(ss);
  save_snd_state_options(ss,fd);
  close(fd);
}

int save_sound_state (snd_info *sp, void *ptr) 
{
  int chan,fd;
  chan_info *cp;
  axis_info *ap;
  fd = (int)ptr;
  sprintf(save_buf,"(%s %s)\n  (%s)\n  (setf contrast-button %d) (setf contrast %f)\n  (setf expand-button %d) (setf expand %f)\n",
	  (sp->read_only) ? "view" : "open",
	  sp->fullname,
	  (sp->syncing) ? "sync" : "unsync",
	  sp->contrasting,sp->contrast,
	  sp->expanding,sp->expand);
  write(fd,save_buf,strlen(save_buf));
  sprintf(save_buf,"  (setf speed %f)\n  (setf reverb-button %d)\n  (setf revscl %f)\n  (setf revlen %f)\n  (setf amp %f)\n",
	  sp->srate,sp->reverbing,sp->revscl,sp->revlen,sp->amp);
  write(fd,save_buf,strlen(save_buf));
  sprintf(save_buf,"  (setf filter-button %d)\n  (setf filter_order %d)\n",
	  sp->filtering,sp->filter_order);
  write(fd,save_buf,strlen(save_buf));
  for (chan=0;chan<sp->nchans;chan++)
    {
      cp = sp->chans[chan];
      ap = cp->axis;
      sprintf(save_buf,"  (select-channel %d)\n    (%s) (%s) (axes %f %f %f %f) (setf cursor %d)\n",
	      chan,
	      (cp->waving) ? "show-wave" : "hide-wave",
	      (cp->ffting) ? "show-fft" : "hide-fft",
	      ap->x0,ap->x1,ap->y0,ap->y1,cp->cursor);
      write(fd,save_buf,strlen(save_buf));
      if (cp->marks)
	{
	  sprintf(save_buf,"    (chan-marks");
	  write(fd,save_buf,strlen(save_buf));
	  report_chan_marks(cp,fd);
	  write(fd,")\n",2);
	}
    }
  return(0);
}

void save_snd_state (snd_state *ss)
{
  /* save as much as possible in the init-file format to restart in same state */
  /* (this function is called automagically behind the user's back to protect against system crash) */
  int fd;
  fd = creat(ss->backup_file,0666);
  if (fd == -1) return;
  save_snd_state_options(ss,fd);
  map_over_sounds(ss,save_sound_state,(void *)fd);
  /* open sound file in previous map can change window width and height */
  sprintf(save_buf,"(setf window-height %d) (setf window-width %d)\n",snd_window_height(ss),snd_window_width(ss));
  write(fd,save_buf,strlen(save_buf));
  save_recorder_state(ss,fd);
  close(fd);
}

void set_session_name (snd_state *ss, char *name)
{
  dir *dp;
  int i,latest,fd;
  time_t latest_date,date;
  char *filename,*sp,*dot;
  if (strcmp(name,".") == 0)
    {
      /* search for latest in *.snd-session list on current directory -- if none complain */
      dp = find_session_files_in_dir(".");
      if (dp->len == 0)
	fprintf(stderr,snd_string_no_session_files_found);
      else
	if (dp->len == 1)
	  ss->session_name = copy_string(dp->files[0]);
	else
	  {  
	    latest_date = file_write_date(dp->files[0]);
	    latest = 0;
	    for (i=1;i<dp->len;i++)
	      {
		date = file_write_date(dp->files[i]);
		if (date > latest_date) {latest_date = date; latest = i;}
	      }
	    ss->session_name = copy_string(dp->files[latest]);
	  }
      free_dir(dp);
    }
  else 
    {
      /* check first for .snd-session extension */
      dot = NULL;
      for (sp=name;(*sp) != '\0';sp++) if ((*sp) == '.') dot=sp;
      if ((dot) && (strcmp(dot,".snd-session") == 0))
	ss->session_name = copy_string(name);
      else
	{
	  filename = (char *)calloc(strlen(name)+13,sizeof(char));
	  sprintf(filename,"%s.snd-session",name);
	  fd = open(filename,O_RDONLY,0);
	  if (fd != -1)
	    {
	      ss->session_name = copy_string(filename);
	      close(fd);
	      return;
	    }
	  else
	    {
	      free(filename);
	      ss->session_name = copy_string(name);
	    }
	}
      fd = open(ss->session_name,O_RDONLY,0);
      if (fd == -1) 
	{
	  fprintf(stderr,snd_string_cant_find,ss->session_name);
	  free(ss->session_name);
	  ss->session_name = NULL;
	}
      else close(fd);
    }
}

void save_state (snd_state *ss, char *session_name)
{
  int save_fd;
  save_fd = open_restart_file(session_name,FALSE);
  if (save_fd == -1) 
    {
      sprintf(save_buf,snd_string_cant_write_p,session_name,strerror(errno));
      snd_printf(ss,save_buf);
    }
  else
    {
      save_snd_state_options(ss,save_fd);
      map_over_sounds(ss,save_sound_state,(void *)save_fd);  /* current sound state -- will traverse chans */
      sprintf(save_buf,"(setf window-height %d) (setf window-width %d)\n",snd_window_height(ss),snd_window_width(ss));
      write(save_fd,save_buf,strlen(save_buf));
      save_dialog_state(ss,save_fd);                         /* current dialog state not covered above */
      save_macro_state(ss,save_fd);                          /* current unsaved keyboard macros (snd-chn.c) */
      save_parser_state(ss,save_fd);                         /* possible newly defined parser variables */
      save_ufun_state(ss,save_fd);                           /* current user-function libraries etc */
      save_recorder_state(ss,save_fd);                       /* current recorder window state */
      save_envelope_editor_state(ss,save_fd);                /* current envelope editor window state */
      close(save_fd);
    }
}


void restore_state (snd_state *ss, char *session_name)
{
  snd_load_file(ss,session_name);
}
