/*
 $Id: macdriv.c,v 1.1.1.1 1996/11/04 12:05:46 roitzsch Exp $
 (C)opyright 1996 by Konrad-Zuse-Center, Berlin
 All rights reserved.
 Part of the common environment

$Log: macdriv.c,v $
Revision 1.1.1.1  1996/11/04 12:05:46  roitzsch
minigraph module

*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <limits.h>

#include	<Quickdraw.h>
#include	<ToolUtils.h>
#include	<Fonts.h>
#include	<Events.h>
#include    <Events.h>
#include	<Windows.h>
#include	<Dialogs.h>
#include	<Menus.h>
#include	<TextEdit.h>
#include	<Scrap.h>
#ifdef THINK_C
#include	<Palettes.h>
#include    <pascal.h>
#else
#include	<Palettes.h>
/* #include	<SysEqu.h> */
#endif
 
#include "minigraph.h"

#define K180PI 57.29578
#define CMTOPT 0.1
#define PTTOCM 10.0
/*
#define TRANSX(X) ((X)*(graph->xScal)+(graph->xTrans))
#define TRANSY(Y) (graph->wdHght-(Y)*(graph->yScal)-(graph->yTrans))
*/
#define TRANSX(X) ((X)*(graph->xScal)+(graph->xTrans))
#define TRANSY(Y) (-(Y)*(graph->yScal)-(graph->yTrans)+(graph->wdHght))

#define maxWindows 16
#define maxColors 64

static real real_min = SHRT_MIN, real_max = SHRT_MAX;

static char *fontName ="courier";
static char *captionName ="MiniGraphic";
static real fontSize[3] = {10.0, 12.0, 14.0};
static real lineWidth[3] = {1.0, 2.0, 3.0};
#define MAXMACMARKERS 7
static char macMarkers[MAXMACMARKERS] =
  { ' ', '*', 'x', '+', '¥', 'Æ', '×' };
static int dyMarker[MAXMACMARKERS] =
  { 0, 5, 3, 3, 3, 3, 4 };
static int *rVals=nil, *gVals=nil, *bVals=nil;

static WindowRecord		wRecords[maxWindows];
static WindowPtr		myWindows[maxWindows];
static Rect				screenRect;

static int MacOpenPort(GRAPHIC *graph)
  {
	int no = graph->wdNo, size;
	short font;
	int top = graph->wdOrgY-graph->wdHght, left = graph->wdOrgX,
		height = graph->wdHght, width = graph->wdWdth;
  	PaletteHandle ph;
	RGBColor newColor;
	int k;

	if (graph->ready) return true;

	if ((graph->wdOrgX)==-1.0)
	  {
	    graph->wdWdth = (graph->right-graph->left)*0.5;
		graph->wdHght = (graph->bottom-graph->top)*0.5-16.0;
		switch (no)
		{
		  case 0:
		    graph->wdOrgX = (graph->right)*0.5;
		    graph->wdOrgY = (graph->bottom-graph->top)*0.5+20;
			break;
		  case 1:
		    graph->wdOrgX = graph->left;
		    graph->wdOrgY = (graph->bottom-graph->top)*0.5+20;
			break;
		  case 2:
		    graph->wdOrgX = graph->left;
		    graph->wdOrgY = graph->bottom;
			break;
		  case 3:
		    graph->wdOrgX = (graph->right)*0.5;
		    graph->wdOrgY = graph->bottom;
			break;
		}
	  }

	top = graph->wdOrgY-graph->wdHght;
	left = graph->wdOrgX;
	height = graph->wdHght;
	width = graph->wdWdth;

	myWindows[no] = GetNewCWindow(501, (Ptr)&wRecords[no],
	                                (WindowPtr) -1);
	if (myWindows[no]==nil)
	  {
	    fprintf(miniErrorFile,"MacOpenPort failed\n");
		return false;
	  }
	MoveWindow(myWindows[no], left, top, false);
	SizeWindow(myWindows[no], width, height, false),
#ifdef THINK_C
	SetWTitle(myWindows[no], CtoPstr(graph->caption));
	PtoCstr((unsigned char*)graph->caption);
#else
	setwtitle(myWindows[no], graph->caption);
#endif
	SetPort(myWindows[no]);

	ph = GetPalette(myWindows[no]);
	for (k=0; k<maxColors; k++)
	  {
		if (rVals[k]==-1) continue;
		newColor.red = 256*rVals[k];
		newColor.green = 256*gVals[k];
		newColor.blue = 256*bVals[k];
		SetEntryColor(ph, k+32, &newColor);
/*		rVals[k] = gVals[k] = bVals[k] = -1; */
	  }
	ShowWindow(myWindows[no]);
	ClipRect(&(myWindows[no]->portRect));
	PmBackColor(graph->backgrCol);
	EraseRect(&(myWindows[no]->portRect));

#ifdef THINK_C
    GetFNum(CtoPstr(graph->fontName), &font);
    PtoCstr((unsigned char*)graph->fontName);
#else
	getfnum(graph->fontName, &font);
#endif
	TextFont(font);
	size = graph->drFntSz;
	TextSize(size);
	size = graph->drPenSz;
	PenSize(size, size);

	graph->ready = true;
	return true;
  }

