/*===========================================================================
  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 Massachusetts 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 : ididrv.c       - Vers 3.6.002  - Mar 1994 -  L. Fini, OAA
 *                         - Vers 3.6.001  - Sep 1993 -  L. Fini, OAA
 *                         - Vers 3.6.000  - Oct 1991 -  L. Fini, OAA
 *
 *  891024:  fix bug within AGLCUIDI    KB
 *  891030:  modify more   KB
 *  891206:  modify for correct colors F.Tribioli
 *  900105:  use IIDQDC to get graphics channel no.  KB
 *  901108:  incorporate Midas-unit into graphics device name  KB
 *  911029:  Support for named colors and background color settings added (LF)
 *           Upgraded to version 36 (LF).
 *           Support for selecting Xor write mode added. LF
 *  920117:  update test of status after IIDOPN_C call   KB
 *  920305:  do not use IICINC because it overrides previous cursor shapes KB
 *  930914:  Support for different line widths added     LF
 *
 *  AGL device driver for a Midas IDI server
 *
 *  This driver uses standard IDI calls to send data to an already open
 *  IDI window.
 *
 *  NB: This driver is based on a number of assumptions about the
 *      way a display is used which will likely function only
 *      with Midas implementations of IDI.
 *
 *      In particular it assumes that a display has been created via a
 *      proper Midas command, before the driver tries to access to it.
 *
 *      The compilation of this module assumes a standard setting
 *      of Midas dirctory tree
 *
 * .VERSION
 *
 * 090416		last modif
 *
 */


#include <aglsys.h>

#include <aglerror.h>
#include <agldcom.h>
#include <agldcaps.h>

#include <fileexts.h>
#include <proto_agl.h>
#include <idi.h>
#include <proto_idi.h>

/*
 *  The following entry points are defined:
 *
 *  Function    Entry point
 *
 *  Initialize  AGLINIDI
 *  Cursor en.  AGLCUIDI
 *  Erase       AGLERIDI
 *  Escape      AGLESIDI
 *  Draw        AGLPLIDI
 *  Finish      AGLTEIDI
 *  Flush buff. AGLSEIDI
 */

#define N_DISPLAYS  4		/* Number of concurrent displays             */
#define NO_DISPLAY (-1)

#define TRUE   1
#define FALSE  0

#define PIXXLEN  0.030       /* We actually don't know the real value         */
#define PIXYLEN  0.030       /* We actually don't know the real value         */

#define VERSCODE 36			/* Declare driver version            */
#define IDINWIDTH    9
#define IDIFLAGS     INTERACTIVE|ERASEIT|SEPALPHA|SETBACKGR
#define IDISOLID   1                           /* Solid line selection   */
#define CHARMULT     1.0

#define IDIBLACK	1
#define IDIRED		2
#define IDIGREEN	3
#define IDIBLUE		4
#define IDIYELLOW	5
#define IDIMAGENTA	6
#define IDICYAN		7
#define IDIWHITE	0

#define CVTX(c) ((int)((double)(c)*IdiFcx[idix]+0.5));
#define CVTY(c) ((int)((double)(c)*IdiFcy[idix]+0.5));
#define INVCVTX(c) ((double)(c)*IdiXfc[idix]);
#define INVCVTY(c) ((double)(c)*IdiYfc[idix]);

static int IdiId[N_DISPLAYS] = { NO_DISPLAY, 
                                  NO_DISPLAY, 
                                  NO_DISPLAY,
                                  NO_DISPLAY  };

static int IdiDpth[N_DISPLAYS];
static int IdiNcol[N_DISPLAYS];
static int IdiXpix[N_DISPLAYS];
static int IdiYpix[N_DISPLAYS];
static int IdiClr[N_DISPLAYS];
static int IdiWdt[N_DISPLAYS];
static int IdiWrMod[N_DISPLAYS];
static int  memid;

static int ColorTbl[8] = {        /* Color remapping table                 */
                             2,    /* 0 : White                             */
                             1,    /* 1 : Black                             */
                             3,    /* 2 : Red                               */
                             4,    /* 3 : Green                             */
                             5,    /* 4 : Blue                              */
                             6,    /* 5 : Yellow                            */
                             7,    /* 6 : Magenta                           */
                             8 };  /* 7 : Cyan                              */
				   /* Black and White swapped for using     */
                                   /* White background                      */

static double IdiFcx[N_DISPLAYS]; 
static double IdiFcy[N_DISPLAYS]; 
static double IdiXfc[N_DISPLAYS]; 
static double IdiYfc[N_DISPLAYS]; 




