/*
    Clif - A C-like Interpreter Framework
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997 T. Hruz, L. Koren

    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.

*/

/*
 * channel_maint.c
 */

#include "channel_maint.h"
#include "mystdio.h"
#include "allocx.h"
#include <math.h>
#include <stdlib.h>
#include <stdio.h>

#ifndef PROTO
#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined(__STDC__)
#define PROTO(ARGS) ARGS
#else
#define PROTO(ARGS) ()
#endif 
#endif

extern int yy_channelparse PROTO((void));
extern void init_ch PROTO((char *));
extern char *allocate PROTO((unsigned, unsigned));

int channel_handle = 0;
char window_name_init[30] = "clif_channel_handle_";
char window_name_cur[30] = "clif_channel_handle_";
char window_name_wr_init[30] = "clif_alpha_channel_handle_";
char window_name_wr_cur[30] = "clif_alpha_channel_handle_";
char window_name_tmp[5];
struct CHANNEL channel[NUMBER_OF_CHANNELS];

#ifdef XWIN
XEvent event;
GC default_gc, set_gc_write;
Display *disp;
#include "xwin.c"
#include "wind.c"
#include "wind_w.c"
#endif

#ifdef MSWIN
#include "mswin.c"
#include "mswind.c"
#include "mswind_w.c"
#endif

void chwrite PROTO((char **));
void chclose PROTO((char **));
void chflush PROTO((void));
static void append PROTO((struct LIST **, struct LIST **));
static int append_record PROTO((struct LIST **, double));
static void redraw_dur_aut PROTO((int));
static void reset_start_aut PROTO((int, double));
static void free_list PROTO((struct RECORD **));
static int fill_write PROTO((int));
int chopen PROTO((char **));


/*
 * Writing to a channel
 */
void 
chwrite (a)
  char **a;
{
  int *handle;
  double *x;
  int n;
  
  handle = (int *)a[0];
  x = (double *)a[1];

  append_record(&channel[*handle].list_tmp,*x);
/*
 * Creating a list from data written into the channel
 * Sampling of data to fill a record
 */
  channel[*handle].cnt++;
  if(channel[*handle].fields == channel[*handle].cnt) 
	/* 
	 * checking if record is full
	 */
    {
      channel[*handle].global_cnt++;
      if ((channel[*handle].global_cnt
	   > (LINEAR_WINDOW_CONSTANT
	      * (channel[*handle].start_time 
		 + pow (channel[*handle].duration_time 
			+ channel[*handle].d_time, 2.))))
	  && (channel[*handle].d_time > 0))
	
	/* 
	 * Redrawing for DURATION_TIME = automatic
	 */
	{
	  d_flush ();
	  if (!strcmp (channel[*handle].on_leave_w, "suspend"))
	    d_pause (*handle);
	  d_clear (*handle);
	  redraw_dur_aut (*handle);
	}
      if ((channel[*handle].global_cnt
	   > (channel[*handle].start_time 
	      + channel[*handle].duration_time))
	  && (channel[*handle].s_time > 0))
	
	/* 
	 * Redrawing for START_TIME = automatic
	 */
	{
	  reset_start_aut (*handle, *x);
	  d_flush ();
	  if (!strcmp (channel[*handle].on_leave_w, "suspend"))
	    d_pause (*handle);
	  d_clear (*handle);
	}
      if (!strcmp (channel[*handle].type, "alpha")) 
	/*
	 * Checking if alphanumerical window were specified
	 * if yes it is filled with appropriate data
	 */
	fill_write (*handle);
      for (n = 0; n < channel[*handle].fields; n++)
	{
	  if(!strcmp (channel[*handle].print_format, "line"))
	    /* 
	     * Drawing the line
	     */
	    {
	      if (channel[*handle].global_cnt == 1)
		{
		  channel[*handle].member[n].x_cur
		    = channel[*handle].global_cnt;
		  channel[*handle].member[n].y_cur = *x;
		}
	      else
		{
		  move (*handle, n, channel[*handle].member[n].x_cur,
			channel[*handle].member[n].y_cur);
		  draw (*handle, n, channel[*handle].global_cnt, *x);
		  channel[*handle].member[n].x_cur
		    = channel[*handle].global_cnt;
		  channel[*handle].member[n].y_cur = *x;
		}
	    }
	  else	/* 
		 * Drawing the points
		 */
	    draw_point (*handle, n, channel[*handle].global_cnt, *x);
	}
      append (&channel[*handle].list, &channel[*handle].list_tmp);
      /*
       * Creating a global list of records written to the channel
       * The data are writen into the list because we support
       * redrawing of the window by DURATION_TIME or START_TIME 
       * specified as automatic
       */
      
      channel[*handle].cnt = 0;
      
    }
}

/*
 * Closing the window with handle a
 */
void
chclose (a)
  char **a;
{
  int *handle;

  handle = (int *)a[0];

  d_destroy_window (*handle);
  if (!strcmp (channel[*handle].type, "alpha"))
/* If it exists alphanumerical window it is destroyed as well */
    d_destroy_window_write (*handle);
}

/*
 * Flush of buffers
 */
void
chflush ()
{
  d_flush ();
}

/*
 * Appending to the global list
 */
static void 
append (z1, z2)
  struct LIST **z1, **z2;
{
  if((*z1)->tail == NULL)
    {
      (*z1)->head = (*z2)->head;
      (*z2)->head = NULL;
      (*z1)->tail = (*z2)->tail;
      (*z2)->tail = NULL;
    }
  else
    {
      (*z1)->tail->next = (*z2)->head;
      (*z2)->head = NULL;
      (*z1)->tail = (*z2)->tail;
      (*z2)->tail = NULL;
    }
}

