/***************************************************************************
*                    Copyright (c) 1986, 87, 88 Tim Mooney                 *
*                      also Copyright 1989 Alan G Baxter                   *
*                                                                          *
*   Data input, screen & HPGL output- TM. Interface, Plt: support & con-   *
*   version files- AGB. See docs for distribution restrictions.            *
***************************************************************************/

/***************************************************************************
*   mp.c - PLOT DATA EMBEDDED IN TEXT FILE
*
*      Mp reads a text file and extracts data from it in a way defined by
*   interactive gadget selection.
*   When the data are collected, mp opens a high-res screen, and plots some
*   or all of the data -- again, in a user-defined way.  Some of the
*   details of plotting specifications can be altered in the "get how to"
*   window callable from menu selection in the main window.
****************************************************************************
*   Capabilities, limitations, and implementation notes:
*
*      Mp can plot lines or points of varying sizes; with or without error
*   bars; in 10 colors.  There is no internal limit on the number of data
*   sets plotted simultaneously, or on the number of points in a single
*   data set, or on the total size of all data sets.  Memory is allocated
*   dynamically; when it's used up, mp will stop processing the data file
*   and crash when it tries to open a new screen.
*
*      Points are actually drawn as squares, except for the smallest sizes.
*   Mp doesn't plot any other kinds of marks.  Points may be any size; one
*   may fill the screen, in fact.  All lines are solid, error bars are
*   lines.
*
*      GetDat() can scale data on input, directed by information in the
*   data file it's reading.  Although GetDat() can also extract a title and
*   labels from the data file, mp makes no use of them at present.
*
*      Once the data are plotted on the screen, the user can zoom in and
*   out, disable axes and grid, etc.  Also, the current picture can be
*   dumped to a file for plotting.  The only plotter language supported
*   is HPGL (Hewlett-Packard) since it's the only one I know.
*
*      IEEE maths libraries are used throughout.
***************************************************************************/
#include <graphics/display.h>
#include <libraries/dosextens.h>
#include <libraries/diskfont.h>
#include <exec/exec.h>
#include <exec/types.h>
#include <intuition/intuitionbase.h>
#include <graphics/regions.h>
#include <devices/keymap.h>
#include <stdio.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>
#include <workbench/icon.h>
#include <graphics/gfxmacros.h>
#include <graphics/gfxbase.h>
#include <math.h>

#define MAIN_MODULE 1

#include "struct.h"
#include "plotlim.h"
#include "front.h"

struct IntuitionBase *IntuitionBase; /* Pointer aus exec */
struct GfxBase *GfxBase;
struct DiskfontBase  *DiskfontBase;
long IconBase;

struct PlotRegion *FullReg;

int MAXVERT=512;       /* Globally declared int replaces #define to allow */
                       /* switches in screen size for Australia  Vs USA   */
int MAXHORIZ=640;
int CHARWIDTH=8;
int CHARHEIGHT=8;
int LMARGIN=57;  /* CHARWIDTH x 7 */
int TMARGIN=8;
int BMARGIN=24;    /* CHARHEIGHT x 3 */
int XMINP=57;      /* LMARGIN */
int YMAXP=504;   /* MAXVERT - TMARGIN */
int YMINP=24;    /* BMARGIN */
int XMAXP=638;   /* (MAXHORIZ-RMARGIN) */

extern short firstcall;
extern int GetDat();
extern void plot();
extern struct Screen *screen;
extern struct NewScreen newscreen;
extern struct NewWindow newwindow;

#define QUIT 0
#define GO 1
#define OFF 0
#define ON 1

int Overscan=ON;       /* Overscan flag can be turned off at start */
int QuitFrontFlag=GO;  /* Quit flag for Front Window requester */
int KEEP_GOING=1;      /* Quit flag for the whole program which all but */
                       /* closes the screen when "New" is selected.     */
int debug = FALSE;

FFP xtic[MAXTICS],ytic[MAXTICS];
short xticp[MAXTICS],yticp[MAXTICS];
char filename[150];
char progname[150];

struct RastPort *p;
struct Pict *Pict;
int xcol=1, ycol=2, ecol=0;

extern struct ViewPort *vp;
char StartDir[150];