void AGLCUIDI (AGLDVCOM)		/* Read virtual cursor position  */
struct bufcom *AGLDVCOM;
{
int idid,idix,stat;
int ixx,iyy;
char keycode;
int mem=(-1);				/* Display coordinates              */
int ncurs, trgstat[32];
int pixval=0;

idix = CHANNEL;
idid = IdiId[idix];			/* was missing ...  KB  */


ncurs=IBUFFR(1);
if(ncurs>0)
	ncurs=0;

ixx = CVTX(RBUFFR(0));			/* Convert cursor coordinates       */
iyy = CVTY(RBUFFR(1));

if (ncurs == 0) 
   {		/*  first we just try to set the cursor coordinates  */
   stat = IICWCP_C(idid,mem,ncurs,ixx,iyy);         /* Preset cursor position */
   if (stat == CURNOTDEF)			/* if not cursor defined, */
      {
      stat = IICINC_C(idid,mem,0,0,0,ixx,iyy);	    /* also init cursor and */
      stat = IICWCP_C(idid,mem,ncurs,ixx,iyy);      /* set position again */
      }

   if (stat == II_SUCCESS)
      stat = IICSCV_C(idid,ncurs,TRUE);		/* Display the cursor   */

   if (stat != II_SUCCESS)
      { 						/* Error */
      ERRCODE = DEVOPNSEV; 
      return; 
      }
   }

if(ncurs==0) 
	stat=IIIENI_C(idid,II_LOC,0,II_CURSOR,	/* Bind cursor to mouse   */
	              0,II_MOVE,0);

stat=IIIENI_C(idid,II_TRG,
                        0,	/* Raise flag 0                           */
                        0,	/* Object 0: no visible effect            */
                        0,	/* Obj id 0                               */
                        0,	/* Operation: appl. specific              */
                        0 );	/* Bind to trigger 0                      */
stat=IIIENI_C(idid,II_TRG,
                        1,	/* Raise flag 1                           */
                        0,	/* Object 0: no visible effect            */
                        0,	/* Obj id 0                               */
                        0,	/* Operation: appl. specific              */
                        0 );	/* Bind to trigger 0                      */
stat=IIIENI_C(idid,II_TRG,
                        2,	/* Raise flag 2                           */
                        0,	/* Object 0: no visible effect            */
                        0,	/* Obj id 0                               */
                        0,	/* Operation: appl. specific              */
                        0 );	/* Bind to trigger 0                      */
stat=IIIENI_C(idid,II_EVLC,
                        3,	/* Raise flag 3                           */
                        0,	/* Object 0: no visible effect            */
                        0,	/* Obj id 0                               */
                        0,	/* Operation: appl. specific              */
                        0 );	/* Bind to trigger 0                      */

do {
	stat=IIIEIW_C(idid,trgstat);		/* loop on the events   */
} while( (trgstat[1]==0)&&
         (trgstat[2]==0)&&
         (trgstat[3]==0)&&
         (trgstat[0]==0)   );

if(trgstat[0] != 0)
		keycode = ' ';
else if ((trgstat[1] != 0) || (trgstat[2] != 0))    /* Enter/Execute button  */
	keycode = 1;
else {
	char cbuf[4];
	stat=IIIGCE_C(idid,0,cbuf);
	keycode= *cbuf;
}
   
if(ncurs==0) {
	stat=IICRCP_C(idid,mem,0,&ixx,&iyy,&mem);

	RBUFFR(0)=INVCVTX(ixx);		/* Convert back cursor coordinates */
	RBUFFR(1)=INVCVTY(iyy);

	stat=IICSCV_C(idid,0,FALSE);	/* Cancel  the cursor   */
}
stat=IIISTI_C(idid);				/* stop the interaction */

IBUFFR(1)=keycode;
IBUFFR(2)=pixval;

}

