#include <config.h>
#ifndef _plan9_
#include <limits.h>
#ifdef NO_MALLOC_H
#include <stdlib.h>
#else
#include <malloc.h>
#endif
#include <string.h>
#else
#include <u.h>
#include <libc.h>
#endif
#include <fconfig.h>
#include <filter.h>
#include <fractal.h>
#include <ui_helper.h>
#include <catalog.h>
#include <xmenu.h>
#include <grlib.h>
#include "play.h"

#ifdef HAVE_GETTEXT
#include <libintl.h>
#else
#define gettext(STRING) STRING
#endif

#define nextchar() (uih->playstring==NULL?xio_getc(FD):uih->playstring[uih->playpos++])
#define ungetchar(c) (uih->playstring==NULL?xio_ungetc(c,FD):uih->playpos--)
#define endoffile() (uih->playstring==NULL?xio_feof(FD):uih->playstring[uih->playpos]==0)
static int nonblockmode;
static catalog_t *catalog;	/*The message catalog should be "session wide" */
CONST static char *errstring;
#define seterr(str) {if(errstring==NULL) errstring=str;}
#define FD uih->playc->file
static char token[1024];
static int first;
static int last;
static int parsenext;

static CONST char *CONST animroot = "animroot";

static inline struct uih_line *
uih_findkey (uih_context * c, int key)
{
  struct uih_line *l = c->playc->lines.first;
  while (l != NULL)
    {
      if (l->key == key)
	return l;
      l = l->next;
    }
  return NULL;
}
static inline void
uih_removeline (uih_context * c, struct uih_line *l)
{
  if (l == NULL)
    return;
  uih_removew (c, l->w);
  if (l->prev)
    l->prev->next = l->next;
  else
    c->playc->lines.first = l->next;
  if (l->next)
    l->next->prev = l->prev;
  free (l);
}

void
uih_line (uih_context * c, dialogparam * d)
{
  struct uih_window *w;
  struct uih_line *l;
  if (c->playstring != NULL)
    {
      seterr (gettext ("line available only in animation replay"));
      return;
    }
  w = uih_registerline (c, 0, -1, -1, -1, -1);
  uih_removeline (c, uih_findkey (c, c->playc->lines.currkey));
  l = (struct uih_line *) calloc (1, sizeof (*l));
  l->posmode = d[0].dint;
  l->w = w;
  l->x1 = d[1].dcoord[0];
  l->y1 = d[1].dcoord[1];
  l->x2 = d[2].dcoord[0];
  l->y2 = d[2].dcoord[1];
  l->color = c->color;
  l->morph = 0;
  l->key = c->playc->lines.currkey++;
  l->prev = NULL;
  l->next = c->playc->lines.first;
  c->playc->lines.first = l;
}

void
uih_morphline (uih_context * c, dialogparam * d)
{
  struct uih_line *l;
  l = uih_findkey (c, c->playc->lines.currkey);
  if (l == NULL)
    {
      seterr (gettext ("Morphing non existing line!"));
      return;
    }
  c->playc->lines.currkey++;
  l->mposmode = d[0].dint;
  l->mx1 = d[1].dcoord[0];
  l->my1 = d[1].dcoord[1];
  l->mx2 = d[2].dcoord[0];
  l->my2 = d[2].dcoord[1];
  l->morph = 1;
  c->playc->lines.morphing = 1;
}

void
uih_morphlastline (uih_context * c, dialogparam * d)
{
  c->playc->lines.currkey--;
  uih_morphline (c, d);
}