main(argc,argv)
int argc;
union {
   char **args;
   struct WBStartup *msg;
} argv;
{
   struct WBArg *arg;
   int x=0,y=0;
   int terse=TRUE, fpal=1;
   FILE *fp;
   char **ToolArray;
   char *Value;
   struct IntuiMessage  *p_message;         /* pointer to message */
   struct DiskObject *diskobj;
   void ProcMes();


   filename[0] = 0;

   /*** OPEN LIBRARIES ***/
   if (!(IconBase = OpenLibrary("icon.library", 0))) {
     ErrorAlert(1);
     sexit(FALSE);
     }
   FFPLARGE = 1.0e10; FFPSMALL = 1.0e-10;
   DiskfontBase = (struct DiskfontBase *) OpenLibrary("diskfont.library",0);
   if( DiskfontBase == NULL )
      {
        ErrorAlert(2);
        sexit(FALSE);
      }
   GfxBase=NULL;
   GfxBase = (struct GfxBase *) OpenLibrary("graphics.library",33);
   if(GfxBase == NULL)
      {
        ErrorAlert(3);
        sexit (FALSE);
      }


   /*** PARSE ARGS ***/
   if (argc != 0) { /* called from CLI */
      stcgfp(StartDir,argv.args[0]);
      if (argc>1)   {
         if (argv.args[argc-1][0] == '?') {
          printf("usage: MultiPlot [-O] [filename]\n");
          exit(0);
         }
         if (argv.args[argc-1][0] != '-') {
           strcpy(filename,argv.args[argc-1]);
           strcpy(Gadget4SIBuff,filename);
         }
         if (argv.args[1][0] == '-') {
            if ((argv.args[1][1] == 'O')||(argv.args[1][1]=='o')) { Overscan=OFF; }
         }

      }
    }

   else { /* called from workbench */
      arg = argv.msg->sm_ArgList; /* point to command - find where multiplot lives */
      if (arg->wa_Lock != NULL) {
         getpath(arg->wa_Lock,StartDir);
         if (isdev(StartDir)) strcat(StartDir,":");
      }
      else stcgfp(StartDir,arg->wa_Name);
      arg++;
      if (argv.msg->sm_NumArgs > 1) {         /* find where data file lives */
         getpath(arg->wa_Lock,Gadget4SIBuff);
         if (isdev(Gadget4SIBuff)) strcat(Gadget4SIBuff,":");
         strmfp(Gadget4SIBuff,Gadget4SIBuff,arg->wa_Name);
      }
      strmfp(progname,StartDir,"multiplot");
      if (diskobj=GetDiskObject(progname))
        {
           ToolArray=diskobj->do_ToolTypes;
           Value=FindToolType(ToolArray,"OVERSCAN");
           if (MatchToolValue(Value,"OFF")) {Overscan=OFF;}
           FreeDiskObject(diskobj);
        }
   }
      /* SORT OUT SCREEN SIZING -- NOT ALL THAT SIMPLE!! */

   IntuitionBase=NULL;
   IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",33);  /* PAL Revision */
   if (IntuitionBase == NULL)
      { fpal=0;
        IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
        if(IntuitionBase == NULL) {
          ErrorAlert(4);
          sexit(FALSE);
        }
      }
   if ((Overscan==ON)&&(ScreenSize(&x,&y)))  /* Will try to get maximum screen size from WorkBench */
      {
        MAXVERT = y;
        MAXHORIZ = x;
        newscreen.Height=y;
        newscreen.Width=x;
        newwindow.Height=y;
        newwindow.Width=x;
       }
   else
     {
        /***** DO PAL - NTSC MAGIC. FROM SETPAL_NTSC *******/
       if (fpal > 0)
            { if (!  ( (GfxBase->DisplayFlags) & PAL )  ) fpal=0; }
       if (fpal == 0)  {
            MAXVERT=400;
            newscreen.Height=400;
            newwindow.Height=400;
         }
      }
   if (!(screen = (struct Screen *)OpenScreen(&newscreen)))
      {
         ErrorAlert(0);
         sexit(FALSE);
      }
   vp = &screen->ViewPort;
   InitColours();

   while (KEEP_GOING)
   {

  /***  RESET  THE WINDOW IN CASE THIS IS NOT FIRST TIME THROUGH ***/
     TMARGIN=CHARHEIGHT;
     BMARGIN= (CHARHEIGHT * 3);
     YMINP= BMARGIN;
     YMAXP=MAXVERT - TMARGIN;
     XMAXP=MAXHORIZ-RMARGIN;
     LMARGIN=(7 * CHARWIDTH);
     XMINP=LMARGIN;

     NewFrontWindow.Screen = screen;
     NewFrontWindow.Title ="                Data Selection Window            ";
     NewFrontWindow.FirstGadget = &Gadget1;
     if (!(FrontWindow = (struct Window *)OpenWindow(&NewFrontWindow)))
      {
         ErrorAlert(0);
         CloseScreen(screen);
         sexit(FALSE);
      }
     ActivateGadget(&Gadget4,FrontWindow,0);
     p = FrontWindow->RPort;
     PrintIText(p,&IText2,0,0);
     QuitFrontFlag=GO;     /*** RESET FLAG IN CASE NOT FIRST TIME ***/
     firstcall=TRUE;

     while (QuitFrontFlag !=QUIT)
      {
        Wait(1l<<FrontWindow->UserPort->mp_SigBit);        /* wait for a message */
        while (p_message = (struct IntuiMessage *)GetMsg(FrontWindow->UserPort))
          ProcMes(p_message);
      }

     if (!KEEP_GOING)   /*  STOP selected from Select Data Window */
      {
         CloseWindow(FrontWindow);
         CloseScreen(screen);
         sexit(FALSE);
      }

     SetPointer(FrontWindow,WaitSprite,26,14,-4,-4);
     SetWindowTitles(FrontWindow,-1,"    Loading data from file...  ");

     strcpy(filename,Gadget4SIBuff);
     xcol=Gadget1SInfo.LongInt;
     ycol=Gadget2SInfo.LongInt;
     ecol=Gadget3SInfo.LongInt;

     /*** OPEN FILE ***/
     fp = fopen(filename,"r");
     if (!fp) {
        printf("Can't open %s\n",filename);
        CloseWindow(FrontWindow);
        CloseScreen(screen);
        sexit(FALSE);
     }

     /*** ALLOCATE/INITIALIZE MEMORY FOR struct Pict ***/
     Pict = (struct Pict *)AllocMem(sizeof(struct Pict),MEMF_CLEAR);
     Pict->ErrBar = (ecol != 0);
     Pict->Tics = (struct Tics *)AllocMem(sizeof(struct Tics),MEMF_CLEAR);
     Pict->Tics->x = xtic;Pict->Tics->y = ytic;
     Pict->Tics->xp = xticp;Pict->Tics->yp = yticp;
     Pict->XRegionLock = Pict->YRegionLock = FALSE;
     Pict->Axes = TRUE;
     Pict->CurrReg =
        (struct PlotRegion *)AllocMem(sizeof(struct PlotRegion),MEMF_CLEAR);
     Pict->NewReg =
        (struct PlotRegion *)AllocMem(sizeof(struct PlotRegion),MEMF_CLEAR);
     Pict->Title = NULL;
     Pict->XLabel = NULL;
     Pict->YLabel = NULL;
     Pict->Plot = NULL;

     /*** GET DATA FROM FILE ***/
     GetDat(fp, xcol, ycol, ecol, terse, Pict);
     (void) fclose(fp);

     FullReg= (struct PlotRegion *)AllocMem(sizeof(struct PlotRegion),MEMF_CLEAR);
     GetPlotLimits(Pict,FullReg);

     /**** GET RID OF WINDOW ***/
     SetWindowTitles(FrontWindow,-1,newscreen.DefaultTitle);
     CloseWindow(FrontWindow);
     ClearPointer(FrontWindow);

     /*** PLOT DATA ***/
     plot(Pict);

     /*** DEALLOCATE MEMORY ***/
     FreeMem(Pict->NewReg,sizeof(struct PlotRegion));
     FreeMem(Pict->CurrReg,sizeof(struct PlotRegion));
     FreeMem(FullReg,sizeof(struct PlotRegion));
     FreeMem(Pict->Tics,sizeof(struct Tics));
     FreeMem(Pict,sizeof(struct Pict));
     FreeStructPlot();
   }

   CloseScreen(screen);
   sexit(TRUE);
}