void AGLINIDI (AGLDVCOM)                    /* Initialize                    */
struct bufcom *AGLDVCOM;
		                       /* This entry point will perform all  */
		                       /* the required initialization for    */
		                       /* the use of an IDI display as an    */
		                       /* AGL graphic device.                */
{
int idid,idix,stat;
char *pt, cbuf[12], midunit[4];

ERRCODE=AGLNOERR;
switch(IBUFFR(0)) {
	int i,itts,nomem,confmode;
	double xleng,yleng;

	case 0:                   
				/* device hardware initialization            */
				/* This function will attach to an existing  */
				/* display for subsequent operations. Up to  */
				/* N_DISPLAYS may be concurrently active     */

		pt=CHARBUF+strlen(CHARBUF)+1;	/* Skip to display name      */

				/*  build complete name "sxwXYmg"  from      */
				/*  "sxwmg" (m=0,1,2,3)                      */

     		cbuf[0] = *pt++;			/* s */
     		cbuf[1] = *pt++;			/* x */
     		cbuf[2] = *pt++;			/* w */
     		OSY_GETSYMB("DAZUNIT",midunit,4);
     		cbuf[3] = midunit[0];			/* X */
     		cbuf[4] = midunit[1];			/* Y */
     		cbuf[5] = *pt++;			/* m */
     		cbuf[6] = *pt;				/* g */
     		cbuf[7] = '\0';
		AG_DMSG("Opening display:",cbuf);

		idix=(-1);
		for(i=0; i<N_DISPLAYS; i++)    /* Search a free display slot */
			if(IdiId[i]==NO_DISPLAY) { 
				idix = i; 
				break; 
		}

		if(idix==(-1)) { 
			ERRCODE=DEVOPNSEV;	/* No free slot             */
			break; 
		}

		stat=IIDOPN_C(cbuf,IdiId+idix);       	/* Open the display */

		if ((stat!=II_SUCCESS) && (stat!=ENTRYFND)) { 
			char auxchr[32];
			sprintf(auxchr,"%d",stat);
			AG_DMSG("IDI open error:",auxchr);
			ERRCODE=DEVOPNSEV;		/* Error opening  */
			IdiId[idix]=NO_DISPLAY;	/* Free the slot  */
			break;
		}

		IdiWrMod[idix] = 0;		/* Preset write mode        */
		CHANNEL=idix;                     /* Return device index  */
		AG_DMSG("Done ...","");
		*(CHARBUF) = '\0';
		break;
  
	case 1:				/* Pass back device characteristics  */
		idix = CHANNEL;
		idid = IdiId[idix];

		*(CHARBUF) = '\0';

     				/* obtain channel no. of graphics plane  */

		idid = IdiId[idix];
		stat = IIDQDC_C(idid,0,4,1,&confmode,&memid,
		                              IdiXpix+idix,
		                              IdiYpix+idix,
		                              IdiDpth+idix,
		                              &itts,&nomem);
     /* printf("IIDQDC: memid,xs,ys = %d, %d, %d\n",
            memid,xs,ys); */
		if (nomem < 1) { 
			AG_DMSG("no graphics plane!","");
			ERRCODE=DEVOPNSEV;              /* Disply open err  */
			IdiId[idix]=NO_DISPLAY;        /* Free the slot    */
			break;
		}

		switch(IdiDpth[idix]) { 	/* Select suitable colors     */
			case 1: 
				IdiNcol[idix]=1;
				IdiClr[idix] = ColorTbl[IDIWHITE];
				IBUFFR(7) = IDIWHITE;	/* Default Background */
				IBUFFR(8) = IDIBLACK;	/* Default foreground */
				IBUFFR(9) = IDIBLACK;
				IBUFFR(16) = IDIWHITE;
				break;

			case 2: 
				IdiNcol[idix]=3; 
				IdiClr[idix] = ColorTbl[IDIWHITE];
				IBUFFR(7) = IDIWHITE;	/* Default Background */
				IBUFFR(8) = IDIBLACK;	/* Default foreground */
				IBUFFR(9) = IDIBLACK;
				IBUFFR(10) = IDIRED;
				IBUFFR(11) = IDIGREEN;
				IBUFFR(12) = IDIBLUE;
				IBUFFR(13) = IDIYELLOW;
				IBUFFR(14) = IDIMAGENTA;
				IBUFFR(15) = IDICYAN;
				IBUFFR(16) = IDIWHITE;
				break;

			default:
				IdiNcol[idix]=7; 
				IdiClr[idix] = ColorTbl[IDIWHITE];
				IBUFFR(7) = IDIWHITE;	/* Default Background */
				IBUFFR(8) = IDIBLACK;	/* Default foreground */
				IBUFFR(9) = IDIBLACK;
				IBUFFR(10) = IDIRED;
				IBUFFR(11) = IDIGREEN;
				IBUFFR(12) = IDIBLUE;
				IBUFFR(13) = IDIYELLOW;
				IBUFFR(14) = IDIMAGENTA;
				IBUFFR(15) = IDICYAN;
				IBUFFR(16) = IDIWHITE;
				break;
		}

		xleng = IdiXpix[idix] * PIXXLEN;
		yleng = IdiYpix[idix] * PIXYLEN;
		IdiFcx[idix] = IdiXpix[idix] - 1;	/* Direct  factor */
		IdiFcy[idix] = IdiYpix[idix] - 1;	/* Direct  factor */
		IdiXfc[idix] = 1.0 / IdiFcx[idix];	/* Reverse factor */
		IdiYfc[idix] = 1.0 / IdiFcy[idix];	/* Reverse factor */
		IdiWdt[idix] = 0;
		
		RBUFFR(0) = xleng;
		RBUFFR(1) = yleng;
		
		IBUFFR(1) = IDIFLAGS;
		IBUFFR(2) = IdiNcol[idix];
		IBUFFR(3) = IdiXpix[idix];
		IBUFFR(4) = IdiYpix[idix];
		IBUFFR(5) = VERSCODE;
		IBUFFR(6) = IDINWIDTH;

		RBUFFR(2) = CHARMULT;
		RBUFFR(3) = 0.0;
		RBUFFR(4) = 0.0;
		RBUFFR(5) = 0.0;
		RBUFFR(6) = xleng;
		RBUFFR(7) = yleng;
		RBUFFR(8) = 0.0;
		RBUFFR(9) = 0.0;
		break;

	case 2:				/* Set color                         */
		if (IBUFFR(1) > IdiNcol[CHANNEL]) 
			IBUFFR(1) = IdiNcol[CHANNEL];
		IdiClr[CHANNEL] = ColorTbl[IBUFFR(1)];
		break;

	case  3:			/* set line style                    */
		break;			/* Not used since AGL 3.3            */

	case  4:		/* set line width                            */
				/* Line width is obtained by using the line  */
				/* style parameter of IIGPLY                 */
				/* lstyl%10 will maintain the original mean- */
				/* ing of line style selector                */
				/* lstyl/10 will select a line width with 0  */
				/* being the only one currently used.        */

		IdiWdt[CHANNEL] = ((IBUFFR(1) < 0) ? 0 : IBUFFR(1))*10;
		break;
	case 5:
		switch(*CHARBUF) {
		default: 
		case 's': case 'S': 	/* Only direct write and XOR supprted */
			IdiWrMod[CHANNEL] = 0;
			break;
		case 'x': case 'X': 
			IdiWrMod[CHANNEL] = 10;
			break;
		}
		break;

	case 6: {				/* Coordinate roundoff       */
			int ixx,iyy;
			idix = CHANNEL;
			ixx = CVTX(RBUFFR(0));
			iyy = CVTY(RBUFFR(1));
			RBUFFR(0)=INVCVTX(ixx);
			RBUFFR(1)=INVCVTY(iyy);
		}
		break;
        
	default:
		break;             
}
}