void
uih_setkey (uih_context * c, int line)
{
  if (!c->play)
    {
      seterr (gettext ("linekey not available in this context!"));
      return;
    }
  c->playc->lines.currkey = line;
}
static void
uih_stopmorphing (uih_context * c)
{
  struct uih_line *l = c->playc->lines.first;
  while (l)
    {
      if (l->morph)
	{
	  l->x1 = l->mx1;
	  l->y1 = l->my1;
	  l->x2 = l->mx2;
	  l->y2 = l->my2;
	  l->posmode = l->mposmode;
	  l->morph = 0;
	  c->playc->lines.morphing = 1;
	}
      l = l->next;
    }
}
void
uih_update_lines (uih_context * c)
{
  int m = 0;
  int co;
  struct uih_line *l = c->playc->lines.first;
  int x1, y1, x2, y2;
  number_t x, y;
  int timer = tl_lookup_timer (c->playc->timer) - c->playc->starttime;
  number_t mmul =		/*(tl_lookup_timer (c->playc->timer) - c->playc->starttime) / (number_t) (c->playc->frametime - c->playc->starttime); */
    MORPHVALUE (timer, c->playc->frametime - c->playc->starttime,
		c->playc->morphlinetimes[0], c->playc->morphlinetimes[1]);


  while (l)
    {
      switch (l->posmode)
	{
	case 0:
	  x1 = (int) (c->image->width * l->x1);
	  y1 = (int) (c->image->height * l->y1);
	  x2 = (int) (c->image->width * l->x2);
	  y2 = (int) (c->image->height * l->y2);
	  break;
	case 1:
	  x = c->image->width * c->image->pixelwidth;
	  y = c->image->height * c->image->pixelheight;
	  if (x > y)
	    x = y;
	  x1 =
	    (int) (c->image->width / 2 +
		   (l->x1 - 0.5) * x / c->image->pixelwidth);
	  y1 =
	    (int) (c->image->height / 2 +
		   (l->y1 - 0.5) * x / c->image->pixelheight);
	  x2 =
	    (int) (c->image->width / 2 +
		   (l->x2 - 0.5) * x / c->image->pixelwidth);
	  y2 =
	    (int) (c->image->height / 2 +
		   (l->y2 - 0.5) * x / c->image->pixelheight);
	  break;
	case 2:
	  x = l->x1;
	  y = l->y1;
	  rotate (*(c->fcontext), x, y);
	  x =
	    (x - c->fcontext->rs.nc) / (c->fcontext->rs.mc -
					c->fcontext->rs.nc) *
	    c->zengine->image->width;
	  y =
	    (y - c->fcontext->rs.ni) / (c->fcontext->rs.mi -
					c->fcontext->rs.ni) *
	    c->zengine->image->height;
	  x1 = (int) x;
	  y1 = (int) y;
	  c->zengine->action->convertup (c->zengine, &x1, &y1);
	  x = l->x2;
	  y = l->y2;
	  rotate (*(c->fcontext), x, y);
	  x =
	    (x - c->fcontext->rs.nc) / (c->fcontext->rs.mc -
					c->fcontext->rs.nc) *
	    c->zengine->image->width;
	  y =
	    (y - c->fcontext->rs.ni) / (c->fcontext->rs.mi -
					c->fcontext->rs.ni) *
	    c->zengine->image->height;
	  x2 = (int) x;
	  y2 = (int) y;
	  c->zengine->action->convertup (c->zengine, &x2, &y2);
	  break;
	}
      if (l->morph)
	{
	  int mx1, mx2, my1, my2;
	  m = 1;
	  switch (l->mposmode)
	    {
	    case 0:
	      mx1 = (int) (c->image->width * l->mx1);
	      my1 = (int) (c->image->height * l->my1);
	      mx2 = (int) (c->image->width * l->mx2);
	      my2 = (int) (c->image->height * l->my2);
	      break;
	    case 1:
	      x = c->image->width * c->image->pixelwidth;
	      y = c->image->height * c->image->pixelheight;
	      if (x > y)
		x = y;
	      mx1 =
		(int) (c->image->width / 2 +
		       (l->mx1 - 0.5) * x / c->image->pixelwidth);
	      my1 =
		(int) (c->image->height / 2 +
		       (l->my1 - 0.5) * x / c->image->pixelheight);
	      mx2 =
		(int) (c->image->width / 2 +
		       (l->mx2 - 0.5) * x / c->image->pixelwidth);
	      my2 =
		(int) (c->image->height / 2 +
		       (l->my2 - 0.5) * x / c->image->pixelheight);
	      break;
	    default:
	      x = l->mx1;
	      y = l->my1;
	      rotate (*(c->fcontext), x, y);
	      x =
		(x - c->fcontext->rs.nc) / (c->fcontext->rs.mc -
					    c->fcontext->rs.nc) *
		c->zengine->image->width;
	      y =
		(y - c->fcontext->rs.ni) / (c->fcontext->rs.mi -
					    c->fcontext->rs.ni) *
		c->zengine->image->height;
	      mx1 = (int) x;
	      my1 = (int) y;
	      c->zengine->action->convertup (c->zengine, &mx1, &my1);
	      x = l->mx2;
	      y = l->my2;
	      rotate (*(c->fcontext), x, y);
	      x =
		(x - c->fcontext->rs.nc) / (c->fcontext->rs.mc -
					    c->fcontext->rs.nc) *
		c->zengine->image->width;
	      y =
		(y - c->fcontext->rs.ni) / (c->fcontext->rs.mi -
					    c->fcontext->rs.ni) *
		c->zengine->image->height;
	      mx2 = (int) x;
	      my2 = (int) y;
	      c->zengine->action->convertup (c->zengine, &mx2, &my2);
	      break;
	    }
	  x1 = (int) (x1 + (mx1 - x1) * mmul);
	  y1 = (int) (y1 + (my1 - y1) * mmul);
	  x2 = (int) (x2 + (mx2 - x2) * mmul);
	  y2 = (int) (y2 + (my2 - y2) * mmul);
	}
      switch (l->color)
	{
	case 1:
	  co = BGCOLOR (c);
	  break;
	case 0:
	  co = FGCOLOR (c);
	  break;
	default:
	  co = SELCOLOR (c);
	  break;
	}
      uih_setline (c, l->w, co, x1, y1, x2, y2);

      l = l->next;
    }
  c->playc->lines.morphing = m;
  if (m)
    c->display = 1;

}

