/*
 $Id: plot.cc,v 1.4 1996/10/08 08:17:41 roitzsch Exp $
 (C)opyright 1996 by Konrad-Zuse-Center, Berlin
 All rights reserved.
 Part of the Kaskade distribution
*/

#include "plot.h"
#include "drivers.h"
#include "minigraph.h"


FILE* miniErrorFile = stdout;   // Null;


// inline static float  sign(float  x) { return (x<0)? -1.0 : 1.0; }
inline static double sign(double x) { return (x<0)? -1.0 : 1.0; }
// inline static int    sign(int    x) { return (x<0)? -1 : 1; }


//-------------------------------------------------------------------------


Plot:: Plot (int type, float size, char* caption) 
{ 
    miniErrorFile = stdout; 

    switch (type)
    {
      case PS      :    
      case PS_QUER :  driver = new PSDriver; break;
      case X11     :  driver = new XDriver;  break;

      default: printf("\n*** Plot: driver type %1d not implemented\n", type); 
	cout.flush(); abort();
    }

    graph = new GRAPHIC(type, size);
    driver->Init(graph, size);

    if (caption) set(CAPTION,caption);
}
//-------------------------------------------------------------------------

Plot:: ~Plot()
{
    driver->Close(graph);
    delete graph;
    delete driver;
}
//-------------------------------------------------------------------------



int Plot:: line(double* x, double* y, int n)
{
    if ((n < 0) || (n > MAX_POINTS))
    {
	fprintf(miniErrorFile,
	    "MiniGraphic - line :  n = %d not allowed as array length !\n", n);
	return False;
    }
    
    if (graph->newScal)  if (!graph->ComputeScaling(*driver)) return False;

    if (!driver->PLine(graph, x, y, n)) return False;
    return True;
}
//-------------------------------------------------------------------------

int Plot:: line(float* x, float* y, int n)
{
    if ((n < 0) || (n > MAX_POINTS))
    {
	fprintf(miniErrorFile,
	    "MiniGraphic - line :  n = %d not allowed as array length !\n", n);
	return False;
    }
    
    if (graph->newScal)  if (!graph->ComputeScaling(*driver)) return False;

    if (!driver->PLine(graph, x, y, n))  return False;
    return True;
}
//-------------------------------------------------------------------------

int Plot:: marker(double* x, double* y, int n)
{
    if ((n < 0) || (n > MAX_POINTS))
    {
	fprintf(miniErrorFile,
	    "MiniGraphic - marker: n = %d not allowed as array length !\n", n);
	return False;
    }

    if (graph->newScal) if (!graph->ComputeScaling(*driver)) return False;

    if (!driver->PMarker(graph, x, y, n)) return False;
    return True;
}
//-------------------------------------------------------------------------

int Plot:: marker(float* x, float* y, int n)
{
    if ((n < 0) || (n > MAX_POINTS))
    {
	fprintf(miniErrorFile,
	    "MiniGraphic - marker: n = %d not allowed as array length !\n", n);
	return False;
    }

    if (graph->newScal) if (!graph->ComputeScaling(*driver)) return False;

    if (!driver->PMarker(graph, x, y, n)) return False;
    return True;
}
//-------------------------------------------------------------------------

int Plot:: fill(double* x, double* y, int n)
{
    if ((n < 0) || (n > MAX_POINTS))
    {
	fprintf(miniErrorFile,
		"MiniGraphic - fill: n = %d not allowed as array length !\n", n);
	return False;
    }
     
    if (graph->newScal) if (!graph->ComputeScaling(*driver))  return False;
    if (!driver->Fill(graph, x, y, n))  return False;
    return True;
}
//-------------------------------------------------------------------------

int Plot:: fill(float* x, float* y, int n)
{
    if ((n < 0) || (n > MAX_POINTS))
    {
	fprintf(miniErrorFile,
		"MiniGraphic - fill: n = %d not allowed as array length !\n", n);
	return False;
    }
     
    if (graph->newScal) if (!graph->ComputeScaling(*driver))  return False;
    if (!driver->Fill(graph, x, y, n))  return False;
    return True;
}
//-------------------------------------------------------------------------

int Plot::text(double x, double y, char* text0)
{
    if (strlen(text0) > MAXTEXT)
    {
	fprintf(miniErrorFile,
	   "MiniGraphic - text :  Text too long, n = %d !\n", strlen(text0));
	return False;
    }
      
    if (graph->newScal) if (!graph->ComputeScaling(*driver)) return False;

    char* text1 = new char[strlen(text0)+1];
    strcpy (text1, text0);
    if (!driver->Text(graph, x, y, text1)) return False;

    delete text1;
    return True;
}
//-------------------------------------------------------------------------


