/*===========================================================================
  Copyright (C) 1995-2009 European Southern Observatory (ESO)
 
  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; either version 2 of 
  the License, or (at your option) any later version.
 
  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; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, 
  MA 02139, USA.
 
  Correspondence concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*
 * HEADER : aglstat.c      - Vers 3.6.001  - Aug 1993 -  L. Fini, OAA
 *                         - Vers 3.6.000  - Nov 1991 -  L. Fini, OAA
 *
 *
 * 090416	last modif
 */





/*                        Status modification routines                       */
 


#include <unistd.h>

#include <aglenvr.h>
#include <aglstat.h>






/*****************************************************************************/
/*                        aspect (Internal AGL use)                          */

/* Set a specified aspect ratio                                              */

/* Aspect ratio control is performed by redefining the clipping area so that */
/* the new clipping area is contained in the previous one and its aspect     */
/* ratio is the same as the ratio between Y and X axis of the user window    */

/* The original aspect ratio can be restored by the function:                */
/*          AGL_sgeom(OFF)                                                   */

/* affects global variables xclow,xclup,yclow,yclup                          */
/* To recompute transform. parameters "setgsta" must be called               */

static void aspect(ratio)
double ratio;			/* required aspect ratio                     */
				/* 1.0e-4 < ratio < 1.0e+4                   */
{
double clratio;				/* current clipp.area aspect ratio   */
AGL_status.errstat=AGLNOERR;

if((ratio<1.0e-3)||(ratio>1.0e+3)) { 
	AGL_status.errstat=(ASPECTWNG); 
	return; 
}

clratio = YXRATIO;

if(clratio<ratio) {			/* left-rigth squeeze                */
	double dlta;
	dlta = (1.0-(clratio/ratio))*(XCLUP-XCLOW)*0.5;
	XCLOW += dlta;
	XCLUP -= dlta;
} else {				/* top-bottom squeeze                */
	double dlta;
	dlta = (1.0-(ratio/clratio))*(YCLUP-YCLOW)*0.5;
	YCLOW += dlta;
	YCLUP -= dlta;
}
}


/***********************************************************************/
/*                                                                     */
/*                    AGL_sgeom (Internal AGL use)                     */

/* Set automatic aspect ratio control ON or OFF                        */

/* Automatic aspect ratio sets the clipping area aspect ratio equal to */
/* the aspect ratio of the currently defined user window               */

void AGL_sgeom(stat)
int stat;                             /* request status (ON or OFF)   */
{
if(stat == ON) {
	double ratio;

	AGL_status.errstat=AGLNOERR;
	if(!DY(window)) return;

	ratio = fabs((double)(YUSLOW-YUSUP))/
	        fabs((double)(XUSLOW-XUSUP));
	aspect(ratio);
	if(AGL_status.errstat != AGLNOERR) return;
	DY(autoasp) = ON;
} else {				/* Set automatic aspect control OFF  */
	XCLOW = XSVLOW; XCLUP = XSVUP;
	YCLOW = YSVLOW; YCLUP = YSVUP;
	DY(autoasp) = OFF;
}
}






/*****************************************************************************/
/*                              testlog (AGL internal use)                   */

/* tests log transformation validity                                         */

static int testlog(code)	/* Returns TRUE/FALSE                        */
int code;			/* Axis selection (X_AXIS/Y_AXIS)            */
{
switch(code) {
	case X_AXIS: 
		return( (XUSUP>0.0) && (XUSLOW>0) );
	case Y_AXIS: 
		return( (YUSUP>0.0) && (YUSLOW>0) );
}
return FALSE;
}







/*****************************************************************************/
/*                              AGL_vflsh (AGL internal use)                  */

/* Forces output of current device buffer                                    */

void AGL_vflsh()
{
DEFINE_AGLDVCOM;

if(AGL_status.vwpoint==NULL) 
	AGL_status.errstat=(NOVWPERR);
else {
	CHANNEL = DY(curchan);
	SENDFUNCT(AGLDVCOM);		/* Empty viewport buffer             */
	AGL_status.errstat=ERRCODE;
}
}