void
uih_clear_line (uih_context * c)
{
  if (c->playstring != NULL)
    {
      seterr (gettext ("clear_line available only in animation replay"));
      return;
    }
  uih_removeline (c, uih_findkey (c, c->playc->lines.currkey++));
}

void
uih_clear_lines (uih_context * c)
{
  if (c->playstring != NULL)
    {
      seterr (gettext ("clear_lines available only in animation replay"));
      return;
    }
  while (c->playc->lines.first != NULL)
    uih_removeline (c, c->playc->lines.first);
  c->playc->lines.currkey = 0;
}

void
uih_freecatalog (uih_context * c)
{
  if (catalog != NULL)
    free_catalog (catalog), catalog = NULL;
}

void
uih_setfont (struct uih_context *uih)
{
  if (catalog != NULL && find_text (catalog, "encoding")
      && find_text (catalog, "encoding")[0] == '2')
    uih->encoding = 2;
  else
    uih->encoding = 1;
  if (uih->image->flags & AAIMAGE)
    uih->font = &xaafont;
  else
    {
      if (uih->encoding == 2)
	{
	  // A better heuristics would be used later.
	  if (uih->image->width > 1000 && uih->image->height > 720)
	    uih->font = &xbigfont3;
	  else
	    {
	      if (uih->image->width > 800 && uih->image->height > 600)
	        uih->font = &xbigfont2;
	      else
	        {
	          if (uih->image->pixelheight < 0.07)
	            uih->font = &xbigfont;
	          else
	            uih->font = &xsmallfont;
	        }
	    }
	}
      else
	{
	  if (uih->image->pixelheight < 0.04)
	    uih->font = &xbigfontil1;
	  else if (uih->image->pixelheight < 0.07)
	    uih->font = &xmedfontil1;
	  else
	    uih->font = &xsmallfontil1;
	}
    }
}

int
uih_loadcatalog (uih_context * c, CONST char *name)
{
  static int firsttime = 1;
  static CONST char *str;
  xio_file f = xio_getcatalog (name);
  if (f == XIO_FAILED)
    {
      if (firsttime)
	{
	  firsttime = 0;
	  return 0;
	}			/*Let XaoS work as stand alone executable */
      uih_error (c, gettext ("Catalog file not found"));
      return 0;
    }
  firsttime = 0;
  if (catalog != NULL)
    free_catalog (catalog);
  catalog = load_catalog (f, &str);
  if (str != NULL)
    uih_error (c, str);
  uih_setfont (c);
  return (catalog != NULL);
}
static void
handler (void *userdata)
{
  struct uih_context *uih = (struct uih_context *) userdata;
  uih->playc->playframe++;
  uih->inanimation = 2;
  if (uih->playc->timerin)
    tl_remove_timer (uih->playc->timer);
  uih->playc->timerin = 0;
}
static void
handler1 (void *userdata)
{
  struct uih_context *uih = (struct uih_context *) userdata;
  uih->playc->playframe++;
  uih->inanimation = 2;
  tl_update_time ();
  tl_reset_timer (uih->playc->timer);
  uih_setcomplettehandler (uih, NULL, NULL);
}

