
/* "UNTIL", a graphics editor,
   Copyright (C) 1985, 1990 California Institute of Technology.
   Original authors: Glenn Gribble, port by Steve DeWeerth
   Unix Port Maintainer: John Lazzaro
   Maintainers's address: lazzaro@hobiecat.cs.caltech.edu;
                          CB 425 CU Boulder/Boulder CO 91125. 

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 (Version 1, 1989).

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; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
USA. */


/*******************************************************************************/
/*                                                                             */ 
/*  file contains stuff used to read in until.cnf file                         */
/*  cleaned up by steve - 8 May 1990                                           */
/*                                                                             */ 
/*******************************************************************************/

#include <time.h>

#include <p2c/p2c.h>

#include "data_types.h"

#ifndef MYLIB_H
#include <p2c/mylib.h>
#endif

#ifndef NEWASM_H
#include <p2c/newasm.h>
#endif

#ifndef ASM_H
#include <p2c/asm.h>
#endif

#ifndef LUNIX_PAS_H
#include <p2c/lunix_pas.h>
#endif

#ifndef CITINFOMOD_H
#include <p2c/citinfomod.h>
#endif


figure *curFigure;   /* Current figure */
fileSpec *curFile;   /* Current file */
fileSpec *files;   /* List of files */

short curColor;  /* Current Color */
short curLWid;  /* Wide Line stuff */
boolean doubleArrows;  /* Arrow information */

/* Wide Arrow stuff */
short curLWidW;   /* Line width */
short curWWidW;   /* Wing width */
short curWLenW;   /* Wing length */

/* Narrow Arrow stuff */
short curWWidN;   /* Wing width */
short curWLenN;   /* Wing length */

/* Text attributes */
centerType curTextOrig;
short curTextScale;   /* Scaling in Points */
short curTextRot;   /* Rotation angle */
short curTextSlant;   /* Slant angle */
short curTextFont;   /* Font number */

boolean showInstBB;  /* Show bounding box of instances? */

short curRots;  /* Number of possible rotations */



Char *today(Char *Result)
{
  long now;
  Char s[64];
  Char u[41];

  time(&now);
  sprintf(s, "%s", ctime(&now));
  s[strlen(s) - 1] = '\0';

  strlower(u, P_citinfo->username);
  u[0] = toupper(u[0]);
  
  sprintf(Result, "%s by %s", s, u);
  return Result;
}


long numpnts(pnt_elem *p)
{
  long n;

  n = 0;
  while (p != NULL) {
    n++;
    p = p->next;
  }
  return n;
}


void restore_color(void)
{
  m_colormode(m_normal);
  m_color(curColor);
}


Static Char *objkinds_NAMES[] = {
  "O_BASE", "O_PRIM"
} ;


Static Char *primkinds_NAMES[] = {
  "PR_NONE", "PR_DOT", "PR_LINE", "PR_BOX", "PR_CIRCLE", "PR_ELLIPSE",
  "PR_NGON", "PR_TEXT", "PR_INST", "PR_LAST"
} ;


/* Perform the necessary matrix operations to create the matrix for this instance. */
void set_instance_mat(object *o)
{
  mat_state m;
  long cx, cy;
  bbrec *WITH;

  if (o->kind != pr_inst) {
    printf("set_instance_mat: WRONG PRIM KIND %s %s\n",
	   objkinds_NAMES[(long)o->kind],
	   primkinds_NAMES[(long)o->kind]);
    return;
  }
  if (o->okind.i.matOnly)
    return;
  mat_push(&m);

  ctm = mat_ident_mat;
  WITH = &o->okind.i.contents->bb;
  cx = (WITH->xh + WITH->xl) / 2;
  cy = (WITH->yh + WITH->yl) / 2;

  mat_tran(o->okind.i.tx, o->okind.i.ty);
  mat_scale(o->okind.i.sx, o->okind.i.sy, o->okind.i.den);
  mat_rot((long)floor(256 * cosD(o->okind.i.rot) + 0.5), 
          (long)floor(256 * sinD(o->okind.i.rot) + 0.5));

  o->okind.i.m = ctm;

  mat_pop(&m);

  /* Now, we should reset the MBB, since this may have changed. */
  set_instance_mbb(o, false);
}