/*
 * Appending to the record's list
 */
static int
append_record (z2, x)	
  struct LIST **z2;
  double x;
{
  if((*z2)->tail == NULL)
    {
      (*z2)->head =
	(struct RECORD *) allocate (sizeof(struct RECORD), PERM);
      (*z2)->head->x = x;
      (*z2)->head->next = NULL;
      (*z2)->tail = (*z2)->head;
    }
  else
    {
      (*z2)->tail->next = 
	(struct RECORD *) allocate (sizeof(struct RECORD), PERM);
      (*z2)->tail->next->x = x;
      (*z2)->tail->next->next = NULL;
      (*z2)->tail = (*z2)->tail->next;
    }
  return (0);
}

/*
 * Redrawing by DURATION_TIME = automatic
 */
static void
redraw_dur_aut (handle)
  int handle;
{
  struct RECORD *scan;
  double global_cnt;
  int n;

  channel[handle].d_time++;
  for (n = 0; n < channel[handle].fields; n++)
    window (handle, n, channel[handle].start_time,
	    channel[handle].member[n].lower,
	    LINEAR_WINDOW_CONSTANT
	    * (channel[handle].start_time
	       + pow(channel[handle].duration_time
		     + channel[handle].d_time,2.)),
	    channel[handle].member[n].upper);
	/*
 	 * Changes world coordinates of the window
	 */

  scan = channel[handle].list->head;
  global_cnt = 0;
  while (scan != NULL)
    {
      global_cnt++;
      for (n = 0; n < channel[handle].fields; n++)
	{
	  if (!strcmp (channel[handle].print_format, "line"))
	    {			
	      if (scan == channel[handle].list->head)
		{
		  channel[handle].member[n].x_cur = global_cnt;
		  channel[handle].member[n].y_cur = scan->x;
		}
	      else
		{
		  move (handle, n, channel[handle].member[n].x_cur,
			channel[handle].member[n].y_cur);
		  draw (handle, n, global_cnt, scan->x);
		  channel[handle].member[n].x_cur = global_cnt;
		  channel[handle].member[n].y_cur = scan->x;
		}
	    }
	  else
	    draw_point (handle, n, global_cnt, scan->x);

	  scan = scan->next;
	}
    }
}

/*
 * Resetting of new begin by START_TIME = automatic
 */
static void
reset_start_aut (handle,x) 
  int handle;
  double x;
{
  struct RECORD *scan;
  int n;

  scan = channel[handle].list->head;
  while (NULL != scan->next)
    {
      channel[handle].list->head = scan->next;
      free_list (&scan);
      scan = channel[handle].list->head;
    }

  channel[handle].start_time += channel[handle].duration_time;

  for (n = 0; n < channel[handle].fields; n++)
    window (handle, n, channel[handle].start_time,
	    channel[handle].member[n].lower,
	    channel[handle].start_time
	    + channel[handle].duration_time,
	    channel[handle].member[n].upper);
  for (n = 0; n < channel[handle].fields; n++)
    {
      channel[handle].member[n].x_cur = channel[handle].global_cnt;
      channel[handle].member[n].y_cur = scan->x;
    }
}

static void
free_list (z3)
  struct RECORD **z3;
{
#if 0  
  free (*z3);
#endif
}

/*
 * Writing to the text (alphanumerical) window
 */
static int
fill_write (handle)
  int handle;
{
  int cnt;
  char str[RECORD_WIDTH];
  char str_tmp[RECORD_WIDTH];
  struct RECORD *z3;
  int y = 9;

  z3 = channel[handle].list_tmp->head;
  d_clear_text( handle);
  while(NULL != z3)
    {
      str[0] = '\0';
      for (cnt = 0; cnt < 5; cnt++)
	{
	  sprintf (str_tmp, "%g", z3->x);
	  strcat (str, str_tmp);
	  strcat (str, " ");
	  z3 = z3->next;
	  if (z3 == NULL)
	    break;
	}
#ifdef XWIN
      channel[handle].item.chars = str;
      channel[handle].item.nchars = strlen
	(channel[handle].item.chars);
/* nemusi byt strlen +1 lebo chcem pocet znakov iba a nie alloc pamate */
      d_draw_text (handle, 0, y);
      y += 15; 
      channel[handle].item.chars = NULL;
#endif
#ifdef MSWIN
      channel[handle].item = allocate (strlen (str) + 1, PERM);
      strcpy (channel[handle].item,str);
      d_draw_text (handle,0,y);
      y += 15;
#if 0
      free (channel[handle].item);
#endif
      channel[handle].item = NULL;
#endif
    }
  return (0);
}

/*
 * Opening of the channel
 * It starts the compiler for parsing of the input string
 */
int
chopen (input_buffer)
  char **input_buffer;
{
  int handle = 0;
  init_ch (*input_buffer);
/*
 * Initialization of the input
 */
  if (yy_channelparse () == -2)
    return(-2); /* Syntax error */

  handle = wind ();
  if ((!strcmp (channel[channel_handle].type, "alpha")) 
/*
 * Checking if alphanumerical window was specified as well
 */
      && (wind_w () == -1))
    return (-1); /* Return if the window was not opened */

  channel_handle++;
  return (handle);
}