void
uih_skipframe (struct uih_context *uih)
{
  if (uih->play && uih->playc->timerin)
    handler (uih), tl_reset_timer (uih->playc->timer);
}

int
uih_replayenable (struct uih_context *uih, xio_file f, xio_constpath filename,
		  int animr)
{
  struct uih_playcontext *p;
  CONST char *s;
  if (uih->play)
    {
      uih_error (uih, gettext ("Replay is already active"));
      return 0;
    }
  if (f == XIO_FAILED)
    {
      uih_error (uih, gettext ("File open failed"));
      return 0;
    }
  p = (struct uih_playcontext *) calloc (1, sizeof (*p));
  if (p == NULL)
    {
      uih_error (uih, gettext ("Out of memory"));
      return 0;
    }
  if (animr)
    {
      uih->menuroot = animroot;
      uih_updatemenus (uih, NULL);
    }
  p->file = f;
  p->playframe = 1;
  p->timer = tl_create_timer ();
  p->frametime = 0;
  p->morph = 0;
  p->morphjulia = 0;
  p->lines.first = NULL;
  p->lines.morphing = 0;
  p->lines.currkey = 0;
  tl_update_time ();
  tl_set_handler (p->timer, handler, uih);
  uih_stoptimers (uih);
  if (uih->stoppedtimers)
    tl_stop_timer (p->timer);
  uih->playc = p;
  uih->play = 1;
  uih_emulatetimers (uih);
  tl_reset_timer (p->timer);
  uih->playc->line = 1;
  if (filename != NULL)
    {
      uih->playc->directory = xio_getdirectory (filename);
    }
  else
    {
      uih->playc->directory = xio_getdirectory (XIO_EMPTYPATH);
    }
  uih->playc->level = 0;
  s = uih->playstring;
  uih->playstring = NULL;
  uih_playupdate (uih);
  uih->playstring = s;
  return 1;
}