void AGLERIDI (AGLDVCOM)			/* Erase screen             */
struct bufcom *AGLDVCOM;
{
int stat,idid,mem;
int color=IBUFFR(0);


idid = IdiId[CHANNEL];

if ((color>=IdiNcol[CHANNEL]) || (color<0))
	color = IDIWHITE;

ERRCODE = AGLNOERR;

mem=memid;

stat=IIMCMY_C (idid,&mem,1,ColorTbl[color]);

if(stat!=II_SUCCESS) 
	ERRCODE=DEVIOSEV; 			/* Access error   */
}


void AGLESIDI (AGLDVCOM)                    /* Escape function               */
struct bufcom *AGLDVCOM;
{
ERRCODE = UNSFEATINF;
}



void AGLSEIDI (AGLDVCOM)
struct bufcom *AGLDVCOM;		/* Actual flushing of the buffer is */
{					/* not performed. It is left to IDI */
ERRCODE=AGLNOERR;
}

void AGLTEIDI (AGLDVCOM)                    /* Terminate                     */
struct bufcom *AGLDVCOM;
{
int stat,idid,idix;

ERRCODE=AGLNOERR;
idix=CHANNEL;
idid=IdiId[idix];

stat=IIDCLO_C(idid);                     /* Close the display              */
IdiId[idix]=NO_DISPLAY;                 /* Free the display slot          */

if(stat!=II_SUCCESS) ERRCODE=DEVIOSEV;

CHANNEL = (-1);
}


void AGLPLIDI (AGLDVCOM)                    /* Draw to next point            */
struct bufcom *AGLDVCOM;
{
int i,n,idid;
int idix;
int lxx[400],lyy[400];			/* AGL Driver interface guarantees   */
					/* that 400 is enough                */
float *vectx, *vecty;

ERRCODE=AGLNOERR;

idix=CHANNEL;
idid = IdiId[idix];
n = NPOINTS;

if(n>1) 
   {
   if (n > 400)
      {
      (void) printf("AGL - ididrv: NPOINT = %d, truncated to 400\n",n);
      n = 400;
      }

   vectx = VECTX;
   vecty = VECTY;
   for(i=0;i<n;i++)
      {
      lxx[i] = CVTX((*vectx++));	/* Convert coordinates       */
      lyy[i] = CVTY((*vecty++));
      }
   IIGPLY_C(idid,memid,lxx,lyy,n,IdiClr[idix]+IdiWrMod[idix],
            IdiWdt[CHANNEL]+IDISOLID);
   }
}