int isdev(string)
char *string;
{
while ((*string!=':') && (*string!='\0')) string++;
if (*string==':') return(FALSE);
else return(TRUE);
}




void ProcMes(p_message)
struct IntuiMessage *p_message;
{
ULONG MesClass;        /*     Fields for storing      */
USHORT MesCode;        /*     intuimessage data       */
APTR Pointer;          /*                             */
int HandleEvent();

   MesClass = p_message->Class;             /* Store values */
   MesCode = p_message->Code;
   Pointer = p_message->IAddress;
   ReplyMsg(p_message);                     /* Reply to message */
   HandleEvent(MesClass,MesCode,Pointer);
}

int HandleEvent(MesClass,MesCode,Pointer)
ULONG MesClass;        /*     Fields for storing      */
USHORT MesCode;        /*     intuimessage data       */
APTR Pointer;          /*                             */
{
struct Process  *OurTask;
struct Window   *old_pr_WindowPtr;
static char drive[150], path[100], node[30], extn[20];

  if ( MesClass == GADGETDOWN)
    {

      if (Pointer == (APTR)&Gadget6) FindData();
      if (Pointer == (APTR)&Gadget5a)
         {
          KEEP_GOING=FALSE;
          QuitFrontFlag = QUIT;
          return(-1);
         }
      if (Pointer == (APTR)&Gadget5)
         {
          strsfn(Gadget4SIBuff,drive,path,node,extn);
          strcat(drive,path);
          strmfe(node,node,extn);

          OurTask = (struct Process *)FindTask(0L);
          old_pr_WindowPtr = (struct Window *)OurTask->pr_WindowPtr;
          OurTask->pr_WindowPtr = (APTR)FrontWindow;
          if (get_fname(FrontWindow,screen,"Select File to Open...",node,drive)==NULL)
               {
                  OurTask->pr_WindowPtr = (APTR)old_pr_WindowPtr;
                  return(0);
               }
           OurTask->pr_WindowPtr = (APTR)old_pr_WindowPtr;
           RemoveGadget(FrontWindow,&Gadget4);
           strmfp(Gadget4SIBuff,drive,node);
           AddGadget(FrontWindow,&Gadget4,-1L);
           RefreshGadgets(&Gadget4,FrontWindow,NULL);
           DrawBorder(p,&Border2,108,57);
          }
       else ;
    }
  if ( MesClass == RAWKEY) { if (MesCode ==196) FindData(); }  /* RETURN key RELEASED */

  return(1);
}