void
uih_replaydisable (struct uih_context *uih)
{
  if (uih->play)
    {
      int i;
      uih->play = 0;
      tl_free_timer (uih->playc->timer);
      if (uih->menuroot == animroot)
	{
	  uih->menuroot = "root";
	  uih_updatemenus (uih, NULL);
	}
      xio_close (uih->playc->file);
      for (i = 0; i < uih->playc->level; i++)
	xio_close (uih->playc->prevfiles[i]);
      uih->display = 1;
      uih->nonfractalscreen = 0;
      uih_setcomplettehandler (uih, NULL, NULL);
      uih_clear_lines (uih);
      free (uih->playc->directory);
      free (uih->playc);
      uih_display (uih);
    }
}
static void
skipblank (struct uih_context *uih)
{
  int c;
  if (uih->playstring != NULL)
    {
      while ((uih->playstring[uih->playpos] == ' ' ||
	      uih->playstring[uih->playpos] == '\t' ||
	      uih->playstring[uih->playpos] == '\r' ||
	      uih->playstring[uih->playpos] == '\n'))
	uih->playpos++;
      return;
    }
  do
    {
      c = xio_getc (FD);
      if (c == '\n')
	uih->playc->line++;
      if (c == ';')
	while (c != '\n' && !xio_feof (FD))
	  {
	    c = xio_getc (FD);
	    if (c == '\n')
	      uih->playc->line++;
	  }
      while (xio_feof (FD) && uih->playc->level)
	{
	  c = XIO_EOF + 1;
	  xio_close (FD);
	  uih->playc->file = uih->playc->prevfiles[--uih->playc->level];
	  uih->playc->line = 1;
	}
    }
  while (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == XIO_EOF + 1);
  if (c != XIO_EOF)
    xio_ungetc (c, FD);
}
static int
gettoken (struct uih_context *uih)
{
  int c;
  int i = 0;
  skipblank (uih);
  if (first && ((c = nextchar ()) != '('))
    {
      if (c && !endoffile ())
	{
	  seterr ("'(' expected");
	}
      last = 1;
      return -1;
    }
  if (first)
    skipblank (uih), first = 0;
  if (endoffile ())
    {
      if (uih->playstring)
	{
	  seterr (gettext ("Missing parameter"));
	}
      else
	seterr (gettext ("Unexpected end of file"));
      return 0;
    }
  if ((c = nextchar ()) == '"')
    {
      while (c == '\r')
	c = nextchar ();
      token[i] = '"';
      i++;
      do
	{
	  c = nextchar ();
	  while (c == '\r')
	    c = nextchar ();
	  if (c == XIO_EOF || c == 0)
	    {
	      if (uih->playstring)
		{
		  seterr (gettext ("Missing parameter"));
		}
	      else
		seterr (gettext ("Unexpected end of file"));
	      return 0;
	    }
	  if (c == '\n' && uih->playstring == NULL)
	    uih->playc->line++;
	  if (c == '\\')
	    token[i] = nextchar ();
	  else
	    token[i] = c;
	  i++;
	  if (i >= 1024)
	    {
	      seterr (gettext ("Token is too long"));
	      i = 0;
	    }
	}
      while (c != '"');
    }
  else
    ungetchar (c);
  do
    {
      c = nextchar ();
      if (c == XIO_EOF || c == 0)
	{
	  if (uih->playstring)
	    {
	      seterr (gettext ("Missing parameter"));
	    }
	  else
	    seterr (gettext ("Unexpected end of file"));
	  return 0;
	}
      token[i] = c;
      i++;
      if (i >= 1024)
	{
	  seterr (gettext ("Token is too long"));
	  i = 0;
	}
    }
  while (c != ' ' && c != '\t' && c != ')' && c != '\n' && c != '\r');
  i--;
  token[i] = 0;
  skipblank (uih);
  if (c == ')')
    {
      last = 1;
      return i;
    }
  c = nextchar ();
  if (uih->playstring == NULL)
    {
      while (xio_feof (FD) && uih->playc->level)
	uih->playc->file =
	  uih->playc->prevfiles[--uih->playc->level], uih->playc->line = 1;
    }
  if (c == XIO_EOF || c == 0)
    {
      if (uih->playstring)
	{
	  seterr (gettext ("Missing parameter"));
	}
      else
	seterr (gettext ("Unexpected end of file"));
      return 0;
    }
  if (c == ')')
    {
      last = 1;
      return i;
    }
  ungetchar (c);
  return i;
}
static char *
gettokenwr (struct uih_context *c)
{
  if (last)
    return NULL;
  if (gettoken (c) < 0)
    return NULL;
  if (errstring)
    return NULL;
  return (token);
}

void
uih_play_formula (struct uih_context *uih, char *fname)
{
  int i;
  for (i = 0; i < nformulas; i++)
    {
      if (!strcmp (formulas[i].shortname, fname))
	{
	  set_formula (uih->fcontext, i);
	  uih_newimage (uih);
	  return;
	}
    }
  seterr (gettext ("Unknown formula type"));
}

void
uih_playmorph (struct uih_context *uih, dialogparam * d)
{
  if (uih->playstring != NULL)
    {
      seterr (gettext ("morph available only in animation replay"));
      return;
    }
  if (d[2].number <= 0 || d[3].number <= 0)
    {
      seterr (gettext ("morphview: Invalid viewpoint"));
      uih->playc->destination = uih->fcontext->currentformula->v;
    }
  uih->playc->source = uih->fcontext->s;
  uih->playc->destination.cr = d[0].number;
  uih->playc->destination.ci = d[1].number;
  uih->playc->destination.rr = d[2].number;
  uih->playc->destination.ri = d[3].number;
  uih->playc->morph = 1;
}

void
uih_playmove (struct uih_context *uih, number_t x, number_t y)
{
  if (uih->playstring != NULL)
    {
      seterr (gettext ("move available only in animation replay"));
      return;
    }
  uih->playc->source = uih->fcontext->s;
  uih->playc->destination.cr = x;
  uih->playc->destination.ci = y;
  uih->playc->destination.rr = uih->fcontext->s.rr;
  uih->playc->destination.ri = uih->fcontext->s.ri;
  uih->playc->morph = 1;
}