int Plot::color(int col_no, int rVal, int gVal, int bVal)
{
    if ((col_no < 32) || (col_no > 95))
    {
	fprintf(miniErrorFile,
		"MiniGraphic - color :  COLNO = %d  not allowed as ", col_no);
	fprintf(miniErrorFile,"colornumber ! (32..95)\n");
	return False;
    }
    if ((rVal < 0) || (rVal > 255))
    {
        fprintf(miniErrorFile,
		"MiniGraphic - color: RVAL = %d not in range ! (0..255)\n",rVal);
	return False;
    }
    if ((gVal < 0) || (gVal > 255))
    {
        fprintf(miniErrorFile,
	   "MiniGraphic - color :  GVAL = %d  not in range ! (0..255)\n", gVal);
	return False;
    }
    if ((bVal < 0) || (bVal > 255))
    {
        fprintf(miniErrorFile,
	    "MiniGraphic - color :  BVAL = %d  not in range ! (0..255)\n",bVal);
	return False;
    }

    if (!driver->Color(col_no, rVal, gVal, bVal)) return False;

    return True;
}
//-------------------------------------------------------------------------


int Plot::set(int type, int iVal)
{
    switch(type)
    {

      case SCALFIT :  

      if ((iVal == 0) || (iVal == 1))  graph->scalFit = iVal;
      else
      {
	  fprintf(miniErrorFile,"MiniGraphic - set :  ");
	  fprintf(miniErrorFile,"SCALFIT = %d ", iVal);
	  fprintf(miniErrorFile,"not allowed, only 0 or 1 !\n");
      }
      graph->newScal = True;
      break;
      
      default :  if (!driver->Settings(graph, type, iVal))  return False;
  }
    return True;
}
//-------------------------------------------------------------------------


int Plot::set(int type, double rVal)
{

    switch (type)
    {
	
      case MINX :        
        graph->minX    = rVal;
	graph->slMinX  = rVal;
	graph->newScal = True;
	break;
	
    case MINY :      
        graph->minY    = rVal;
	graph->slMinY  = rVal;
	graph->newScal = True;
	break;
	
    case MAXX :      graph->maxX = rVal;
	graph->slMaxX = rVal;
	graph->newScal = True;
	break;
	
    case MAXY :      graph->maxY = rVal;
	graph->slMaxY = rVal;
	graph->newScal = True;
	break;
      
	default :  fprintf(miniErrorFile,
			   "MiniGraphic - set :  unkown type %d !\n", type);
	return False;
    }
    return True;
}
//-------------------------------------------------------------------------

int Plot:: set(int type, char* str)
{
    switch (type)
    {
      case CAPTION :
      case FILENAME :
      default :  if (!driver->Settings(graph, type, str))  return False;
            
      return True;
    }
}
//-------------------------------------------------------------------------

int Plot:: request (int type, int* val)
{
    switch (type)
    {
      case WDORGX :  *val = graph->wdOrgX;  	return True;
      case WDORGY :  *val = graph->wdOrgY;  	return True;
      case WDWDTH:   *val = graph->wdWdth;  	return True;
      case WDHGHT :  *val = graph->wdHght;  	return True;
      case PENSIZE : *val = graph->drPenSz; 	return True;
      case LINESTYLE :  *val = graph->linestyle;return True;
      case FONTSIZE :  *val = graph->drFntSz;	return True;
      case FONTPROP :  *val = graph->FntProp;	return True;
      case MARKER :  *val = graph->mark;	return True;
      case MAXWD :  *val = graph->maxWd;	return True;
      case MAXCOL :  *val = graph->maxCol;	return True;
      case MAXGRY :  *val = graph->maxGry;	return True;
      case PREC :  *val = graph->prec;		return True;
      case PENCOL :  *val = graph->penCol;	return True;
      case FONTCOL :  *val = graph->fntCol;	return True;
      case MARKCOL :  *val = graph->mrkCol;	return True;
      case FILLCOL :  *val = graph->fllCol;	return True;
      case BACKGRCOL :  *val = graph->backgrCol;return True;
      case SCALFIT :  *val = graph->scalFit;	return True;
	// case BUFFER :  *val = graph->buffer;	return True;
	default :  fprintf(miniErrorFile,
			   "MiniGraphic - request :  Request for "); 
	fprintf(miniErrorFile, "unknown type %d !\n", type);
	return False;
    }
//    return True;
}
//-------------------------------------------------------------------------