/*****************************************************************************/
/*                              execmd (AGL internal use)                    */

/* Executes a device specific command (O.S. command)                         */

static void execmd(cmd)
char *cmd;                    /* Command string to execute                  */
{
extern void AG_DMSG();

AGL_status.errstat=AGLNOERR;

if ( *cmd=='\0') return;

AG_DMSG("Exec:",cmd);

if(SYSTEM(cmd)<0) 
	AGL_status.errstat = DEVCMDWNG;
}






/*****************************************************************************/
/*                              AGL_dstop (AGL internal use)                   */

/* Closes operations on the given device                                     */

void AGL_dstop(slot)
int slot;                          /* Device slot                           */
{
DEFINE_AGLDVCOM;
extern void AG_DMSG();
int (*termf)();

CHANNEL=GRCHAN(slot);

AG_DMSG("Close:",DEVNAM(slot));

IBUFFR(0)=FALSE;
termf = *(DRVADDR(slot)+5);
termf(AGLDVCOM);
ACTREQST(slot)=0;		/* clear device request counter          */

if(IBUFFR(0)) {			/* If IBUFR(0) returns TRUE, then the    */
	if(FILNAM(slot) != '\0') {	/* file was not actually written and */
					/* it should be deleted              */
		AG_DMSG("Empty file removed:",FILNAM(slot));
		REMOVE(FILNAM(slot));
	}
} else
	execmd ( DEVCOMMND(slot) );	/* execute device command            */

AGL_status.errstat = MAX(AGL_status.errstat,ERRCODE);
}




/*****************************************************************************/
/*                          AGL_fvwp (Internal AGL Use)                      */

/* Deallocates space for viewport structure (also clear viewport pointers)   */

void AGL_fvwp(vwpid)			/* Returns error code                */
int vwpid;
{
if(AGL_status.vwpts[vwpid] != NULL) {
	free((char *)AGL_status.vwpts[vwpid]);
	AGL_status.vwpts[vwpid] = NULL;
}
AGL_status.vwpoint = NULL;
AGL_status.curvwp=VWPEMPTY;
}






/***********************************************************************/
/*                    AGL_sstat (internal AGL use)                     */

/* This routine is called in order to recompute transformation parame- */
/* ters and to set the graphic status in the following cases:          */

/*    - when defining the viewport                                     */
/*    - when defining the clipping area,                               */
/*    - when changing the aspect ratio                                 */
/*    - when defining the user window,                                 */
/*    - when switching between normalized and user mode,               */
/*    - when switching between log and linear transf.                  */

/* Recomputed paremeters are held in the global variables:             */
/*    aglfcx, aglfcy, aglofx, aglofy                                   */

/* Method:                                                             */

/*   Let (xi,yi) and (xo,yo) be the input and output coordinates to be */
/*   transformed, then:                                                */

/*     xo = XCLOW + (xi-xbot)*(XCLUP-XCLOW)/(xtop-xbot)                */
/*     yo = YCLOW + (yi-ybot)*(YCLUP-YCLOW)/(ytop-ybot)                */

/*     where input and output rectangules are defined as follows:      */

/*                Input     ----transf.----->     Output               */
/*      ytop --+---------+--         YCLUP ----+---------+--           */
/*             |         |                     |         |             */
/*             | (xi,yi) |                     | (xo,yo) |             */
/*      ybot --+---------+--         YCLOW ----+---------+--           */
/*            xbot      xtop                 XCLOW     XCLUP           */

/*     In order to increase efficiency, the above relationships can be */
/*     rewritten as follows:                                           */

/*         xo = aglfcx * xi + aglofx                                   */
/*         yo = aglfcy * yi + aglofy                                   */

/*     where:                                                          */

/*         aglfcx = (XCLUP-XCLOW)/(xtop-xbot)                          */
/*         aglofx = XCLOW  - aglfcx * xbot                             */
/*         aglfcy = (YCLUP-YCLOW)/(ytop-ybot)                          */
/*         aglofy = YCLOW -  aglfcy * ybot                             */

/*  Values chosen for (xbot,xtop,ybot,ytop) depend on the transforma-  */
/*  tion in effect: either user window bounds or their logarithms may  */
/*  be used.                                                           */