void
uih_playmorphjulia (struct uih_context *uih, number_t x, number_t y)
{
  if (uih->playstring != NULL)
    {
      seterr (gettext ("morphjulia available only in animation replay"));
      return;
    }
  uih->playc->sr = uih->fcontext->pre;
  uih->playc->si = uih->fcontext->pim;
  uih->playc->dr = x;
  uih->playc->di = y;
  uih->playc->morphjulia = 1;
}

void
uih_playmorphangle (struct uih_context *uih, number_t angle)
{
  if (uih->playstring != NULL)
    {
      seterr (gettext ("morphangle available only in animation replay"));
      return;
    }
  uih->playc->morphangle = 1;
  uih->playc->srcangle = uih->fcontext->angle;
  uih->playc->destangle = angle;
}

void
uih_playautorotate (struct uih_context *uih, int mode)
{
  if (mode)
    {
      uih_fastrotateenable (uih);
      uih_rotatemode (uih, ROTATE_CONTINUOUS);
    }
  else
    uih_rotatemode (uih, ROTATE_NONE);
}

void
uih_playfilter (struct uih_context *uih, dialogparam * p)
{
  CONST char *fname = p[0].dstring;
  int mode;
  int i;
  for (i = 0; i < uih_nfilters; i++)
    {
      if (!strcmp (uih_filters[i]->shortname, fname))
	{
	  mode = p[1].dint;
	  if (mode)
	    uih_enablefilter (uih, i);
	  else
	    uih_disablefilter (uih, i);
	  return;
	}
    }
  seterr (gettext ("Unknown filter"));
}

void
uih_playdefpalette (struct uih_context *uih, int shift)
{
  if (uih->zengine->fractalc->palette == NULL)
    return;
  if (mkdefaultpalette (uih->zengine->fractalc->palette) != 0)
    {
      uih_newimage (uih);
    }
  uih->palettetype = 0;
  uih->palettechanged = 1;
  if (shiftpalette (uih->zengine->fractalc->palette, shift))
    {
      uih_newimage (uih);
    }
  uih->manualpaletteshift = 0;
  uih->paletteshift = shift;
}

void
uih_zoomcenter (struct uih_context *uih, number_t x, number_t y)
{
  uih->xcenter = x;
  uih->ycenter = y;
  uih->xcenterm = INT_MAX;
  uih->ycenterm = INT_MAX;
}
extern char *xtextposnames[];
extern char *ytextposnames[];
void
uih_playtextpos (struct uih_context *uih, dialogparam * p)
{
  int x, y;
  x = p[0].dint;
  y = p[1].dint;
  uih_settextpos (uih, x, y);
}

void
uih_playusleep (struct uih_context *uih, int time)
{
  parsenext = 0;
  if (uih->playstring != NULL)
    {
      seterr (gettext ("sleep available only in animation replay"));
      return;
    }
  uih->playc->frametime = time;
  if (time < tl_lookup_timer (uih->playc->timer)	/*&&((!uih->step)||(!uih->zoomactive)) */
    )
    {
      tl_slowdown_timer (uih->playc->timer, time);
      uih->playc->playframe++;
    }
  else
    {
      tl_set_interval (uih->playc->timer, time);
      if (!uih->playc->timerin)
	{
	  uih->playc->timerin = 1;
	  tl_add_timer (syncgroup, uih->playc->timer);
	}
      else
	printf (gettext ("Internal program error #12 %i\n"),
		uih->playc->playframe);
    }
  uih->playc->starttime = tl_lookup_timer (uih->playc->timer);
}

void
uih_playtextsleep (struct uih_context *uih)
{
  uih_playusleep (uih,
		  500000 + 1000000 * (uih->nletters +
				      uih->todisplayletters) /
		  uih->letterspersec);
  uih->nletters = 0;
  uih->todisplayletters = 0;
}


void
uih_playwait (struct uih_context *uih)
{
  parsenext = 0;
  if (uih->playstring != NULL)
    {
      seterr (gettext ("wait available only in animation replay"));
      return;
    }
  if (!uih->uncomplette && !uih->display && !uih->recalculatemode
      && !uih->displaytext && !uih->clearscreen)
    {
      uih->playc->playframe++;
    }
  else
    {
      uih_setcomplettehandler (uih, handler1, uih);
    }
}
void
uih_playjulia (struct uih_context *uih, int julia)
{
  julia = !julia;
  if (julia != uih->fcontext->mandelbrot)
    {
      uih->fcontext->mandelbrot = julia;
      uih->fcontext->version++;
      uih_updatemenus (uih, "uimandelbrot");
      uih_newimage (uih);
    }
}
void
uih_playcalculate (struct uih_context *uih)
{
  uih_newimage (uih);
}