FindData()
{
FILE *fp;

   if (fp = fopen(Gadget4SIBuff,"r") )
     {
       SetPointer(FrontWindow,WaitSprite,26,14,-4,-4);
       SetWindowTitles(FrontWindow,-1,"    Checking file... ");
       if (CheckDat(fp,Gadget1SInfo.LongInt,Gadget2SInfo.LongInt,Gadget3SInfo.LongInt))
          {
            QuitFrontFlag = QUIT;
          }
       fclose(fp);
       ClearPointer(FrontWindow);
     }
   else
     {
       SetWindowTitles(FrontWindow,-1,newscreen.DefaultTitle);
       Message("     Can't open file        ");
     }
   return(0);
}


sexit(Err)
int Err;
{
if (IconBase) CloseLibrary(IconBase);
if (IntuitionBase) CloseLibrary(IntuitionBase);
if (GfxBase) CloseLibrary(GfxBase);
if (DiskfontBase) CloseLibrary(DiskfontBase);
exit(Err);
}


ScreenSize(x,y)
int *x;
int *y;
{
struct Screen *WBScreen;
int result;

   WBScreen = (struct Screen *)AllocMem(sizeof(struct Screen),MEMF_CLEAR);
   result = GetScreenData(WBScreen,sizeof(struct Screen),WBENCHSCREEN,NULL);
   *x=WBScreen->Width;
   if (WBScreen->Height > 300) *y=WBScreen->Height;   /* if wb is interlace */
   else *y=2*(WBScreen->Height);
   FreeMem(WBScreen,sizeof(struct Screen));
   return(result);
}


