/* ---------------------------------------------------------------------

   PWS16DEV written by L. Granroth
            modified and additional code by R.Baines  7/89

   Module selects graphics device to be used and provides for some
   basic graphics utilities to be used in addition to those provided
   in the Turbo C graphics library.  There is also a method for using
   an externally defined BGI driver.

   --------------------------------------------------------------------- */



#define GRAPHICS

#include <graphics.h>
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <dir.h>
#include "pwstruct.h"
#include "pwsglobl.h"
#include "pwsgraph.h"
#include "proto.h"

/* define size of window under various widths and heights */
#define numbin640 540
#define numbin720 600
#define numbin800 720
#define numbin1024 900
#define numhi200 144
#define numhi348 288
#define numhi350 288
#define numhi480 400
#define numhi600 518
#define numhi768 640
#define numdev 14

/* Different Graphics Device Drivers */
static struct dev_table dev[] =
  {
    "ATT400", ATT400, ATT400HI,
    "CGA", CGA, CGAHI,
    "EGA", EGA, EGAHI,
    "EGA64", EGA64, EGA64HI,
    "EGAMONO", EGAMONO, EGAMONOHI,
    "HERC", HERCMONO, HERCMONOHI,
    "HGC", HERCMONO, HERCMONOHI,
    "HERCULES", HERCMONO, HERCMONOHI,
    "PC3270", PC3270, PC3270HI,
    "MCGA", MCGA, MCGAHI,
    "VGA", VGA, VGAHI,
    "8514", IBM8514, IBM8514HI,
    "EXTERNAL", DETECT, 0,
    "UNKNOWN", DETECT, 0
  };


/*---------------------------------------------------------------------

  pws16_device written by L. Granroth  10-14-88
               modified by R. Baines   07-26-89
  to handle output device selection and return the device-specific
  number of time bins for the PWS16PC program.

  ---------------------------------------------------------------------*/

int pws16_device (char *select)
{

  int i, nomatch=TRUE;
  char device[LLEN];

  /* See if autodetect or select mode */
  if (select)
  {
    strncpy (device, select, LLEN);
    while (nomatch)
    {
      /* Search table for indicated selection */
      strupr (device);
      for (i=0; i<numdev; i++)
         if (!(nomatch=strcmp(device,dev[i].name)))
            break;

      /* if not in table then prompt for device */
      if (nomatch)
      {
        printf("Unknown output device: %s", select);
        printf("Enter one of the following:\n");

	for (i=0; i<numdev; i++)
	   printf ("%s ",dev[i].name);

	printf ("QUIT\ndevice> ");
	gets (device);

	if (strcmp(strupr(device), "QUIT") == 0)
	   error(8);
      }
    }
  }


  /* if autodetect then autodetect otherwise use info from table */

  if (dev[i].driver == DETECT)
  { /* detect graph driver to use */
    detectgraph (&GraphDriver, &GraphMode);
    testGraphError();
  }
  else
  {
     GraphDriver = dev[i].driver;
     GraphMode = dev[i].mode;
  }

  /* Get window size for particular driver and mode */
  /* Find position of lower left corner of window on x-axis */
  /* Find position of lower left corner of window on y-axis */
  switch (GraphDriver)
  {
    case CGA:
    case ATT400:
      NumWide = numbin640;
      NumHigh = numhi200;
      Yorg = 200-(200-numhi200)/2;
      Xorg = (640-numbin640)*2/3;
      break;
    case EGA:
    case EGA64:
    case EGAMONO:
      NumWide = numbin640;
      NumHigh = numhi350;
      Yorg = 350-(350-numhi350)/2;
      Xorg = (640-numbin640)*2/3;
      break;
    case HERCMONO:
    case PC3270:
      NumWide = numbin720;
      NumHigh = numhi350;
      Yorg = 350-(350-numhi350)/2;
      Xorg = (720-numbin720)*2/3;
      break;
    case VGA:
    case MCGA:
      NumWide = numbin640;
      NumHigh = numhi480;
      Yorg = 480-(480-numhi480)/2;
      Xorg = (640-numbin640)*2/3;
      break;
	case IBM8514:
	  NumWide = numbin1024;
      NumHigh = numhi768;
      Yorg = 768-(768-numhi768)/2;
      Xorg = (1024-numbin1024)*2/3;
	  break;
	default:
	  NumWide = numbin800;
	  NumHigh = numhi600;
	  Yorg = 600 - (600-numhi600)/2;
	  Xorg = (800-numbin800)*2/3;
  }


  /* Give values to Tics */
  if (NumHigh > numhi200)
  {
     Tic = 2;
     LongTic = 4;
  }
  else
  {
     Tic = 1;
     LongTic = 2;
  }

  /* Register Grapics Drivers */
  if (registerbgidriver(Herc_driver) < 0) error(10);
  if (registerbgidriver(EGAVGA_driver) < 0) error(10);
  if (registerbgifont(small_font) < 0) error(10);

  return (NumWide);
}                                   /* PWS_Device */