void
uih_playzoom (struct uih_context *uih)
{
  uih->zoomactive = 1;
}

void
uih_playunzoom (struct uih_context *uih)
{
  uih->zoomactive = -1;
}

void
uih_playstop (struct uih_context *uih)
{
  uih->zoomactive = 0;
}

void
uih_playmessage (struct uih_context *uih, char *name)
{
  char *message;
  if (catalog == NULL)
    {
      uih_text (uih, gettext ("No catalog file loaded"));
      return;
    }
  message = find_text (catalog, name);
  if (message == NULL)
    {
      uih_text (uih, gettext ("Message not found in catalog file"));
      return;
    }
  uih_text (uih, message);
}

void
uih_playload (struct uih_context *uih, xio_path file)
{
  xio_file f;
  xio_pathdata tmp;
  if (uih->playstring != NULL)
    {
      seterr (gettext ("load available only in animation replay"));
      return;
    }
  if (uih->playc->level == MAXLEVEL)
    {
      seterr (gettext ("Include level overflow"));
      return;
    }


  xio_addfname (tmp, uih->playc->directory, file);
  f = xio_ropen (tmp);

  if (f == XIO_FAILED)
    {
      seterr (gettext ("File not found"));
      return;
    }
  uih->playc->prevfiles[uih->playc->level] = uih->playc->file;
  uih->playc->level++;
  uih->playc->file = f;
  uih->playc->line = 1;
}
static void
uih_processcommand (struct uih_context *uih, int flags)
{
  CONST char *error;
  first = 1;
  last = 0;
  error = menu_processcommand (uih, gettokenwr, 1, flags, uih->menuroot);
  if (error != NULL)
    seterr (error);
  if (!last)
    {
      seterr (gettext ("Too many parameters"));
    }
}
void
uih_playupdate (struct uih_context *uih)
{
  static char errtext[1024];
  errstring = NULL;
  while (uih->play && uih->playc->playframe && errstring == NULL)
    {
      parsenext = 1;
      uih->playc->playframe--;
      if (uih->playc->lines.morphing)
	{
	  uih_stopmorphing (uih);
	  uih->display = 1;
	}
      if (uih->playc->morph)
	{
	  uih->fcontext->s = uih->playc->destination;
	  uih_animate_image (uih);
	  uih->playc->morph = 0;
	}
      if (uih->playc->morphangle)
	{
	  uih_angle (uih, uih->playc->destangle);
	  uih->playc->morphangle = 0;
	}
      if (uih->playc->morphjulia)
	{
	  uih_setjuliaseed (uih, uih->playc->dr, uih->playc->di);
	  uih->playc->morphjulia = 0;
	}
      while (!xio_feof (FD) && parsenext && errstring == NULL)
	{
	  uih_processcommand (uih, MENUFLAG_NOPLAY);
	}			/*while parsenext */
      uih_update_lines (uih);
      if (errstring != NULL)
	{
	  uih_error (uih, errstring);
	  if (uih->play)
	    {
	      sprintf (errtext, gettext ("Replay disabled at line %i"),
		       uih->playc->line);
	      uih_message (uih, errtext);
	    }
	  /*errstring[255]=0; */
	}
      if ((xio_feof (FD) && parsenext) || errstring)
	{
	  uih_replaydisable (uih);
	}
    }				/*while play&&playframe */
}
void
uih_load (struct uih_context *uih, xio_file f, xio_constpath filename)
{
  nonblockmode = 1;
  uih_replayenable (uih, f, filename, 0);
  uih_replaydisable (uih);
  nonblockmode = 0;
}

void
uih_command (struct uih_context *uih, CONST char *command)
{
  errstring = NULL;
  uih->playpos = 0;
  uih->playstring = command;
  uih_processcommand (uih, (uih->play ? MENUFLAG_NOMENU : 0));
  uih->playstring = NULL;
  if (errstring != NULL)
    {
      uih_error (uih, errstring);
    }
}