static int MacNewPict(GRAPHIC *graph)
  {
	int ind = graph->wdNo;

	if (!(graph->ready)) return false;
	SetPort(myWindows[ind]);
	ClipRect(&(myWindows[ind]->portRect));
	PmBackColor(graph->backgrCol);
	EraseRect(&(myWindows[ind]->portRect));

	return true;
  }
/*
static int MacShow(graph)
GRAPHIC *graph;
  {
	int ind = graph->wdNo;
	EventRecord myEvent;

	if (!(graph->ready)) return false;
	myEvent.what = 0;

	SetPort(myWindows[ind]);
	while (true)
	  {
	    GetNextEvent(everyEvent,&myEvent);
		if (myEvent.what==mouseDown) break;
	  }
	return true;
  }
*/
static int MacClose(GRAPHIC *graph)
  {
    int ind = graph->wdNo;

	if (!(graph->ready)) return false;
	CloseWindow(myWindows[ind]);
	myWindows[ind] = nil;
	graph->wdNo = -1;

	SetPort(FrontWindow());
	SetCursor(&(qd.arrow));

	return true;
  }

static int MacPLine(GRAPHIC *graph, void *xAdr, void *yAdr, int n)
  {
    int k, px, py, size;
	real x, y, xt, yt;

	SetPort(myWindows[graph->wdNo]);
	PmForeColor(graph->penCol);
	size = graph->drPenSz;
	PenSize(size, size);
	if ((graph->prec)==SINGLE)
	  { x = ((float*)xAdr)[0]; y = ((float*)yAdr)[0]; }
	else
	  { x = ((double*)xAdr)[0]; y = ((double*)yAdr)[0]; }
    xt = TRANSX(x); yt = TRANSY(y);
    if ((xt<real_min)||(xt>real_max)||
        (yt<real_min)||(yt>real_max)) return true;
    px = xt; py = yt;
	MoveTo(px, py);

	for (k=1; k<n; k++)
	  {
	    if ((graph->prec)==SINGLE)
		  { x = ((float*)xAdr)[k]; y = ((float*)yAdr)[k]; }
		else
		  { x = ((double*)xAdr)[k]; y = ((double*)yAdr)[k]; }
	    xt = TRANSX(x); yt = TRANSY(y);
	    if ((xt<real_min)||(xt>real_max)||
	        (yt<real_min)||(yt>real_max)) return true;
	    px = xt; py = yt;
		LineTo(px, py);
	  }
    return true;
  }

static int MacPMarker(GRAPHIC *graph, void *xAdr, void *yAdr, int n)
  {
    int k, px, py, size;
	real x, y, xt, yt;
	char s[2];

	SetPort(myWindows[graph->wdNo]);
	PmForeColor(graph->mrkCol);
	size = fontSize[MEDIUM];
	TextSize(size);
#ifdef THINK_C
	s[0] = 1; s[1] = macMarkers[graph->mark];
#else
	s[0] = macMarkers[graph->mark]; s[1] = '\0';
#endif
	for (k=0; k<n; k++)
	  {
	    if ((graph->prec)==SINGLE)
		  { x = ((float*)xAdr)[k]; y = ((float*)yAdr)[k]; }
		else
		  { x = ((double*)xAdr)[k]; y = ((double*)yAdr)[k]; }
	    xt = TRANSX(x); yt = TRANSY(y);
	    if ((xt<real_min)||(xt>real_max)||
	        (yt<real_min)||(yt>real_max)) return true;
	    px = xt-2; py = yt+dyMarker[graph->mark];
	    MoveTo(px, py);
#ifdef THINK_C
        DrawString((unsigned char*)s);
#else
	    drawstring(s);
#endif
	  }
	size = graph->drFntSz;
	TextSize(size);
    return true;
  }
 