/* ----------------------------------------------------------------------

   EXIT_GRAPH   written by R. Baines
   will beep, wait for a key to be pressed, then close graphics screen

   ----------------------------------------------------------------------*/

void exit_graph(void)
{
   pause_bell();
   closegraph();
   if (GraphDriver != HERCMONO)
      restorecrtmode();
}


/* ---------------------------------------------------------------------

   testGraphError
   closes graph, then displays appropriate error message.

   --------------------------------------------------------------------- */

void testGraphError(void)
{
   if ((ErrorCode = graphresult()) != grOk)
   {
     closegraph();
     puts(grapherrormsg(ErrorCode));
     exit(TRUE);
   }
}

/* ---------------------------------------------------------------------

   gprintf written by R. Baines
   like printf except displays to the graphics screen.

   --------------------------------------------------------------------- */

void gprintf(int *xloc, int *yloc, char *fmt, ...)
{
	va_list Argptr;
	char Workstr[140];
	struct textsettingstype textinfo;

	va_start(Argptr, fmt);
	vsprintf(Workstr, fmt, Argptr);
	outtextxy(*xloc, *yloc, Workstr);

	gettextsettings(&textinfo);
	if (textinfo.direction)
		*yloc -= textwidth(Workstr);
	else
		*xloc += textwidth(Workstr);

	va_end(Argptr);
}


/* ---------------------------------------------------------------------

   superscriptxy written by R. Baines
   if characters to be displayed in the graphics screen need to be
   superscripts. Superscripts value between carets.

   ie.  ^23^ superscripts 23 

   --------------------------------------------------------------------- */

int superscriptxy(int x,int y, int xmul,int xdiv, int ymul,int ydiv, char *src)
{
  int num=0;
  char *sptr, buffer[LLEN];

  strcpy(buffer, src);
  sptr = strtok(buffer, "^");
  while(sptr)
  {
    num++;
    gprintf(&x, &y, sptr);
    sptr = strtok(0, "^");
    if (sptr) {
       setusercharsize(xmul*.8, xdiv, ymul*.6, ydiv);
       gprintf(&x, &y, sptr);
       setusercharsize(xmul, xdiv, ymul, ydiv);
    }
    sptr = strtok(0, "^\n");
  }

  return (num);
}


/* ---------------------------------------------------------------------

   externalBGI written by R. Baines
   verifies the BGI driver exists and installs it.

   --------------------------------------------------------------------- */

void externalBGI(char name[], char mode[])
{
   char filename[80];
   struct ffblk ffblk;
   int errorcode;


   /* Verify File Exists */
   strcpy(filename, name);

   if (!(strstr(name, ".BGI")))
      strcat(filename, ".BGI");

   if ((findfirst("",&ffblk,0)) && ((GraphMode = atoi(mode)) >= 0)) {
      GraphDriver=installuserdriver(name, NULL);
      dev[12].driver = GraphDriver;
      dev[12].mode = GraphMode;

      /* read result of last graphics operation */
      errorcode = graphresult();
      if (errorcode != grOk) {
	 printf("Graphics error: %s\n", grapherrormsg(errorcode));
	 printf("Using Normal Graphics Devices");
	 GraphDriver=DETECT;
      }
   }
   else
      printf("BGI File Not Found.  Using Normal Graphics Devices\n");

}