void set_ellipse_mbb(object *o)
{
  pr_ellipse_rec *WITH;

  WITH = &o->okind.e;
  ellipseArcBB(WITH->cx, WITH->cy, WITH->a, WITH->b, WITH->s, WITH->l, WITH->r, WITH->pie, &o->bb);
}


/* Perform the matrix operations to update the instance MBB from the object that it calls. */
void set_instance_mbb(object *o, boolean recurse)
{
  mat_state m;
  long x, y;
  bbrec *WITH1;

  if (o->kind != pr_inst) {
    printf("set_instance_mbb: WRONG PRIM KIND %s %s\n",
	   objkinds_NAMES[(long)o->kind],
	   primkinds_NAMES[(long)o->kind]);
    return;
  }

  if (recurse)
    set_base_mbb(o->okind.i.contents, true);

  /* All four corners of contents^.BB must be transformed by o.i.m to get true MBB for */
  mat_push(&m);
  ctm = o->okind.i.m;
  WITH1 = &o->okind.i.contents->bb;
  emptybb(&o->bb);   /* Empty out instance BB */
  mat_transform(WITH1->xh, WITH1->yh, &x, &y);
  addbbpnt(&o->bb, x, y);
  mat_transform(WITH1->xh, WITH1->yl, &x, &y);
  addbbpnt(&o->bb, x, y);
  mat_transform(WITH1->xl, WITH1->yh, &x, &y);
  addbbpnt(&o->bb, x, y);
  mat_transform(WITH1->xl, WITH1->yl, &x, &y);
  addbbpnt(&o->bb, x, y);
  mat_pop(&m);
}


/* O be an object of kind o_base */
void set_base_mbb(object *o, boolean recurse)
{
  object *op;

  if (o->kind != o_base) {
    printf("set_base_mbb: object kind<>o_base, = %s\n",
	   objkinds_NAMES[(long)o->kind]);
    return;
  }

  if (o->next == o) {  /* Totally empty object */
    o->bb.xl = 0;
    o->bb.yl = 0;
    o->bb.xh = 0;
    o->bb.yh = 0;
    return;
  }

  emptybb(&o->bb);
  op = o->next;
  while (op->kind != o_base) {
    if (op->kind == pr_inst)
      set_instance_mbb(op, recurse);
    addbb(&o->bb, &op->bb);
    op = op->next;
  }
}


/* Generate/update the MBB for a line */
void set_line_mbb(bbrec *bb, pnt_elem *p)
{
  emptybb(bb);
  while (p != NULL) {
    addbbpnt(bb, p->x, p->y);
    p = p->next;
  }
}


long primBytes(objkinds k)
{
  long Result;
  object *o;

  switch (k) {

  case pr_none:
  case pr_last:
    printf("getprim: illegal value=%s\n", primkinds_NAMES[(long)k]);
    _Escape(1);
    break;

  /* case combined due to no special sizeof operators for any of these types */
  case pr_dot:
  case pr_line:
  case pr_box:
  case pr_circle:
  case pr_ellipse:
  case pr_ngon:
  case pr_text:
  case pr_inst:
    Result = sizeof(object);
    break;
  }

  return Result;
}


object *getprim(objkinds k, long lx, long ly, long hx, long hy)
{
  object *o, *basep;

  o = Malloc(primBytes(k));

  basep = curFigure->guts->okind.i.contents;
  if (basep->kind != o_base)
    printf("get_prim: base.kind is not a o_base, = %s\n", objkinds_NAMES[(long)basep->kind]);

  /* insert in linked list */
  o->next = basep;
  o->prev = basep->prev;
  o->prev->next = o;
  basep->prev = o;
  newbb(&o->bb, lx, ly, hx, hy);
  o->color.value = curColor;
  o->color.priority = 0;
  o->kind = k;
  return o;
}


object *make_instance(object *cont, mat_matrix mat, boolean insert)
{
  object *o;
  pr_inst_rec *WITH1;

