#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "grap.h"
#include "y.tab.h"

int     nnum    = 0;    /* number of saved numbers */
double  num[MAXNUM];

int     just;           /* current justification mode (RJUST, etc.) */
int     sizeop;         /* current optional operator for size change */
double  sizexpr;        /* current size change expression */

void savenum(int n, double f)   /* save f in num[n] */
{
       num[n] = f;
       nnum = n+1;
       if (nnum >= MAXNUM)
               ERROR "too many numbers" WARNING;
}

void setjust(int j)
{
       just |= j;
}

void setsize(int op, double expr)
{
       sizeop = op;
       sizexpr = expr;
}

char *tostring(char *s)
{
       register char *p;

       p = malloc(strlen(s)+1);
       if (p == NULL)
               ERROR "out of space in tostring on %s", s FATAL;
       strcpy(p, s);
       return(p);
}

void range(Point pt)    /* update the range for point pt */
{
       Obj *p = pt.obj;

       if (!(p->coord & XFLAG)) {
               if (pt.x > p->pt1.x)
                       p->pt1.x = pt.x;
               if (pt.x < p->pt.x)
                       p->pt.x = pt.x;
       }
       if (!(p->coord & YFLAG)) {
               if (pt.y > p->pt1.y)
                       p->pt1.y = pt.y;
               if (pt.y < p->pt.y)
                       p->pt.y = pt.y;
       }
}

void halfrange(Obj *p, int side, double val)    /* record max and min for one direction */
{
       if (!(p->coord&XFLAG) && (side == LEFT || side == RIGHT)) {
               if (val < p->pt.y)
                       p->pt.y = val;
               if (val > p->pt1.y)
                       p->pt1.y = val;
       } else if (!(p->coord&YFLAG) && (side == TOP || side == BOT)) {
               if (val < p->pt.x)
                       p->pt.x = val;
               if (val > p->pt1.x)
                       p->pt1.x = val;
       }
}


Obj *lookup(char *s, int inst)  /* find s in objlist, install if inst */
{
       Obj *p;
       int found = 0;

       for (p = objlist; p; p = p->next){
               if (strcmp(s, p->name) == 0) {
                       found = 1;
                       break;
               }
       }
       if (p == NULL && inst != 0) {
               p = (Obj *) calloc(1, sizeof(Obj));
               if (p == NULL)
                       ERROR "out of space in lookup" FATAL;
               p->name = tostring(s);
               p->type = NAME;
               p->pt = ptmax;
               p->pt1 = ptmin;
               p->fval = 0.0;
               p->next = objlist;
               objlist = p;
       }
       dprintf("lookup(%s,%d) = %d\n", s, inst, found);
       return p;
}

double getvar(Obj *p)   /* return value of variable */
{
       return p->fval;
}

double setvar(Obj *p, double f) /* set value of variable to f */
{
       if (strcmp(p->name, "pointsize") == 0) {        /* kludge */
               pointsize = f;
               ps_set = 1;
       }
       p->type = VARNAME;
       return p->fval = f;
}

Point makepoint(Obj *s, double x, double y)     /* make a Point */
{
       Point p;

       dprintf("makepoint: %s, %g,%g\n", s->name, x, y);
       p.obj = s;
       p.x = x;
       p.y = y;
       return p;
}

Attr *makefattr(int type, double fval)  /* set double in attribute */
{
       return makeattr(type, fval, (char *) 0, 0, 0);
}

Attr *makesattr(char *s)                /* make an Attr cell containing s */
{
       Attr *ap = makeattr(STRING, sizexpr, s, just, sizeop);
       just = sizeop = 0;
       sizexpr = 0.0;
       return ap;
}

Attr *makeattr(int type, double fval, char *sval, int just, int op)
{
       Attr *a;

       a = (Attr *) malloc(sizeof(Attr));
       if (a == NULL)
               ERROR "out of space in makeattr" FATAL;
       a->type = type;
       a->fval = fval;
       a->sval = sval;
       a->just = just;
       a->op = op;
       a->next = NULL;
       return a;
}

Attr *addattr(Attr *a1, Attr *ap)       /* add attr ap to end of list a1 */
{
       Attr *p;

       if (a1 == 0)
               return ap;
       if (ap == 0)
               return a1;
       for (p = a1; p->next; p = p->next)
               ;
       p->next = ap;
       return a1;
}

void freeattr(Attr *ap) /* free an attribute list */
{
       Attr *p;

       while (ap) {
               p = ap->next;   /* save next */
               if (ap->sval)
                       free(ap->sval);
               free((char *) ap);
               ap = p;
       }
}

char *slprint(Attr *stringlist) /* print strings from stringlist */
{
       int ntext, n, last_op, last_just;
       double last_fval;
       static char buf[1000];
       Attr *ap;

       buf[0] = '\0';
       last_op = last_just = 0;
       last_fval = 0.0;
       for (ntext = 0, ap = stringlist; ap != NULL; ap = ap->next)
               ntext++;
       sprintf(buf, "box invis wid 0 ht %d*textht", ntext);
       n = strlen(buf);
       for (ap = stringlist; ap != NULL; ap = ap->next) {
               if (ap->op == 0) {      /* propagate last value */
                       ap->op = last_op;
                       ap->fval = last_fval;
               } else {
                       last_op = ap->op;
                       last_fval = ap->fval;
               }
               sprintf(buf+n, " \"%s\"", ps_set || ap->op ? sizeit(ap) : ap->sval);
               if (ap->just)
                       last_just = ap->just;
               if (last_just)
                       strcat(buf+n, juststr(last_just));
               n = strlen(buf);
       }
       return buf;     /* watch it:  static */
}

char *juststr(int j)    /* convert RJUST, etc., into string */
{
       static char buf[50];

       buf[0] = '\0';
       if (j & RJUST)
               strcat(buf, " rjust");
       if (j & LJUST)
               strcat(buf, " ljust");
       if (j & ABOVE)
               strcat(buf, " above");
       if (j & BELOW)
               strcat(buf, " below");
       return buf;     /* watch it:  static */
}

char *sprntf(char *s, Attr *ap) /* sprintf(s, attrlist ap) */
{
       char buf[500];
       int n;
       Attr *p;

       for (n = 0, p = ap; p; p = p->next)
               n++;
       switch (n) {
       case 0:
               return s;
       case 1:
               sprintf(buf, s, ap->fval);
               break;
       case 2:
               sprintf(buf, s, ap->fval, ap->next->fval);
               break;
       case 3:
               sprintf(buf, s, ap->fval, ap->next->fval, ap->next->next->fval);
               break;
       case 5:
               ERROR "too many expressions in sprintf" WARNING;
       case 4:
               sprintf(buf, s, ap->fval, ap->next->fval, ap->next->next->fval, ap->next->next->next->fval);
               break;
       }
       free(s);
       return tostring(buf);
}