#ifdef __cplusplus
static int MacString(GRAPHIC *graph, real x,real y, const char *s)
#else
static int MacString(GRAPHIC *graph, real x,real y, char *s)
#endif
  {
	int px, py, size;
	int xt = TRANSX(x), yt = TRANSY(y);

    if ((xt<real_min)||(xt>real_max)||
        (yt<real_min)||(yt>real_max)) return true;
	SetPort(myWindows[graph->wdNo]);
	PmForeColor(graph->fntCol);
	size = graph->drFntSz;
	TextSize(size);
	px = xt; py = yt;
    MoveTo(px, py);
#ifdef THINK_C
    DrawString(CtoPstr(s));
    PtoCstr((unsigned char*)s);
#else
    drawstring(s);
#endif
    return true;
  }
 
static int MacFill(GRAPHIC *graph, void *xAdr, void *yAdr, int n)
  {
    int k, px, py, px0, py0;
	real x, y, xt, yt;
	PolyHandle Tr;

	SetPort(myWindows[graph->wdNo]);
	PmForeColor(graph->fllCol);
	if ((graph->prec)==SINGLE)
	  { x = ((float*)xAdr)[0]; y = ((float*)yAdr)[0]; }
	else
	  { x = ((double*)xAdr)[0]; y = ((double*)yAdr)[0]; }
    xt = TRANSX(x); yt = TRANSY(y);
    if ((xt<real_min)||(xt>real_max)||
        (yt<real_min)||(yt>real_max)) return true;
    px0 = xt; py0 = yt;
	Tr = OpenPoly();
	MoveTo(px0, py0);

	for (k=1; k<n; k++)
	  {
	    if ((graph->prec)==SINGLE)
		  { x = ((float*)xAdr)[k]; y = ((float*)yAdr)[k]; }
		else
		  { x = ((double*)xAdr)[k]; y = ((double*)yAdr)[k]; }
	    xt = TRANSX(x); yt = TRANSY(y);
	    if ((xt<real_min)||(xt>real_max)||
	        (yt<real_min)||(yt>real_max))
	      { KillPoly(Tr); return true; }
	    px = xt; py = yt;
		LineTo(px, py);
	  }
	LineTo(px0, py0);
    ClosePoly();

    PaintPoly(Tr);
	KillPoly(Tr);
    return true;
  }
    