  if (insert)
    o = getprim(pr_inst, 0, 0, 0, 0);
  else {
    o = Malloc(primBytes(pr_inst));
    o->color.value = 0;
    o->color.priority = 0;
    o->kind = pr_inst;
    o->next = NULL;
    o->prev = NULL;
  }

  WITH1 = &o->okind.i;
  WITH1->contents = cont;
  if (cont->kind != o_base)
    printf("make_instance: cont^.kind not o_base, = %s\n", objkinds_NAMES[(long)cont->kind]);
  else
    cont->okind.base.refcount++;

  WITH1->m = mat;
  WITH1->matOnly = true;
  WITH1->closed = false;

  /* Get the BB from the object I am calling. */
  set_instance_mbb(o, false);
  return o;
}


object *make_dot(long ex, long ey)
{
  object *o;
  pr_dot_rec *WITH;

  o = getprim(pr_dot, ex - 1, ey - 1, ex + 1, ey + 1);
  WITH = &o->okind.d;
  WITH->x = ex;
  WITH->y = ey;
  return o;
}


pnt_elem *make_pnt_elem(long x, long y)
{
  pnt_elem *l;

  l = Malloc(sizeof(pnt_elem));
  l->x = x;
  l->y = y;
  l->next = NULL;
  return l;
}


/* The lowest level make_line */
object *make_line0(pnt_elem *p_p, short p_lwid, short p_wwid, short p_wlen,
		   boolean p_h1, boolean p_h2, boolean p_closed,
		   boolean p_curve)
{
  object *o;
  pr_line_rec *WITH;

  o = getprim(pr_line, 0, 0, 0, 0);
  WITH = &o->okind.l;
  set_line_mbb(&o->bb, p_p);
  WITH->pnts = p_p;
  WITH->h1 = p_h1;
  WITH->h2 = p_h2;
  WITH->lwid = p_lwid;
  WITH->wwid = p_wwid;
  WITH->wlen = p_wlen;
  WITH->curve = p_curve;
  WITH->closed = p_closed;
  return o;
}


/* Select the correct default/set value */
Static short default_(short wValue, short wDefault, short nValue, short nDefault, lineType lt)
{
  if (lt == l_nArrow) {
    if (nValue != 0)
      return nValue;
    else
      return nDefault;
  } 
  else {  /* if lt = l_wArrow then */
    if (wValue != 0)
      return wValue;
    else
      return wDefault;
  }
}


object *make_line(pnt_elem *p, lineType lt)
{
  object *Result;

  switch (lt) {

  case l_line:
    Result = make_line0(p, curLWid, 0, 0, false, false, false, false);
    break;

  case l_nArrow:
  case l_wArrow:
    Result = make_line0(p, default_(curLWidW, def_lwidW, 0, 0, lt),
	default_(curWWidW, def_wwidW, curWWidN, def_wwidN, lt),
	default_(curWLenW, def_wlenW, curWLenN, def_wlenN, lt), true,
	doubleArrows, false, false);
    break;

  case l_polygon:
    Result = make_line0(p, curLWid, 0, 0, false, false, true, false);
    break;

  case l_curve:
    Result = make_line0(p, curLWid, 0, 0, false, false, false, true);
    break;

  default:
    printf("Bad lineType in make_line.\n");
    break;
  }
  return Result;
}


object *make_box(long sx, long sy, long ex, long ey)
{
  object *o;
  pr_box_rec *WITH;

  o = getprim(pr_box, sx, sy, ex, ey);
  WITH = &o->okind.b;
  if (sx < ex) {
    WITH->x1 = sx;
    WITH->x2 = ex;
  } else {
    WITH->x1 = ex;
    WITH->x2 = sx;
  }
  if (sy < ey) {
    WITH->y1 = sy;
    WITH->y2 = ey;
  } else {
    WITH->y1 = ey;
    WITH->y2 = sy;
  }
  return o;
}


object *make_circle(long x, long y, long rad)
{
  object *o;
  pr_circle_rec *WITH;

  o = getprim(pr_circle, x - rad, y - rad, x + rad, y + rad);
  WITH = &o->okind.c;
  WITH->cx = x;
  WITH->cy = y;
  WITH->r = rad;
  return o;
}