void AGL_sstat()
{
double xbot,xtop,ybot,ytop;

if(DY(modeflag)!=NORMAL) {
	double denom;

	if ( DY(flogx) && testlog(X_AXIS) ) {
		xtop = log((double)XUSUP); xbot = log((double)XUSLOW);
		AGL_status.xlogon = TRUE;
	} else {
		xtop = XUSUP; xbot = XUSLOW;
		AGL_status.xlogon = FALSE;
	}

	if( DY(flogy) && testlog(Y_AXIS) ) {
		ytop = log((double)YUSUP); ybot = log((double)YUSLOW);
		AGL_status.ylogon = TRUE;
	} else {
		ytop = YUSUP; ybot = YUSLOW;
		AGL_status.ylogon = FALSE;
	}

	if(DY(modeflag)==SPECIAL) {
		if(DY(UsrTransf) == NULL) {
			AGL_status.errstat=MODEERR;
			DY(modeflag)=USER;
			AGL_status.UTransf=FALSE;
		} else {
			(*DY(UsrInit))();	/* Init. user transformation */
			AGL_status.UTransf=TRUE;
		}
	} else
		AGL_status.UTransf=FALSE;
		
                                    /* Compute transformation params    */
	
	denom=xtop-xbot;
	if(denom!=0) {
		AGL_status.aglfcx = (XCLUP-XCLOW-0.0002)/denom;
		AGL_status.aglofx = XCLOW  - AGL_status.aglfcx * xbot + 0.0001;
	}
	denom=ytop-ybot;
	if(denom!=0) {
		AGL_status.aglfcy = (YCLUP-YCLOW-0.0002)/denom;
		AGL_status.aglofy = YCLOW -  AGL_status.aglfcy * ybot + 0.0001;
	}
}
}




/************************************************************************/
/*                      AGL_swdt (internal AGL use)                     */

/* This routine commands the current driver to set the current line     */
/* width                                                                */

void AGL_swdt(width)
int width;			/* width to set. It is assumed that the */
				/* value is correct for the device      */
{
DEFINE_AGLDVCOM;
if(AGL_status.vwpoint==NULL) { 
	AGL_status.errstat=(NOVWPERR); 
	return; 
}
IBUFFR(0)=4; IBUFFR(1)=width; CHANNEL=DY(curchan);
INITFUNCT(AGLDVCOM);
AGL_status.errstat=(ERRCODE);
}

/************************************************************************/
/*                      AGL_sclr (internal AGL use)                     */

/* This routine commands the current driver to set the current color    */

void AGL_sclr()
{
DEFINE_AGLDVCOM;

if(AGL_status.vwpoint==NULL) { 
	AGL_status.errstat=NOVWPERR; 
	return; 
}

IBUFFR(0)=2; 
IBUFFR(1)=DY(color); 
CHANNEL=DY(curchan);
INITFUNCT(AGLDVCOM);
AGL_status.errstat=ERRCODE;
}


/**************************************************************************/
/*                     AGL_sgbl (internal AGL use)                        */

/* Sets the global status according various status flags (called by CDEF) */
/* and WDEF                                                               */

void AGL_sgbl()
{
int maxerr=AGLNOERR;
AGL_status.errstat=AGLNOERR;

if(DY(window)) {
	if(DY(autoasp)==ON) {			/* Set automatic aspect ratio */
		AGL_sgeom(ON);
		if(AGL_status.errstat != AGLNOERR) {
			DY(autoasp)=OFF;
			maxerr=AGL_status.errstat;
		}
	}

	if(DY(flogx)) {
		if( !testlog(X_AXIS)) {
			DY(flogx)=FALSE;
			maxerr = MAX(maxerr,NOLOGERR);
		}
	}
 
	if(DY(flogy)) {
		if( !testlog(Y_AXIS)) {
			DY(flogy)=FALSE;
			maxerr = MAX(maxerr,NOLOGERR);
		}
	}

	AGL_sstat();			/* Set graphic status params       */
}
AGL_status.errstat=maxerr;
}