static int MacSettings(GRAPHIC *graph, int type, void *valAdr)
  {
    int iVal, size;

	switch (type)
	{
    case WDORGX :
      iVal = *((int*)valAdr);
      if ((iVal >= 0) && (iVal <= graph->right))
    	graph->wdOrgX = iVal;
      else
      	fprintf(miniErrorFile,"MacSettings :  wrong value for WDORGX  %d\n", iVal);
      break;
    case WDORGY :
	  iVal = *((int*)valAdr);
      if ((iVal >= 0) && (iVal <= graph->bottom))
    	graph->wdOrgY = iVal;
      else
      	fprintf(miniErrorFile,"MacSettings :  wrong value for WDORGY  %d\n", iVal);
      break;
    case WDWDTH :
	  iVal = *((int*)valAdr);
      if ((iVal >= 0) && (iVal + graph->wdOrgX <= graph->right))
    	graph->wdWdth = iVal;
      else
      	fprintf(miniErrorFile,"MacSettings :  wrong value for WDWDTH  %d\n", iVal);
      break;
    case WDHGHT :
	  iVal = *((int*)valAdr);
      if ((iVal >= 0) && (iVal <= graph->wdOrgY))
    	graph->wdHght = iVal;
      else
      	fprintf(miniErrorFile,"MacSettings :  wrong value for WDHGHT  %d\n", iVal);
      break;
	case PENSIZE:
	  iVal = *((int*)valAdr);
	  switch (iVal)
	    {	
			case SMALL  : graph->drPenSz = lineWidth[SMALL];  break;
		  	case MEDIUM : graph->drPenSz = lineWidth[MEDIUM]; break;
		    case BIG	: graph->drPenSz = lineWidth[BIG];    break;
		    default		: graph->drPenSz = iVal*graph->xScal;
		}
	  break;
	case FONTSIZE:
	  iVal = *((int*)valAdr);
	  switch (iVal)
	    {
			case SMALL  : graph->drFntSz = fontSize[SMALL];  break;
		  	case MEDIUM : graph->drFntSz = fontSize[MEDIUM]; break;
		    case BIG    : graph->drFntSz = fontSize[BIG];    break;
			default		: graph->drFntSz = iVal*graph->xScal;
		}
	  break;
	case MARKER:
	  iVal = *((int*)valAdr);
	  if ((iVal>=0)&&(iVal<MAXMACMARKERS))
	    graph->mark = iVal;
	  else
	    fprintf(miniErrorFile,"MacSettings: unkown marker %d\n", iVal);
	  break;
	case FILLCOL:
	  iVal = *((int*)valAdr);
	  graph->fllCol = iVal;
	  break;
	case MARKCOL:
	  iVal = *((int*)valAdr);
	  graph->mrkCol = iVal;
	  break;
	case FONTCOL:
	  iVal = *((int*)valAdr);
	  graph->fntCol = iVal;
	  break;
	case PENCOL:
	  iVal = *((int*)valAdr);
	  graph->penCol = iVal;
	  break;
	case BACKGRCOL:
	  iVal = *((int*)valAdr);
	  graph->backgrCol = iVal;
	  break;
	case CAPTION:
	  size = strlen((char*)valAdr);
	  graph->caption = (char*)malloc(size+1);
	  strncpy(graph->caption, (char*)valAdr, size+1);
	  if (graph->ready)
	    {
		  SetPort(myWindows[graph->wdNo]);
#ifdef THINK_C
          SetWTitle(myWindows[graph->wdNo], CtoPstr(graph->caption));
          PtoCstr((unsigned char*)graph->caption);
#else
          setwtitle(myWindows[graph->wdNo], graph->caption);
#endif
		}
	  break;
	default:
	  fprintf(miniErrorFile,"MacSettings: unkown type %d\n", type);
	  break;
	}
    return true;
  }

static int MacWait(GRAPHIC  *graph, int *typAdr, int  *buttonAdr,
                   void *xkoordAdr, void *ykoordAdr, int *chAdr)
  { 
	int ind = graph->wdNo, waitLoop = true, whichPart;
	float x, y;
	EventRecord myEvent;
	WindowPtr clickedWindow;

	if (!(graph->ready)) return false;
	myEvent.what = 0;

	*typAdr = *buttonAdr = *chAdr = 0;
	if (graph->prec == SINGLE)
	  *((float*)xkoordAdr) = *((float*)ykoordAdr) = 0.0;
	else
	  *((double*)xkoordAdr) = *((double*)ykoordAdr) = 0.0;

	SetPort(myWindows[ind]);
	while (waitLoop)
	{
	  GetNextEvent(everyEvent,&myEvent);
	  switch (myEvent.what)
	  {
		case mouseDown:
		  whichPart = FindWindow(myEvent.where,&clickedWindow);
		  if (clickedWindow!=myWindows[ind]) break;
		  GlobalToLocal(&(myEvent.where));
		  x = (myEvent.where).h;
		  y = (myEvent.where).v;
	      if (graph->prec == SINGLE)
	        {
	          *((float*)xkoordAdr) = (x-graph->xTrans)/graph->xScal;
	          *((float*)ykoordAdr) = (graph->wdHght-y-graph->yTrans)/graph->yScal;
	        }
	      else
	        {
	          *((double*)xkoordAdr) = (x-graph->xTrans)/graph->xScal;
	          *((double*)ykoordAdr) = (graph->wdHght-y-graph->yTrans)/graph->yScal;
	        }
		  *typAdr |= 8;
		  *buttonAdr = 1;
		  waitLoop=false;
		  break;
		case keyDown:
		  *chAdr = BitAnd(myEvent.message,charCodeMask);
		  *typAdr |= 4;
		  if (BitAnd(myEvent.modifiers,shiftKey)) *typAdr |= 2;
		  if (BitAnd(myEvent.modifiers,controlKey)) *typAdr |= 1;
		  waitLoop=false;
		  break;
	  }
	}
	return true;
  }