object *make_ellipse(long x, long y, long a0, long b0, long start, long len,
		     long rot)
{
  object *o;
  pr_ellipse_rec *WITH;

  /* The bounding box on this is not quite right, but... */
  o = getprim(pr_ellipse, 0, 0, 0, 0);
  WITH = &o->okind.e;
  WITH->cx = x;
  WITH->cy = y;
  WITH->a = a0;
  WITH->b = b0;
  WITH->s = start;
  WITH->l = len;
  WITH->r = rot;
  WITH->pie = false;
  set_ellipse_mbb(o);
  return o;
}


object *make_text(long x0, long y0, Char *s)
{
  long xm, ym, xl, yl;
  object *o;
  pr_text_rec *WITH;

  /*gr_strlims(tmptext,xl,xm,yl,ym);*/
  xl = 0;
  xm = 50;
  yl = 0;
  ym = 10;

  o = getprim(pr_text, x0, y0, x0 + xm - xl, y0 + ym - yl);
  WITH = &o->okind.t;
  WITH->x = x0;
  WITH->y = y0;
  strcpy(WITH->words, s);
  strcpy(WITH->TeXwords, s);
  WITH->orig = curTextOrig;
  WITH->scale = curTextScale;
  WITH->rot = curTextRot;
  WITH->slant = curTextSlant;
  WITH->font = curTextFont;
  return o;
}


Static object *make_base(figure *fig)
{
  object *bp;
  base_obj *WITH1;

  bp = Malloc(sizeof(object));
  WITH1 = &bp->okind.base;
  bp->kind = o_base;
  bp->next = bp;   /* Make circular list */
  bp->prev = bp;
  WITH1->refcount = 0;
  WITH1->paths = NULL;
  WITH1->parent = fig;   /* Indicate parent */
  emptybb(&bp->bb);
  return bp;
}


Static boolean checkfile(fileSpec *fp, Char *n, figure **Result)
{
  figure *figP;
  boolean found = false;

  figP = fp->figures;
  while ((figP != NULL) && (!found)) {
    if (!strcmp(figP->name, n)) {
      *Result = figP;
      return true;
    }
    figP = figP->next;
  }

  return false;
}


/* Find the named figure in the list of files/figures */
figure *find_figure(Char *n)
{
  figure *Result;
  fileSpec *filP;

  /* First look in the current file */
  if (checkfile(curFile, n, &Result))
    return Result;

  /* Now check the other files */
  filP = files;
  while (filP != NULL) {
    if (filP != curFile)
      if (checkfile(filP, n, &Result))
        return Result;
    filP = filP->next;
  }

  printf("\007find_figure: Could not find \"%s\"\n", n);

  return NULL;
}


figure *make_figure(Char *n)
{
  figure *f;
  object *b;

  f = Malloc(sizeof(figure));
  curFigure = f;
  b = make_base(f);
  f->guts = make_instance(b, mat_ident_mat, false);
  today(f->edit_date);
  strcpy(f->mapFile, curFile->defMapFile);
  f->next = curFile->figures;
  curFile->figures = f;
  strcpy(f->name, n);
  f->changes = 0;
  f->active = false;
  f->thisfile = false;

  f->grid = 512;
  f->linewidth = 0;
  f->wing_length = 0;

  return f;
}


void finishFigure(figure *fig, short g, short lw, short wl, short c, short sd, short sw)
{
  if (g != 0)
    fig->grid = g;
  if (lw != 0)
    fig->linewidth = lw;
  if (wl != 0)
    fig->wing_length = wl;
  /*if c>0 then color:=c;*/
  today(fig->edit_date);
}


fileSpec *make_filespec(Char *fn, incore_status s)
{
  fileSpec *ac_file;

  ac_file = Malloc(sizeof(fileSpec));
  curFile = ac_file;
  strcpy(ac_file->fileName, fn);
  *ac_file->defMapFile = '\0';
  ac_file->status = s;
  ac_file->figures = NULL;
  ac_file->next = files;
  files = ac_file;
  return ac_file;
}