int Plot:: request(int type, double* rVal)
{

    switch (type)
    {
      case MINX :  *rVal = graph->minX;		break;
      case MINY :  *rVal = graph->minY;		break;
      case MAXX :  *rVal = graph->maxX;		break;
      case MAXY :  *rVal = graph->maxY;		break;
      case SLMINX: *rVal = graph->slMinX;	break;
      case SLMINY: *rVal = graph->slMinY;	break;
      case SLMAXX: *rVal = graph->slMaxX;	break;
      case SLMAXY: *rVal = graph->slMaxY;	break;
      case TOP :   *rVal = graph->top;		break;
      case LEFT :  *rVal = graph->left;		break;
      case BOTTOM : *rVal = graph->bottom;	break;
      case RIGHT :  *rVal = graph->right;	break;
      case XRESOL : *rVal = graph->xRes;	break;
      case YRESOL : *rVal = graph->yRes;	break;
      case TGXCM :  *rVal = graph->drXcm;	break;
      case TGYCM :  *rVal = graph->drYcm;	break;
      case USXTG :  *rVal = graph->uXdr;	break;
      case USYTG :  *rVal = graph->uYdr;	break;
	default :  fprintf(miniErrorFile,
			   "MiniGraphic - request :  Request for "); 
	fprintf(miniErrorFile,"unknown type %d !\n", type);
	return False;
    }
    return True;
}
//-------------------------------------------------------------------------


int Plot:: request(int type, char* cp)
{
    switch (type)
    {
      case CAPTION :  cp = graph->caption;	return True;
      case FILENAME :  cp = graph->fileName;	return True;
	default :  fprintf(miniErrorFile,
			   "MiniGraphic - request :  Request for "); 
	fprintf(miniErrorFile,"unknown type %d !\n", type);
	return False;
    }
//    return True;
}
//-------------------------------------------------------------------------

int Plot::clear()
{
    return driver->NewPict(graph);
}


/*
int Plot::gin(int geo, void* x1koordAdr, 
	   		void* y1koordAdr, void* x2koordAdr, void* y2koordAdr)
{
    *(float*)x1koordAdr = *(float*)y1koordAdr =
    *(float*)x2koordAdr = *(float*)y2koordAdr = 0;

   if (geo < 1 || geo > 3)
      {
         fprintf(miniErrorFile,"MiniGraphic - zibgeo :  geo = %d not allowed !\n", geo);
         return False;
      }

    if (graph->newScal)  if (!graph->ComputeScaling(*driver))  return False;

    return driver->Gin(graph, geo, x1koordAdr, y1koordAdr,
		       x2koordAdr, y2koordAdr);
}
//-------------------------------------------------------------------------
 
  
int Plot::event(int* typAdr,  int* buttonAdr, 
		void* xkoordAdr, void* ykoordAdr, int* chAdr)
{
    if (graph->newScal) if (!graph->ComputeScaling(*driver))  return False;
    return driver->Event(graph, typAdr, buttonAdr,
			 xkoordAdr, ykoordAdr, chAdr);
}
//-------------------------------------------------------------------------

  
int Plot:: wait(int* typAdr,  int* buttonAdr, 
	       void* xkoordAdr, void* ykoordAdr, int* chAdr)
{
    if (graph->newScal)  graph->ComputeScaling(*driver);
    return driver->Wait(graph, typAdr, buttonAdr,
			xkoordAdr, ykoordAdr, chAdr);
}
//-------------------------------------------------------------------------
*/

int Plot:: string(char* stringAdr, int* lengthAdr)
{
    if (graph->newScal)  graph->ComputeScaling(*driver);
    if (!driver->String(graph, stringAdr, lengthAdr)) return False;

    return True;
}
//-------------------------------------------------------------------------

void Plot:: flush()
{
    driver->FlushDisplay();
}
//-------------------------------------------------------------------------

/*--------------------------  class  GRAPHIC  --------------------------*/