static int MacGin (GRAPHIC *graph, int geo, void *x1koordAdr, void *y1koordAdr,
					void *x2koordAdr, void *y2koordAdr)
  { 
static int first = true;
if (first)
  {
    first = false;
	fprintf(miniErrorFile,"zibevent not yet implemented\n");
  }
	switch (geo)
	{
	  case LINE:
	    break;
	  case RECTANGLE:
	    break;
	  default:
	    fprintf(miniErrorFile,"%d as geo for zibgin not implemented\n",geo);
	    break;
	}
	return true;
  }

static int MacEvent (GRAPHIC *graph, int *typAdr, int *buttonAdr,
					void *xkoordAdr, void *ykoordAdr, int *charAdr)
  { 
static int first = true;
if (first)
  {
    first = false;
	fprintf(miniErrorFile,"zibevent not yet implemented\n");
  }
	return true;
  }

static int MacWindow(GRAPHIC *graph)
  {
	int  no = graph->wdNo;
    return true; 
  }

static int MacColor(int col_no, int rVal, int gVal, int bVal)
  {
	col_no -= 32;
	if ((col_no<0)||(col_no>=maxColors)) return false;
	rVals[col_no] = rVal;
	gVals[col_no] = gVal;
	bVals[col_no] = bVal;
  	return true;
  }
 
int MacInit(GRAPHIC *graph)
  {
	int i, k, free;
	static int first = true;
BitMap screenBits;
GrafPtr thePort;

	if (first)
	  {
		for (k=0; k<maxWindows; k++) myWindows[k]=nil;

		InitGraf(&qd.thePort);
		InitFonts();
		FlushEvents(everyEvent, 0);
		InitWindows();
		screenRect = qd.screenBits.bounds;
		first = false;
		screenBits = qd.screenBits;
		thePort = qd.thePort;

		rVals = (int*)malloc(maxColors*sizeof(int));
		gVals = (int*)malloc(maxColors*sizeof(int));
		bVals = (int*)malloc(maxColors*sizeof(int));
		if (bVals==nil) return false;
		for (k=0; k<maxColors; k++)
		  rVals[k] = gVals[k] = bVals[k] = -1;
	  }

	for (free=0; free<maxWindows; free++)
	  if (myWindows[free]==nil) break;
	if (free==maxWindows)
	  { fprintf(miniErrorFile,"More than %d windows\n",graph->maxWd); return false; }
	myWindows[free] = (WindowPtr)(-1);

	graph->PLine = MacPLine;
    graph->PMarker = MacPMarker;
    graph->Text = MacString;
    graph->Fill = MacFill;
    graph->Color = MacColor;
    graph->Settings = MacSettings;
    graph->NewPict = MacNewPict;
    graph->OpenPort = MacOpenPort;
    graph->Close = MacClose;
    graph->Wait = MacWait; 
    graph->Gin = MacGin; 
    graph->Event = MacEvent; 
/*    graph->Window = MacWindow; */

    graph->bottom = screenRect.bottom;
    graph->left = screenRect.left;
    graph->top = screenRect.top+20.0;
    graph->right = screenRect.right;
    graph->wdOrgX = -1.0;
    graph->wdOrgY = -1.0;
    graph->wdWdth = -1.0;
    graph->wdHght = -1.0;

    graph->drRes = 1.0;
	graph->drPenSz = lineWidth[SMALL]; 
	graph->drFntSz = fontSize[MEDIUM];
    graph->drXcm = CMTOPT;
    graph->drYcm = CMTOPT;

	graph->penCol = WHITE;
	graph->fntCol = WHITE;
	graph->mrkCol = WHITE;
	graph->backgrCol = BLACK;

/*    graph->fillP = true; */
/*    graph->clipP = true; */
    graph->maxCol = maxColors;
    graph->maxGry = 24;
	graph->maxWd = 4;
	graph->mark = STAR;
	graph->prec = SINGLE;
	graph->line_count = 0;
	graph->id = MAC;
	graph->wdNo = free;
	graph->fontName = fontName;
	graph->fileName = nil;
	graph->caption = captionName;
    graph->file = nil;
    for (i = 0; i < 16; i++)
       graph->Ass[i] = nil;

	return true;
  }