int GRAPHIC:: ComputeScaling(Driver& driver)
{

    xreal width, height,
          xmin, xmax, ymin, ymax, dx, dy, xscal, yscal, xtrans=0, ytrans=0;

    if (!ready)  driver.OpenPort(this);

    width  = wdWdth;
    height = wdHght;
    
    xmin = slMinX;
    xmax = slMaxX;
    ymin = slMinY;
    ymax = slMaxY;
    dx = xmax-xmin;
    dy = ymax-ymin;

    xscal = width/dx;
    yscal = height/dy;
   
    switch (scalFit)
    {
      case 0:
	xtrans = -xmin*xscal;
	ytrans = -ymin*yscal;
	break;

      case 1:
	if (fabs(xscal)>fabs(yscal))
	{
	    xscal = sign(xscal)*fabs(yscal);
	    xtrans = (width-dx*xscal)*0.5-xmin*xscal;
	    ytrans = -ymin*yscal;
	}
	else
	{
	    yscal = sign(yscal)*fabs(xscal);
	    xtrans = -xmin*xscal;
	    ytrans = (height-dy*yscal)*0.5-ymin*yscal;
	}
	break;

      case 2:
	if (fabs(xscal)>fabs(yscal))
	{
	    xscal = sign(xscal)*fabs(yscal);
	    xtrans = -xmin*xscal;
	    ytrans = -ymin*yscal;
	}
	else
	{
	    yscal = sign(yscal)*fabs(xscal);
	    xtrans = -xmin*xscal;
	    ytrans = -ymin*yscal;
	}
	break;

      default:
	fprintf(miniErrorFile,"MiniGraphic : Unknown scaling rule %d\n",scalFit);
	break;
    }
    /*
      fprintf(miniErrorFile,
      "xscal=%e, yscal=%e, xtrans=%e, ytrans=%e\n",xscal,yscal,xtrans,ytrans);
      */

    xScal = xscal;
    yScal = yscal;
    xTrans = xtrans;
    yTrans = ytrans;
    uXdr = fabs(xscal);
    uYdr = fabs(yscal);
    uXcm = (drXcm)/xscal;
    uYcm = (drYcm)/yscal;
    uRes = (drRes)/xscal;
    uPenSz = (drPenSz)/xscal;
    uFntSz = (drFntSz)/xscal;
    xRes = fabs(1/xscal);
    yRes = fabs(1/yscal);
    
    newScal = False;
    return True;
}
//-------------------------------------------------------------------------


int GRAPHIC:: PrintGraph()
{
    fprintf(miniErrorFile,
	 "U: (%8.3g,%8.3g,%8.3g,%8.3g)-(%8.3g,%8.3g,%8.3g,%8.3g)\n",
			minX, minY, maxX, maxY,
			slMinX, slMinY,
			slMaxX, slMaxY);
    fprintf(miniErrorFile,
	    "D: (%8.3g,%8.3g,%8.3g,%8.3g)-(%8.3d,%8.3d),(%8.3d,%8.3d)\n",
	    left, bottom, right, top, wdOrgX,wdOrgY, wdWdth,wdHght);
	fprintf(miniErrorFile,"1cm = (%8.3g,%8.3g)u, (%8.3g,%8.3g)d\n",
			uXcm, uYcm, drXcm, drYcm);
	fprintf(miniErrorFile,"Resolution = %8.3gu, %8.3g\n", uRes, drRes);
	fprintf(miniErrorFile,"Pensize    = %8.3gu, %8.3d\n", uPenSz, drPenSz);
	fprintf(miniErrorFile,"Fontsize   = %8.3gu, %8.3d\n", uFntSz, drFntSz);
	fprintf(miniErrorFile,"id=%d, wdNo=%d %s, prec=%s precission\n",
		id, wdNo, (ready)?"is ready":"is not ready",
		(prec==SINGLE)?"Single":"Double");
	if ((caption)!=0)
	  fprintf(miniErrorFile,"Caption = '%s'\n", caption);
	if ((fontName)!=0)
	  fprintf(miniErrorFile,"Font = '%s'\n", fontName);
	if ((fileName)!=0)
	  fprintf(miniErrorFile,"File = '%s'\n", fileName);
	fprintf(miniErrorFile,"Scaling:(%e,%e), Translating:(%e,%e)\n",
			xScal, yScal,
			xTrans, yTrans);
	return True;
}
//-------------------------------------------------------------------------


GRAPHIC:: GRAPHIC(int type, float /*size*/) 
{ 
    id   = type;

    minX = 0.0;
    minY = 0.0;
    maxX = 1.0;
    maxY = 1.0;
    slMinX = 0.0;
    slMinY = 0.0;
    slMaxX = 1.0;
    slMaxY = 1.0;
    ready = False;
    newScal = True;
    scalFit = 1;
    line_count = 0;
    page_count = 1;
    wdNo = 0;

    caption  = 0; 
    fileName = 0; 
    fontName = 0;
    file     = 0;
}
//-------------------------------------------------------------------------

GRAPHIC:: ~GRAPHIC() 
{ 
    if (caption)  delete caption; 
    if (fileName) delete fileName; 
    if (file)     fclose(file);
}
