/*  File drawmap.c  */

#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfxmacros.h>
#include <graphics/gfxbase.h>
#include <devices/printer.h>
#include <exec/io.h>
#include <exec/memory.h>
#include <stdio.h>
#include <fcntl.h>
#include <math.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <workbench/workbench.h>

#ifdef LATTICE      /* Lattice supports prototypes ! */
#define FDwAT
#define LETTUCE
#include <ios1.h>
#include <workbench/startup.h>
#include <string.h>
#include <stdlib.h>
#include <proto/all.h>
int CXBRK(VOID) { return(0); }
#endif

#include "iff/ilbm.h"

#include "drawmap.h"
#include "drawmap-proto.h"
#include "drawmap-req.h"
#include "drawmap-menu.h"

#ifndef NO_ASL
#include "libraries/aslbase.h"
#endif

#define PROJECT 0
   /* menu selection numbers */
   /* this should look similar to menustrip */
   #define ABOUT 0
/* #define DRAW 1 */
    #define MAP 2
      #define FLAT     0
      #define MERCATOR 1
      #define BOX      2
    #define SPHERE 3
      #define SPHEREOFFSET 3
      #define GLOBE    3
      #define ORBITAL  4
      #define ZOOM_IN  5
      #define ZOOM_OUT 6
/* #define IFF PICTURE 4 */
    #define SAVE 5
    #define SAVEAS 6

   #define PRINT 7
   #define GRID 8
   #define CLEAR 9

   #define QUIT 10
#define EDIT 1
   #define COLOR_F  0
   #define COLOR 1
   #define DRAW 2
   #define FLOOD 3
   #define TEXT 4
   #define COLORPALETTE 5
#define SPECIAL 2
   #define SHADOW  0

short *map, *map_trig;                 /* workspaces for map  */
short *td, *td_trig;

struct Screen *s;                      /* pointer to screen   */
struct Window *w, *wt;                 /* pointers to Windows */
struct RastPort *rp;                   /* pointer to RastPort */
struct ViewPort *vp;                   /* pointer to ViewPort */
struct AreaInfo mapAreaInfo;
struct TmpRas mapTmpRas;
struct GfxBase *GfxBase;
struct IntuitionBase *IntuitionBase;

#ifndef NO_ASL
extern struct AslBase *AslBase;
#endif
extern struct ArpBase *ArpBase;
extern struct FileRequester *filereq;
short areaArray[5*NUMPTS];             /* 5 words per point for drawing    */
short area[2*NUMPTS];                  /* storage for each individual area */

#ifndef LATTICE
unsigned short *arrow, *cross;         /* storage for mouse pointers */
unsigned short *waiter, *transparent;
unsigned short *close_data_c, *ilbm_data_c;
#endif

UBYTE *bp[DEPTH];                      /* bitplane pointers         */
/*  short ytable[SHEIGHT];                * under shadow() *
    short rowoffset; */
#define rowoffset (WWIDTH/8)

struct Requester req;


/* ============================================================= */
#ifdef LETTUCE
void _main (line)
register char *line;
#else
main ()
#endif

{
   struct IntuiMessage *msg;
   PLANEPTR workspace;
   LONG exitcode=RETURN_ERROR;
   struct MsgPort *idcmpport;
   struct Process *process;
   extern void free_svector(), InitTextRequest();
   extern int readmap();
   extern int HandleEvent();
   extern short *svector();
   extern VOID FreeArpRequest(), FreeFileRequest();
   int ix;

#ifdef LETTUCE      /* optimized for Lattice/SAS C (from umain.c)*/
   extern struct UFB _ufbs[];
   extern int _fmode,_iomode;
   register int x;
   struct FileHandle *handle;
   extern int (*_ONBREAK)();
   extern int CXBRK();

   if (*line=='\0'){    /* running under workbench */
        _ufbs[0].ufbfh = Open("NIL:",MODE_NEWFILE);
        _ufbs[1].ufbfh = _ufbs[0].ufbfh;
        _ufbs[1].ufbflg = UFB_NC;
        _ufbs[2].ufbfh = _ufbs[0].ufbfh;
        _ufbs[2].ufbflg = UFB_NC;
        handle = (struct FileHandle *)(_ufbs[0].ufbfh << 2);
        process = (struct Process *)FindTask(0);
        process->pr_ConsoleTask = (APTR)handle->fh_Type;
        x = 0;
   }
   else                    /* running under CLI            */
   {
        _ufbs[0].ufbfh = Input();
        _ufbs[1].ufbfh = Output();
        _ufbs[2].ufbfh = Open("*", MODE_OLDFILE);
        x = UFB_NC;                     /* do not close CLI defaults    */
   }

   _ufbs[0].ufbflg |= UFB_RA | O_RAW | x;
   _ufbs[1].ufbflg |= UFB_WA | O_RAW | x;
   _ufbs[2].ufbflg |= UFB_RA | UFB_WA | O_RAW;

   x = (_fmode) ? 0 : _IOXLAT;
   stdin->_file = 0;
   stdin->_flag = _IOREAD | x;
   stdout->_file = 1;
   stdout->_flag = _IOWRT | x;
   stderr->_file = 2;
   stderr->_flag = _IORW | x;

   _ONBREAK = CXBRK;

#endif
   if ((GfxBase = (struct GfxBase *) OpenLibrary ("graphics.library",0)) == NULL)  {
      printf ("Can't open library");
      goto end0;
   }

   if ((IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library",0)) == NULL)  {
      printf ("Can't open library");
      goto end1;
   }
   if ((s = OpenScreen (&mapscreen)) == NULL)  {
      printf ("Can't open screen or init windows");
      goto end2;
   }
   if ((idcmpport=CreatePort(NULL,0))== NULL ){
      printf ("Can't open screen or init windows");
      goto end21;
   }

   mapWindow.Screen = s;
   if ((w = OpenWindow (&mapWindow)) == NULL)  {
      printf ("Can't open screen or init windows");
      goto end3;
   }
   maptitleWindow.Screen=s;
   if ((wt=OpenWindow (&maptitleWindow)) == NULL){
      printf ("Can't open screen or init windows");
      goto end31;
   }
   w->UserPort=idcmpport;
   wt->UserPort=idcmpport;
   ModifyIDCMP(wt, CLOSEWINDOW|ACTIVEWINDOW);    /* Titlebar Window to get CLOSEWINDOW message*/
   ModifyIDCMP(w, IDCMPFLAGS);


#ifndef LATTICE
   if (((arrow = (UWORD *) AllocMem (arrow_size, MEMF_CHIP)))==NULL){
      goto end41;
   }
   for (ix=0; ix<arrow_size/2; ++ix)
      arrow[ix] = arrow_data[ix];
                                       /* init. mouse pointers */
   if (((cross = (UWORD *) AllocMem (cross_size, MEMF_CHIP)))== NULL){
      goto end42;
   }
   for (ix=0; ix<cross_size/2; ++ix)
      cross[ix] = cross_data[ix];

   if (((waiter = (UWORD *) AllocMem (waiter_size, MEMF_CHIP))) == NULL){
      goto end43;
   }
   for (ix=0; ix<waiter_size/2; ++ix)
      waiter[ix] = waiter_data[ix];

   if (((transparent = (UWORD *) AllocMem (transparent_size, MEMF_CHIP))) == NULL){
      goto end44;
   }
   for (ix=0; ix<transparent_size/2; ++ix)
      transparent[ix] = transparent_data[ix];

   if (((close_data_c = (UWORD *) AllocMem (close_size, MEMF_CHIP))) == NULL){
      goto end45;
   }
   CopyMem(close_data, close_data_c, close_size);
   closeimage.ImageData=close_data_c;

   if (((ilbm_data_c = (UWORD *) AllocMem (ilbm_size, MEMF_CHIP))) == NULL){
      goto end46;
   }
   CopyMem(ilbm_data,ilbm_data_c);
   ilbmimage.ImageData=ilbm_data_c;

#endif

   vp = &(s->ViewPort);                /* pointer to viewport */
   LoadRGB4 (vp, &mapcolors[0], 4);    /* init. color values  */
   DrawImage(&s->RastPort,&closeimage,0,0);     /* looks nicer than */
                                                /* system gadgs. */
   SetPointer (wt, arrow, arrow_size/4-2, 16, arrow_x_offset, arrow_y_offset);
   SetPointer (w, arrow, arrow_size/4-2, 16, arrow_x_offset, arrow_y_offset);

   rp = w->RPort;
   if ((workspace = (PLANEPTR) AllocRaster (WWIDTH,WHEIGHT)) == NULL)  {
      printf ("Can't get space");
      goto end4;
   }
   InitTmpRas (&mapTmpRas, workspace, RASSIZE(WWIDTH,WHEIGHT));
   rp->TmpRas = &mapTmpRas;            /* link it to the RastPort */
   InitArea (&mapAreaInfo, &areaArray[0], NUMPTS);
   rp->AreaInfo = &mapAreaInfo;        /* link it to the RastPort */

   SetPointer (w, waiter, waiter_size/4-2, 16,
               waiter_x_offset, waiter_y_offset);

   if ((map = (short *) AllocMem ((MAXVAL-1)*sizeof(short), MEMF_CLEAR| MEMF_PUBLIC)) == NULL)  {
      printf ("Can't get space for map information");
      goto end5;
   }
   if ((ix = readmap (map, mapname, MAXVAL)) != OK)  { /* read map file */
      printf ("Error reading file :");
      printf (mapname);
      goto end6;
   }
   if ((map_trig = (short *) AllocMem ((MAXVAL-1)*sizeof(short), MEMF_CLEAR| MEMF_PUBLIC)) == NULL)  {
      printf ("Can't get space for map information");
      goto end6;
   }
   if ((ix = readmap (map_trig, mapname_trig, MAXVAL)) != OK)  { /* read map_trig file */
      printf ("Error reading file :");
      printf (mapname_trig);
      goto end7;
   }
   if ((td = (short *) AllocMem ((MAXTIDY-1)*sizeof(short), MEMF_CLEAR| MEMF_PUBLIC)) == NULL)  {
      printf ("Can't get space for map information");
      goto end7;
   }
   if ((ix = readmap (td, tdname, MAXTIDY)) != OK)  {  /* read td file */
      printf ("Error reading file :");
      printf (tdname);
      goto end8;
   }
   if ((td_trig = (short *) AllocMem ((MAXTIDY-1)*sizeof(short), MEMF_CLEAR| MEMF_PUBLIC)) == NULL)  {
      printf ("Can't get space for map information");
      goto end8;
   }
   if ((ix = readmap (td_trig, tdname_trig, MAXTIDY)) != OK)  { /* read td_trig file */
      printf ("Error reading file :");
      printf (tdname_trig);
      goto end9;
   }
   SetPointer (w, arrow, arrow_size/4-2, 16, arrow_x_offset, arrow_y_offset);


    /* redirect system requesters ("Printer trouble", ...)*/
#ifndef LATTICE
   process = (struct Process *)FindTask(NULL);   /* Finds our process */
#endif
   process->pr_WindowPtr = (APTR)w;

   DrawBorder (rp, &border_top, (WWIDTH-TWIDTH)/2, (WHEIGHT-THEIGHT)/2-THEIGHT/2);

   PrintIText(rp,&hailtext, (WWIDTH-TWIDTH)/2+13, (WHEIGHT-THEIGHT)/2+TEXTYOFFS);

   SetMenuStrip(w,&Menu1);       /* TATA !!! We set the MENUs */

   SetAPen (rp,ORANGE);                /* land  */
   SetBPen (rp,BLUE);                  /* water */
   SetDrMd (rp,JAM2);

   InitTextRequest ();                 /* initialize the string requester */

   view_height = VIEW_HEIGHT;          /* constants for globe view */
   eta = view_height/RE;
   facp = 1. + eta;
   etap = 1./facp;

   for (ix=0; ix<DEPTH; ++ix)          /* initialize bitplane pointers */
      bp[ix] = w->RPort->BitMap->Planes[ix];
   /* wait for message from */
   /*   Intuition           */
   do {
      WaitPort (w->UserPort);
      msg = (struct IntuiMessage *)GetMsg (w->UserPort);
      if (msg==NULL)
        continue;
   } while (HandleEvent (msg) == OK);   /* Replies msg !!! */
   exitcode=0;
#ifndef NO_ASL
   if (AslBase !=NULL){
        if (filereq)    FreeFileRequest(filereq);
        CloseLibrary(AslBase);
    }
   else
#endif
      if (ArpBase != NULL){ /* i.e. if Filerequester has been initialized */
        FreeArpRequest(filereq);
    }

end9:
   FreeMem (td_trig, (MAXTIDY-1)*sizeof(short) ); /* done, so clean up */
end8:
   FreeMem (td,  (MAXTIDY-1)*sizeof(short) );
end7:
   FreeMem (map_trig, (MAXVAL-1)*sizeof(short) );
end6:
   FreeMem (map, (MAXVAL-1)*sizeof(short) );
end5:
   FreeRaster (workspace, WWIDTH, WHEIGHT);
#ifndef LATTICE
end4:
   FreeMem (ilbm_data_c, ilbm_size);
end46:
   FreeMem (close_data_c, close_size);
end45:
   FreeMem (transparent, transparent_size);
end44:
   FreeMem (waiter, waiter_size);
end43:
   FreeMem (cross, cross_size);
end42:
   FreeMem (arrow, arrow_size);
#endif
   ClearPointer (w);
   Forbid();        /* Strip ALL IntuiMessages */
   while (msg = (struct IntuiMessage *)GetMsg (w->UserPort)){
    ReplyMsg((struct Messsage *)msg);
   }
   w->UserPort=NULL;
   wt->UserPort=NULL;
   ModifyIDCMP(wt, NULL);    /* Titlebar Window to get CLOSEWINDOW message*/
   ModifyIDCMP(w, NULL);
   Permit();
#ifndef LATTICE
end41:
#else
end4:
#endif
   CloseWindow(wt);
end31:
   CloseWindow(w);
end3:
   CloseScreen (s);
end21:
   DeletePort(idcmpport);
end2:
   CloseLibrary ((struct Library *)IntuitionBase);
end1:
   CloseLibrary ((struct Library *)GfxBase);
end0:
   printf("\nDrawmap closed.\n");
   exit (exitcode);
}

/* ============================================================= */

int readmap (ws, fname, num)                /* reads map files into memory */

short *ws;
char *fname;
int num;

{
   BPTR handlebin;

   int disp, numrd;

   if ((handlebin = Open (fname, MODE_OLDFILE)) == NULL)
      return (NOT_OK);
   disp = 0;
   FOREVER {
      if ((numrd = Read (handlebin, (char*) &ws[disp], 4000)) <= 0)
         break;
      disp += numrd / sizeof(short);
   }
   Close (handlebin);
   if (disp!=num)
      return (NOT_OK);
   return (OK);
}

/* ============================================================= */

void InitTextRequest ()                /* initializes a string requester */

{
   InitRequester (&req);               /* initialize the requester */
   req.LeftEdge = TLEFT;
   req.TopEdge = TTOP;
   req.Width = TWIDTH;
   req.Height = THEIGHT;
   req.ReqGadget = &gad;
   req.ReqText = &rtext;
   req.BackFill = ORANGE;
   req.Flags = 0;
   req.ReqBorder = &border_top;

   strcpy (userinput, defaulttext); /* copy default text string */
}

/* ============================================================= */

int HandleEvent (msg)                  /* processes main Intuition events */

struct IntuiMessage *msg;

{
   static char title_FLAT[]     = "   Flat Map";
   static char title_MERCATOR[] = "   Mercator";
   static char title_GLOBE[]    = "   Globe...view from infinitely far away";
   static char title_ORBITAL[60];   /* is filled in by sprintf */
   static char title_PRINT[]    = "   Print";
   static char PRINT_wait[]     = "   <-- Click here to CANCEL printing";
   static char PRINT_error[]    = "   Print aborted";
   static char title_SAVE[]     = "   Save";
   static char SAVEAS_wait[]    = "   Please select save name for displayed map";
   static char SAVE_wait[]      = "   Saving displayed map as IFF Picture";
   static char SAVE_error[]     = "   Screen not successfully saved";

   static char title_GRID[]     = "   Grid";
   static char title_FLOOD[]    = "   Flood Fill";
   static char title_DRAW[]     = "   Draw Line";
   static char title_SHADOW[]   = "   Shadow";
   static char title_BOX[]      = "   Box";
   static char title_COLORS[]   = "   Colors";
   static char title_TEXT[]     = "   Text";
   static char title_HELP[]     = "   About Drawmap";
   static char title_CLEARS[]   = "   Clear Screen";
   static char press_prompt[]   = "   Press LEFT button to select center point";
   static char drag_prompt[]    = "   Press and drag LEFT button to select box";
   static char flood_wait[]     = "   Flood fill...press LEFT button to fill area | RIGHT button to CANCEL";
   static char draw_wait[]      = "   Draw...press LEFT button to draw a line | RIGHT button to CANCEL";
   static char box_error[]      = "   Box of zero size not allowed";
   static char grid_error[]     = "   Invalid map displayed for Grid option";
   static char fmt_ORBITAL[]    = "   Orbital...view from %.2lf kilometers";
   static char fmt_ZOOM_IN[]    = "   Zoom In...view from %.2lf kilometers";
   static char fmt_ZOOM_OUT[]   = "   Zoom Out...view from %.2lf kilometers";
   #define MAXLENGHT 255
   static char picname[MAXLENGHT+1] = "DrawmapPIC";
   static LONG lenghtpicname = 10;  /* strlen(picname)*/
   static int picnum=0;

   struct IntuiMessage *msgf;
   extern long PopChoose();
   extern void fullmap(), globe(), stars(), floodfill(), drawline();
   extern void box(), grid(), shadow(), do_text(), getcoord();
   extern void displayhelp(), setwin();
   extern LONG dump(), save(), saveas();
   extern int getbox();

   static long oldval = -1L;
   static short activepen= ORANGE;
   static long fill = FILL;
   static long color_offset = 0;
   int x, y, x0, y0, result;
   double lat[2], lam[2];
   static double lamg, latg;
   USHORT select,flag;
   LONG menunum,itemnum,subnum;

   switch (msg->Class) {
   case CLOSEWINDOW:
      DisplayBeep(0);
      ReplyMsg((struct Message *)msg);
      return (NOT_OK);
      break;
   case ACTIVEWINDOW:         /* Titlebar (Closegad) window activated */
      ActivateWindow (w);     /* Reactivate other Window */
      break;
   case RAWKEY:
      if (msg->Code==0x5F){     /* HELP key pressed */
        setwin (w, RMBTRAP, CLOSEWINDOW, title_HELP );
        displayhelp();
        setwin (w, 0, IDCMPFLAGS, (char *) -1 );
      }
      break;

   case MENUPICK:
      select=msg->Code;
      while (select != MENUNULL){
         menunum=MENUNUM(select);
         itemnum=ITEMNUM(select);
         subnum=SUBNUM(select);
         switch (menunum)  {
            case PROJECT:
               switch (itemnum){
                  case ABOUT:
                     setwin (w, RMBTRAP, CLOSEWINDOW, title_HELP );
                     displayhelp();
                     setwin (w, 0, IDCMPFLAGS, (char *) -1 );
                     break;
                  case MAP:
                     switch (subnum){
                        case FLAT:                    /* flat map */
                           setwin (w, RMBTRAP, CLOSEWINDOW, title_FLAT );
                           SetPointer (w, waiter, waiter_size/4-2, 16,
                                 waiter_x_offset, waiter_y_offset);
                           fullmap (map, FLAT, fill);
                           SetPointer (w, arrow, arrow_size/4-2, 16,
                           arrow_x_offset, arrow_y_offset);
                           setwin (w, 0, IDCMPFLAGS, (char *) -1 );
                           oldval = subnum;
                           break;
                        case MERCATOR:                /* Mercator map */
                           setwin (w, RMBTRAP, CLOSEWINDOW, title_MERCATOR );
                           SetPointer (w, waiter, waiter_size/4-2, 16,
                           waiter_x_offset, waiter_y_offset);
                           fullmap (map, MERCATOR, fill);
                           SetPointer (w, arrow, arrow_size/4-2, 16,
                           arrow_x_offset, arrow_y_offset);
                           setwin (w, 0, IDCMPFLAGS, (char *) -1 );
                           oldval = subnum;
                           break;
                        case BOX:                     /* box */
                           setwin (w, RMBTRAP, IDCMPFLAGS, drag_prompt );
                           if (oldval!=FLAT && oldval!=MERCATOR)  {
                              ModifyIDCMP (w, CLOSEWINDOW);
                              SetPointer (w, waiter, waiter_size/4-2, 16,
                              waiter_x_offset, waiter_y_offset);
                              fullmap (map, FLAT, fill);
                              ModifyIDCMP (w, IDCMPFLAGS);
                              oldval = FLAT;
                           }
                           SetPointer (w, cross, cross_size/4-2, 16,
                           cross_x_offset, cross_y_offset);
                           result = getbox (&x0, &y0, &x, &y);
                           SetPointer (w, arrow, arrow_size/4-2, 16,
                           arrow_x_offset, arrow_y_offset);
                           if (result!=OK)  {
                              setwin (w, 0, IDCMPFLAGS, box_error );
                              DisplayBeep(s);
                              break;
                           }
                           setwin (w, RMBTRAP, CLOSEWINDOW, title_BOX );
                           SetPointer (w, waiter, waiter_size/4-2, 16,
                           waiter_x_offset, waiter_y_offset);
                           getcoord (x0, y0, oldval, &lat[0], &lam[0]);
                           getcoord (x, y, oldval, &lat[1], &lam[1]);
                           /* Move (rp, 0, 0);
                           ClearScreen (rp);*/
                           SetRast(rp,BLUE);
                           box (map, lat, lam, fill);
                           SetPointer (w, arrow, arrow_size/4-2, 16,
                           arrow_x_offset, arrow_y_offset);
                           setwin (w, 0, IDCMPFLAGS, (char *) -1 );
                           oldval = subnum;
                           break;
                        default:
                           break;
                     }
                     break;
                  /* end of case MAP */
                  case SPHERE:
                     switch (subnum){
                        case ZOOM_IN-SPHEREOFFSET:                 /* zoom views */
                        case ZOOM_OUT-SPHEREOFFSET:
                           if (subnum==ZOOM_IN-SPHEREOFFSET)  {
                              view_height /= 2.;
                              if (view_height<MIN_HEIGHT)
                                    view_height = MIN_HEIGHT;
                              sprintf (title_ORBITAL, fmt_ZOOM_IN, view_height);
                           }
                           else  {
                              view_height *=2.;
                              sprintf (title_ORBITAL, fmt_ZOOM_OUT, view_height);
                           }
                           eta = view_height/RE;
                           facp = 1. + eta;
                           etap = 1./facp;
                        case GLOBE-SPHEREOFFSET:                 /* globe views */
                        case ORBITAL-SPHEREOFFSET:
                           setwin (w, RMBTRAP, IDCMPFLAGS, (char *)-1 );
                           if ( (subnum!=ZOOM_IN-SPHEREOFFSET && subnum!=ZOOM_OUT-SPHEREOFFSET) || (oldval!=ZOOM_IN && oldval!=ZOOM_OUT && oldval!=GLOBE   && oldval!=ORBITAL) )  {
                              SetWindowTitles (w, (char *) -1, press_prompt );
                              if (oldval!=FLAT && oldval!=MERCATOR)  {
                                 ModifyIDCMP (w, CLOSEWINDOW);
                                 SetPointer (w, waiter, waiter_size/4-2, 16,
                                             waiter_x_offset, waiter_y_offset);
                                 fullmap (map, FLAT, fill);
                                 ModifyIDCMP (w, IDCMPFLAGS);
                                 oldval = FLAT;
                              }
                              SetPointer (w, cross, cross_size/4-2, 16,
                                          cross_x_offset, cross_y_offset);
                              do  {
                                 WaitPort (w->UserPort);
                                 msgf = (struct IntuiMessage *) GetMsg (w->UserPort);
                                 if (msgf==NULL)
                                    continue;
                                 else if (msgf->Code== SELECTUP)
                                    break;
                                 ReplyMsg ((struct Message *)msgf);
                              } while (1);
                              x = msgf->MouseX;          /* get mouse position */
                              y = msgf->MouseY;
                              ReplyMsg ((struct Message *)msgf);
                              getcoord (x, y, oldval, &latg, &lamg);
                           }
                           if (subnum==ORBITAL-SPHEREOFFSET)  {       /* re-initialize values for */
                              view_height = VIEW_HEIGHT; /* orbital view          */
                              eta = view_height/RE;
                              facp = 1. + eta;
                              etap = 1./facp;
                              sprintf (title_ORBITAL, fmt_ORBITAL, view_height);
                              setwin (w, RMBTRAP, CLOSEWINDOW, title_ORBITAL );
                           }
                           else if (subnum==GLOBE-SPHEREOFFSET)
                              setwin (w, RMBTRAP, CLOSEWINDOW, title_GLOBE );
                           else
                              setwin (w, RMBTRAP, CLOSEWINDOW, title_ORBITAL);
                           ModifyIDCMP (w, CLOSEWINDOW);
                           SetPointer (w, waiter, waiter_size/4-2, 16,
                                       waiter_x_offset, waiter_y_offset);
                           /* Move (rp, 0, 0);
                           ClearScreen (rp); crashes after do_text !*/
                           SetRast (rp,BLACK);
                           SetAPen (rp, BLUE);        /* blue globe */
                           DrawEllipse (rp, CENTERX, CENTERY, HRADIUS, VRADIUS);
                           Flood (rp, 1, CENTERX, CENTERY);
                           SetAPen (rp, ORANGE);      /* reset colors */
                           SetBPen (rp, BLUE);
                           globe (map, map_trig, latg, lamg, subnum+SPHEREOFFSET, fill); /* draw map */
                           stars();
                           SetPointer (w, arrow, arrow_size/4-2, 16,
                                       arrow_x_offset, arrow_y_offset);
                           setwin (w, 0, IDCMPFLAGS, (char *) -1 );
                           oldval = subnum+SPHEREOFFSET ;
                           break;
                        default:
                           break;
                    }
                    break;
                  case SAVE:
                  case SAVEAS:
                     /* number of screens saved yet */

                     if (itemnum==SAVE){
                        if (picnum<999){ picnum++; } else { picnum=0; }
                        if ( lenghtpicname < (MAXLENGHT-4) ){
                            sprintf( picname+lenghtpicname ,".%03d",picnum);
                            /* prints number into namestring */
                        }
                        else{
                            setwin (w, 0, IDCMPFLAGS, SAVE_error );
                            DisplayBeep(s);
                        }
                     }
                     else{
                        setwin (w, RMBTRAP, CLOSEWINDOW, SAVEAS_wait );
                        lenghtpicname=saveas(&picname[0]);
                        if (lenghtpicname==NULL || lenghtpicname > MAXLENGHT ){
                            lenghtpicname=strlen(picname); /* old picname unchanged*/
                            setwin (w, 0, IDCMPFLAGS, SAVE_error );
                            DisplayBeep(s);
                            break;
                        }
                     }

                     setwin (w, RMBTRAP, CLOSEWINDOW, SAVE_wait );
                     SetPointer (w, waiter, waiter_size/4-2, 16,
                           waiter_x_offset, waiter_y_offset);
                     if (save(&picname[0])!=OK){
                        setwin (w, 0, IDCMPFLAGS, SAVE_error );
                        DisplayBeep(s);
                     }
                     else{
                        setwin (w, 0, IDCMPFLAGS, title_SAVE );
                     }
                     if (itemnum==SAVE){     /* cut number of saved screen */
                        *(picname+lenghtpicname)='\0';
                     }

                     SetPointer (w, arrow, arrow_size/4-2, 16,
                           arrow_x_offset, arrow_y_offset);
                     break;
                  case PRINT:
                     setwin (w, RMBTRAP, CLOSEWINDOW, PRINT_wait );
                     SetPointer (w, waiter, waiter_size/4-2, 16,
                           waiter_x_offset, waiter_y_offset);
                     if(dump(wt)!=OK){
                        setwin (w, 0, IDCMPFLAGS, PRINT_error );
                        DisplayBeep(s);
                     }
                     else{
                        setwin (w, 0, IDCMPFLAGS, title_PRINT );
                     }
                     SetPointer (w, arrow, arrow_size/4-2, 16,
                           arrow_x_offset, arrow_y_offset);

                     Forbid();
                     if (IntuitionBase->ActiveWindow==wt){
                        ActivateWindow(w);
                        /* ... because titlebar window has been activated
                           and all IDCMP Messages are eaten by dump() */
                     }
                     Permit();

                     break;
                  case GRID:
                     if (oldval!=FLAT     && oldval!=MERCATOR &&
                            oldval!=GLOBE    && oldval!=ORBITAL  &&
                            oldval!=ZOOM_IN  && oldval!=ZOOM_OUT){
                        SetWindowTitles (w, (char *) -1, grid_error );
                        DisplayBeep(s);
                     }

                     else  {
                        setwin (w, RMBTRAP , CLOSEWINDOW, title_GRID );
                        SetPointer (w, waiter, waiter_size/4-2, 16,
                                    waiter_x_offset, waiter_y_offset);
                        grid (oldval, latg, lamg);
                        SetPointer (w, arrow, arrow_size/4-2, 16,
                                 arrow_x_offset, arrow_y_offset);
                        setwin (w, 0, IDCMPFLAGS, (char *) -1 );
                     }
                     break;
                  case CLEAR:                  /* clear screen */
                     SetWindowTitles (w,(char *) -1, title_CLEARS);
                     /* Move (rp, 0, 0);
                     ClearScreen (rp); */
                     SetRast(rp,BLUE);
                     oldval = -1;
                     break;
                  case QUIT:
                     ReplyMsg((struct Message *)msg);
                     return(NOT_OK);
                     break;
                  default:
                     break;
               }
               break;
            case EDIT:
               switch (itemnum){
                  case COLOR_F:                 /* toggle color-fill flag */
                     flag=((struct MenuItem *) ItemAddress(&Menu1, (LONG) select))->Flags;
                     if (flag & CHECKED)
                        fill = FILL;
                     else
                        fill = NOFILL;
                     break;
                  case COLOR:
                     activepen=subnum; /* Set Active Edit Pen */
                     break;
                  case DRAW:
                     setwin (w, RMBTRAP, IDCMPFLAGS, draw_wait );
                     SetPointer (w, cross, cross_size/4-2, 16,
                                 cross_x_offset, cross_y_offset);
                     drawline(activepen);
                     SetPointer (w, arrow, arrow_size/4-2, 16,
                                 arrow_x_offset, arrow_y_offset);
                     setwin (w, 0, IDCMPFLAGS, title_DRAW );
                     break;
                  case FLOOD:                   /* flood fill */
                     setwin (w, RMBTRAP, MOUSEBUTTONS, flood_wait );
                     SetPointer (w, cross, cross_size/4-2, 16,
                                 cross_x_offset, cross_y_offset);
                     floodfill (activepen);
                     SetPointer (w, arrow, arrow_size/4-2, 16,
                                 arrow_x_offset, arrow_y_offset);
                     setwin (w, 0, IDCMPFLAGS, title_FLOOD );
                     break;
                  case TEXT:                    /* get user text */
                     setwin (w, RMBTRAP, IDCMPFLAGS, title_TEXT);
                     do_text (msg, activepen);
                     setwin (w, 0, IDCMPFLAGS, title_TEXT );
                     break;
                  case COLORPALETTE:                  /* modify color table */
                     SetWindowTitles (w, (char *) -1, title_COLORS );
                     color_offset += 4;
                     if (color_offset>=num_colors)
                        color_offset = 0;
                     LoadRGB4 (vp, &mapcolors[color_offset], 4);
                     break;
                  default:
                     break;
               }
               break;
            case SPECIAL:
               switch (itemnum){
                  case SHADOW:                  /* make shadows */
                     setwin (w, RMBTRAP, CLOSEWINDOW, title_SHADOW );
                     SetPointer (w, waiter, waiter_size/4-2, 16,
                                 waiter_x_offset, waiter_y_offset);
                     shadow ();
                     SetPointer (w, arrow, arrow_size/4-2, 16,
                                 arrow_x_offset, arrow_y_offset);
                     setwin (w, 0, IDCMPFLAGS, (char *) -1 );
                     break;
                  default:
                     break;
               }
               break;
            default:
               break;
         }
         select=((struct MenuItem *) ItemAddress(&Menu1, (LONG) select))->NextSelect;
      } /* end of while */
   /* end of case MENUPICK */
   default:
      break;
   } /* end of switch (class) */
   ReplyMsg((struct Message *)msg);
   return (OK);
}


/* ============================================================= */

void fullmap (ws, type, fill)          /* draws flat map projections */

short *ws;
int type, fill;

{

   extern void afill(), adraw(), plotpoint();
   int j, i, k, h1, h2, narea;
   double t;
   long pen;
   short np, xs, ys;

   /* Move (rp, 0, 0);                    * clear screen *
   ClearScreen (rp); */
   SetRast(rp,BLUE);
   j = 0;
   np = 0;
   narea = 0;
   pen = ORANGE;
   SetAPen (rp, pen);
   for (i=0; i<MAXVAL; i+=2)  {
      if (ws[i]==0 && ws[i+1]==0)  {   /* check for end of area */
         ++narea;
         pen = ORANGE;
         for (k=0; k<num_lakes; ++k)  {
            if (narea==lakes[k])  {
               pen = BLUE;
               break;
            }
         }
         SetAPen (rp, pen);
         if (np<=1)  {
            xs = CENTERX + area[j-2];
            ys = CENTERY + area[j-1];
            plotpoint (xs, ys);
         }
         else  {
            if (fill==FILL)
               afill (np, pen);
            else
               adraw (np);
         }
         j = 0;
         np = 0;
         area[0] = 0;
         area[1] = 0;
         pen = ORANGE;
         SetAPen (rp, pen);
      }
      else  {                          /* get coords of new point */
         t = ws[i];                    /* y = latitude */
         if (type==FLAT)
            t = (t/100.) * VFACTOR;
         else if (type==MERCATOR)  {
            t = (t/200. + 45.) * rad;
            t = log (tan (t)) * M_VFACTOR;
         }
         if (t<0.)
            t -= 0.5;
         else
            t += 0.5;
         h2 = -t;
         t = ws[i+1];                  /* x = longitude */
         t = (t/100.) * HFACTOR;
         if (t<0.)
            t -= 0.5;
         else
            t += 0.5;
         h1 = t;
         if (np!=0)  {                 /* disallow identical adjacent pts */
            if (h1==area[j-2] && h2==area[j-1])
               continue;
         }
         xs = CENTERX + h1;
         ys = CENTERY + h2;
         plotpoint (xs, ys);
         area[j] = h1;
         area[j+1] = h2;
         j += 2;
         ++np;
      }
   }
   if (np>0)  {                        /* check for last area */
      pen = ORANGE;
      SetAPen (rp, pen);
      if (np==1)  {
         xs = CENTERX + area[j-2];
         ys = CENTERY + area[j-1];
         plotpoint (xs, ys);
      }
      else  {
         if (fill==FILL)
            afill (np, pen);
         else
            adraw (np);
      }
   }
   SetAPen (rp, ORANGE);
}

/* ============================================================= */

void grid (val, lat0, lam0)            /* controls drawing of grids */

long val;
double lat0, lam0;

{

   extern void globe_grid();
   long oldpen, h1;
   double lam, lat;
   static double lat_interval = 20.;
   static double lam_interval = 30.;

   oldpen = rp->FgPen;                 /* save original pen color */
   if (val!=FLAT && val!=MERCATOR)     /* draw grid for globe     */
      globe_grid (val, lat0, lam0);
   else  {                             /* otherwise grid for flat */
                                       /*   or Mercator map       */
      SetAPen (rp, BLACK);             /* set grid color to black */
      for (lam=-180.; lam<=+180.; lam += lam_interval)  {
         h1 = lam*HFACTOR + CENTERX;
         Move (rp, h1, 0);
         Draw (rp, h1, WHEIGHT-1);
      }
      for (lat=80.; lat>=-80.; lat -= lat_interval)  {
         if (val==FLAT)
            h1 = -lat*VFACTOR;
         else
            h1 = -log (tan((lat/2.+45.)*rad)) * M_VFACTOR;
         h1 += CENTERY;
         Move (rp, 0, h1);
         Draw (rp, WWIDTH-1, h1);
      }
      SetAPen (rp, WHITE);             /* draw coordinate axes in white */
      Move (rp, CENTERX, 0);
      Draw (rp, CENTERX, WHEIGHT-1);
      Move (rp, 0, CENTERY);
      Draw (rp, WWIDTH-1, CENTERY);
   }
   SetAPen (rp, oldpen);               /* restore pen color */
}

/* ============================================================= */

void globe_grid (val, lat0, lam0)      /* controls drawing globe grid */

double lat0, lam0;
long val;

{

   extern void globe_grid_plot();
   extern int limit_lam(), limit_lat();
   double lat, lam, c0, s0, c1, s1, c2, s2, rlam, rlat;
   double hp, scale, fac3, dlat, dlam, ddelt;
   double lamp[2], latp[2];
   int k;
   char first;
   static double lat_interval = 20.;
   static double lam_interval = 30.;
   static double delta = 5.;

   lat0 *= rad;
   c0 = cos (lat0);
   s0 = sin (lat0);
   dlat = lat_interval;
   dlam = lam_interval;
   ddelt = delta;
   if (val==GLOBE)  {                  /* ordinary globe view */
      hp = 0.;
      scale = 1.;
      fac3 = 1.;
   }
   else  {                             /* orbital view */
      hp = etap;
      scale = sqrt (1.-etap*etap);
      fac3 = (facp/(facp-hp)) * scale;
      if (view_height<=1200.)  {
         dlat /= 4.;
         dlam /= 4.;
         ddelt /= 5.;
      }
   }
   SetAPen (rp, BLACK);                /* grid lines in black */
   for (lat=80.; lat>=-80.; lat-=dlat)  {  /* lines of equal latitude */
      rlat = lat*rad;
      if ((k=limit_lam (&lamp[0], rlat, lat0, hp))!=OK)
         continue;                     /* skip if entirely out of view */
      lamp[0] += lam0;
      lamp[1] += lam0;
      k = lamp[0]/ddelt - 1.;          /* express limits as multiple */
      lamp[0] = k*ddelt;               /*   of ddelt                 */
      k = lamp[1]/ddelt + 1.;
      lamp[1] = k*ddelt;
      c1 = cos (rlat);
      s1 = sin (rlat);
      first = TRUE;
      if (lat==0.)
         SetAPen (rp, WHITE);          /* draw equator in white */
      for (lam=lamp[0]; lam<=lamp[1]; lam+=ddelt)  {
         rlam = (lam-lam0)*rad;
         if (rlam<-pi)
            rlam += twopi;
         if (rlam>+pi)
            rlam -= twopi;
         c2 = cos (rlam);
         s2 = sin (rlam);
         globe_grid_plot (rlat, rlam, c0, s0, c1, s1, c2, s2,
                          val, hp, scale, fac3, &first);
      }
      if (lat==0.)
         SetAPen (rp, BLACK);          /* reset pen to black */
   }
   for (lam=-180.; lam<+180.; lam+=dlam)  {  /* meridian circles */
      rlam = (lam-lam0)*rad;
      if (rlam<-pi)
         rlam += twopi;
      if (rlam>+pi)
         rlam -= twopi;
      if ((k=limit_lat (&latp[0], lat0, rlam, hp))!=OK)
         continue;                     /* skip if entirely out of view */
      k = latp[0]/ddelt + 1.;          /* express limits as multiple */
      latp[0] = k*ddelt;               /*   of ddelt                 */
      k = latp[1]/ddelt - 1;
      latp[1] = k*ddelt;
      if (latp[0]>=90.)                /* exclude North polar point */
         latp[0] = 90. - ddelt;
      if (latp[1]<=-90.)               /* exclude South polar point */
         latp[1] = -90. + ddelt;
      c2 = cos (rlam);
      s2 = sin (rlam);
      first = TRUE;
      if (lam==0. || lam==-180.)       /* prime meridian in white */
         SetAPen (rp, WHITE);
      for (lat=latp[0]; lat>=latp[1]; lat-=ddelt)  {
         rlat = lat*rad;
         c1 = cos (rlat);
         s1 = sin (rlat);
         globe_grid_plot (rlat, rlam, c0, s0, c1, s1, c2, s2,
                          val, hp, scale, fac3, &first);
      }
      if (lam==0. || lam==-180.)
         SetAPen (rp, BLACK);          /* reset pen to black */
   }
}

/* ============================================================= */

void globe_grid_plot (lat, lam, c0, s0, c1, s1, c2, s2,
                      val, hp, scale, fac3, first)

double lat, lam, c0, s0, c1, s1, c2, s2;   /* draws globe grids */
long val;
double hp, scale, fac3;
char *first;

{

   extern void plotpoint(), globe_rim_fix();
   char in_view;
   short h1, h1c;                      /* x-dist. (pix) from center */
   short h2, h2c;                      /* y-dist. (pix) from center */
   long x, y;
   double lamc, dlam;                  /* longitude */
   double latc, dlat;                  /* latitude  */
   double zp, facz, h1d, h2d, fac2;
   static char prev_in_view;
   static short h1prev, h2prev;
   static double latprev, lamprev, zpprev;

   in_view = FALSE;                    /* get status of current point */
   zp = s1*s0 + c1*c0*c2;
   if (zp>=hp)  {                      /* zp > hp => in view */
      in_view = TRUE;
      h1d = HRADIUS * c1 * s2;
      h2d = -VRADIUS * (s1*c0 - c1*s0*c2);
      if (val!=GLOBE)  {
         fac2 = (facp/(facp-zp))*scale;
         h1d *= fac2;
         h2d *= fac2;
      }
      h1 = h1d;
      h2 = h2d;
   }
   if (*first==TRUE)  {                /* get status of first point */
      *first = FALSE;
      if (in_view==TRUE)  {            /* if first point is in view, */
         x = h1 + CENTERX;             /*   move pen to first point  */
         y = h2 + CENTERY;             /*   and plot it              */
         Move (rp, x, y);
         plotpoint (x, y);
         h1prev = h1;
         h2prev = h2;
      }
      prev_in_view = in_view;          /* save status of first point */
      latprev = lat;
      lamprev = lam;
      zpprev = zp;
      return;
   }
   if (in_view==TRUE)  {               /* if current point is in view, */
      if (prev_in_view==FALSE)  {      /*   but previous point was not */
         facz = zp / (zpprev-zp);      /*   in view, get rim point by  */
         latc = lat - (latprev-lat)*facz; /* linear interpolation      */
         lamc = lam - (lamprev-lam)*facz;
         dlat = fabs (lat-latprev);
         dlam = fabs (lam-lamprev);
         if ( fabs (latc-latprev)> dlat || /* if rim point not between */
              fabs (latc-lat)    > dlat)   /*   current and previous   */
            latc = (lat+latprev)/2.;       /*   points, use midpoint   */
         if ( fabs (lamc-lamprev)> dlam ||
              fabs (lamc-lam)    > dlam )
            lamc = (lam+lamprev)/2.;
         c1 = cos (latc);
         h1d = HRADIUS * c1 * sin (lamc);
         h2d = -VRADIUS * (sin (latc)*c0 - c1*s0*cos (lamc));
         if (val!=GLOBE)  {
            h1d *= fac3;
            h2d *= fac3;
         }
         h1c = h1d;
         h2c = h2d;
         globe_rim_fix (&h1c, &h2c);
         x = h1c + CENTERX;            /* move to rim point & plot it */
         y = h2c + CENTERY;
         Move (rp, x, y);
         plotpoint (x, y);
         h1prev = h1c;
         h2prev = h2c;
      }
      if (h1!=h1prev || h2!=h2prev)  {
         x = h1 + CENTERX;             /* draw to current point */
         y = h2 + CENTERY;
         Draw (rp, x, y);
      }
      h1prev = h1;
      h2prev = h2;
   }
   else  {                             /* current point is out of view   */
      if (prev_in_view==TRUE)  {       /* if previous point was in view, */
         facz = zp / (zpprev-zp);      /*   get rim point by linear      */
         latc = lat - (latprev-lat)*facz; /* interpolation               */
         lamc = lam - (lamprev-lam)*facz;
         dlat = fabs (lat-latprev);
         dlam = fabs (lam-lamprev);
         if ( fabs (latc-latprev)> dlat || /* if rim point not between */
              fabs (latc-lat)    > dlat)   /*   current and previous   */
            latc = (lat+latprev)/2.;       /*   points, use midpoint   */
         if ( fabs (lamc-lamprev)> dlam ||
              fabs (lamc-lam)    > dlam )
            lamc = (lam+lamprev)/2.;
         c1 = cos (latc);
         h1d = HRADIUS * c1 * sin (lamc);
         h2d = -VRADIUS * (c0*sin (latc) - c1*s0 * cos (lamc));
         if (val!=GLOBE)  {
            h1d *= fac3;
            h2d *= fac3;
         }
         h1c = h1d;
         h2c = h2d;
         globe_rim_fix (&h1c, &h2c);
         x = h1c + CENTERX;            /* draw to rim point */
         y = h2c + CENTERY;
         Draw (rp, x, y);
      }
   }
   prev_in_view = in_view;             /* save status of current point */
   latprev = lat;
   lamprev = lam;
   zpprev = zp;
}

/* ============================================================= */

int limit_lam (lam, lat, lat0, etap)   /* computes limits on longitude */
                                       /*   for constant latitude      */
double *lam, lat, lat0, etap;

{
   double alpha;
   alpha = (etap-sin(lat)*sin(lat0)) / (cos(lat)*cos(lat0)+0.00000001);
                 /* +0.00..01 prevents GURU 5 crashes (divide by zero) */
   if (alpha<=-1.)  {                  /* negative => lamda covers */
      lam[0] = -180.;                  /*   entire hemisphere      */
      lam[1] = +180.;
      return (OK);
   }
   else if (alpha>=+1.)                /* positive => nothing in view */
      return (NOT_OK);
   else  {                             /* otherwise, compute limits */
      lam[0] = -acos (alpha)/rad;
      lam[1] = -lam[0];
      return (OK);
   }
}

/* ============================================================= */

int limit_lat (lat, lat0, lam, etap)   /* computes limits on latitude */
                                       /*   for constant longitude    */
double *lat, lat0, lam, etap;

{
   double radical, a, b, sum, fac1;

   a = sin (lat0);
   b = cos (lat0) * cos (lam);
   sum = a*a + b*b;
   radical = sum - etap*etap;
   if (radical<=0.)                    /* no real solutions */
      return (NOT_OK);
   else  {                             /* two real solutions      */
      radical = sqrt (radical);        /* solve quadrtic equation */
      fac1 = (a*etap + b*radical)/sum;
      lat[0] = asin (fac1)/rad;
      fac1 = (a*etap - b*radical)/sum;
      lat[1] = asin (fac1)/rad;
      if (lat[0]<lat[1])  {            /* put in correct order */
         b = lat[0];
         lat[0] = lat[1];
         lat[1] = b;
      }
      if (a>etap)                      /* check North pole */
         lat[0] = 90.;
      if (a<-etap)                     /* check South pole */
         lat[1] = -90.;
      return (OK);
   }
}

/* ============================================================= */

void getcoord (x, y, val, lat, lam)    /* converts screen coordinates   */
                                       /*   into latitude and longitude */
int x, y;
long val;
double *lat, *lam;

{

   (*lam) = (x - CENTERX) / HFACTOR;
   if (val==FLAT)
      (*lat) = (CENTERY - y) / VFACTOR;
   else
      (*lat) = -90. + 2.*atan(exp((CENTERY-y)/M_VFACTOR))/rad;
}

/* ============================================================= */

void globe (ws, ws_trig, lat0, lam0, val, fill) /* draws globe projections */

short *ws, *ws_trig;
double lat0, lam0;
long val;
int fill;

{

   extern void plotpoint(), globe_fill(), globe_rim_fix(), globe_tidy();
   char first, prev_in_view, in_view, latzero;
   short h1, h1c, h1prev;              /* x-dist. (pix) from center */
   short h2, h2c, h2prev;              /* y-dist. (pix) from center */
   short np, narea,nrim_in, nrim_out;
   short xs, ys;
   int i, j;
   long x, y, pen, first_color;
   double lam, lamc, lamprev;          /* longitude */
   double lat, latc, latprev;          /* latitude  */
   double c0, s0, c1, s1, c2, zp, zpprev;
   double hp, fac2, fac3, facz, scale;
   double h1d, h2d, dlat, dlam, lat0p;
   static double fac = 1./32767.0;

   latzero = FALSE;
   if (val==GLOBE)  {                  /* ordinary globe view */
      hp = 0.;
      scale = 1.;
      fac3 = 1.;
   }
   else  {                             /* orbital globe view */
      hp = etap;
      scale = sqrt (1.-etap*etap);
      fac3 = (facp/(facp-hp)) * scale;
   }
   if (lat0==0.)  {
      c0 = 1.;
      s0 = 0.;
      if (val==GLOBE)
         latzero = TRUE;               /* equatorial, ordinary globe view */
   }
   else  {
      lat0p = lat0 * rad;
      c0 = cos (lat0p);
      s0 = sin (lat0p);
   }
   first = TRUE;
   pen = ORANGE;
   SetAPen (rp, pen);
   first_color = BLACK;
   j = 0;
   np = 0;
   narea = 0;
   nrim_in = 0;
   nrim_out = 0;
   for (i=0; i<MAXVAL; i+=2)  {
      if (ws[i]==0 && ws[i+1]==0)  {   /* if end of area, then     */
         ++narea;                      /*   color-fill and skip to */
         first = TRUE;                 /*    next area             */
         if (np>0 && fill==FILL)
            globe_fill (np, narea, nrim_in, nrim_out, first_color);
         j = 0;
         np = 0;
         nrim_in = 0;
         nrim_out = 0;
         first_color = BLACK;
         continue;
      }
      lat = ws[i];                     /* latitude */
      lat = (lat/100.) * rad;
      lam = ws[i+1];                   /* longitude */
      lam = (lam/100. - lam0) * rad;
      if (lam<-pi)
         lam += twopi;
      if (lam>pi)
         lam -= twopi;
      c1 = ws_trig[i];                 /* cosine of latitude */
      c1 *= fac;
      s1 = ws_trig[i+1];               /* sine of latitude */
      s1 *= fac;
      in_view = FALSE;                 /* get status of current point */
      if (latzero==TRUE)  {            /* equatorial globe view */
         zp = c1*cos (lam);
         if (lam>=-pi2 && lam<=+pi2)  {
            in_view = TRUE;
            h1 = HRADIUS * c1 * sin (lam);
            h2 = -VRADIUS * s1;
         }
      }
      else  {                          /* oblique earth view */
         c2 = cos (lam);
         zp = s1*s0 + c1*c0*c2;
         if (zp>=hp)  {                /* zp > hp => in view */
            in_view = TRUE;
            h1d = HRADIUS * c1 * sin (lam);
            h2d = -VRADIUS * (s1*c0 -c1*s0*c2);
            if (val!=GLOBE)  {
               fac2 = (facp/(facp-zp)) * scale;
               h1d *= fac2;
               h2d *= fac2;
            }
            h1 = h1d;
            h2 = h2d;
         }
      }
      if (first==TRUE)  {              /* get status of first point */
         first = FALSE;
         if (in_view==TRUE)  {         /* if first point is in view, */
            x = h1 + CENTERX;          /*   move pen to first point  */
            y = h2 + CENTERY;          /*   and plot it              */
            Move (rp, x, y);
            first_color = ReadPixel (rp, x, y);
            xs = x;
            ys = y;
            plotpoint (xs, ys);
            h1prev = h1;
            h2prev = h2;
            area[0] = h1;              /* save first point for later use */
            area[1] = h2;
            j = 2;
            np = 1;
         }
         prev_in_view = in_view;       /* save status of first point */
         latprev = lat;
         lamprev = lam;
         zpprev = zp;
         continue;
      }
      if (in_view==TRUE)  {            /* if current point is in view, */
         if (prev_in_view==FALSE)  {   /*   but previous point was not */
            facz = zp / (zpprev-zp);   /*   in view, get rim point by  */
            latc = lat - (latprev-lat)*facz; /* linear interpolation   */
            lamc = lam - (lamprev-lam)*facz;
            dlat = fabs (lat-latprev);
            dlam = fabs (lam-lamprev);
            if ( fabs (latc-latprev)> dlat || /* if rim point not between */
                 fabs (latc-lat)    > dlat)   /*   current and previous   */
               latc = (lat+latprev)/2.;       /*   point, use midpoint    */
            if ( fabs (lamc-lamprev)> dlam ||
                 fabs (lamc-lam)    > dlam )
               lamc = (lam+lamprev)/2.;
            if (latzero==TRUE)  {
               h1c = HRADIUS * cos (latc) * sin (lamc);
               h2c = -VRADIUS * sin (latc);
            }
            else  {
               c1 = cos (latc);
               h1d = HRADIUS * c1 * sin (lamc);
               h2d = -VRADIUS * (sin (latc)*c0 - c1*s0*cos (lamc));
               if (val!=GLOBE)  {
                  h1d *= fac3;
                  h2d *= fac3;
               }
               h1c = h1d;
               h2c = h2d;
            }
            globe_rim_fix (&h1c, &h2c); /* correct the computed rim point */
            x = h1c + CENTERX;         /* move to rim point & plot it */
            y = h2c + CENTERY;
            Move (rp, x, y);
            xs = x;
            ys = y;
            plotpoint (xs, ys);
            h1prev = h1c;
            h2prev = h2c;
            area[j] = h1;              /* save coords of rim point */
            area[j+1] = h2;
            j += 2;
            ++nrim_in;
            ++np;
         }
         if (h1!=h1prev || h2!=h2prev)  {
            x = h1 + CENTERX;          /* draw to current point */
            y = h2 + CENTERY;
            Draw (rp, x, y);
            area[j] = h1;              /* save coords of current point */
            area[j+1] = h2;
            j += 2;
            ++np;
         }
         h1prev = h1;
         h2prev = h2;
      }
      else  {                          /* current point is out of view   */
         if (prev_in_view==TRUE)  {    /* if previous point was in view, */
            facz = zp / (zpprev-zp);   /*   get rim point by linear      */
            latc = lat - (latprev-lat)*facz; /* interpolation            */
            lamc = lam - (lamprev-lam)*facz;
            dlat = fabs (lat-latprev);
            dlam = fabs (lam-lamprev);
            if ( fabs (latc-latprev)> dlat || /* if rim point not between */
                 fabs (latc-lat)    > dlat)   /*   current and previous   */
               latc = (lat+latprev)/2.;       /*   point, use midpoint    */
            if ( fabs (lamc-lamprev)> dlam ||
                 fabs (lamc-lam)    > dlam )
               lamc = (lam+lamprev)/2.;
            if (latzero==TRUE)  {
               h1c = HRADIUS * cos (latc) * sin (lamc);
               h2c = -VRADIUS * sin (latc);
            }
            else  {
               c1 = cos (latc);
               h1d = HRADIUS * c1 * sin (lamc);
               h2d = -VRADIUS * (c0*sin(latc) - c1*s0 * cos(lamc));
               if (val!=GLOBE)  {
                  h1d *= fac3;
                  h2d *= fac3;
               }
               h1c = h1d;
               h2c = h2d;
            }
            globe_rim_fix (&h1c, &h2c); /* correct the computed rim point */
            x = h1c + CENTERX;         /* draw to rim point */
            y = h2c + CENTERY;
            Draw (rp, x, y);
            area[j] = h1;              /* save coords of rim point */
            area[j+1] = h2;
            j += 2;
            ++nrim_out;
            ++np;
         }
      }
      prev_in_view = in_view;          /* save status of current point */
      latprev = lat;
      lamprev = lam;
      zpprev = zp;
   }
   if (fill == FILL)
      globe_tidy (td, td_trig, lat0, lam0, val);
}

/* ============================================================= */

void globe_fill (np, narea, nrim_in, nrim_out, first_color)
                                       /* fills area on globe */

short np, narea, nrim_in, nrim_out;
long first_color;

{

   extern void plotpoint ();
   int k;
   short xs, ys;
   char is_lake;
   static long pen = ORANGE;

   if (nrim_in!=nrim_out)
      return;
   if (nrim_in==0)  {                  /* fill areas with no rim points */
      is_lake = FALSE;
      for (k=0; k<num_lakes; ++k)      /* check for lake */
         if (narea==lakes[k])  {
            if (first_color==ORANGE)  {
               pen = BLUE;             /* make lake blue if drawn */
               is_lake = TRUE;         /*   into orange           */
               break;
            }
            else                       /* don't color-fill if drawn */
               return;                 /*   into blue               */
         }
      xs = CENTERX + area[0];
      ys = CENTERY + area[1];
      if (np==1)
         plotpoint (xs, ys);
      else if (np>=GLOBE_FILL_MIN)
         afill (np, pen);
      if (is_lake==TRUE)
         pen = ORANGE;
   }
}

/* ============================================================= */

void globe_rim_fix (h1, h2)            /* find nearest actual rim point */

short *h1, *h2;

{

   short inc1, inc2;
   int i;
   long x, y, color;
   static int itmax = 20;

   if ((*h1)>=0)                       /* right half */
      inc1 = +1;
   else                                /* left half */
      inc1 = -1;
   if ((*h2)>=0)                       /* bottom half */
      inc2 = +1;
   else                                /* top half */
      inc2 = -1;
   x = (*h1) + CENTERX + 5*inc1;       /* coords of test pixel */
   y = (*h2) + CENTERY + 5*inc2;
   for (i=0; i<itmax; ++i)  {          /* look for nearest black pixel */
      if ((color = ReadPixel (rp, x, y))==BLACK)
         break;
      x += inc1;
      y += inc2;
   }
   x -= inc1;
   y -= inc2;
   for (i=0; i<itmax; ++i)  {          /* look back for previous blue one */
      if ((color = ReadPixel (rp, x, y))==BLUE || color==ORANGE)
         break;
      x -= inc1;
      y -= inc2;
   }
   (*h1) = x - CENTERX;
   (*h2) = y - CENTERY;
}

/* ============================================================= */

void globe_tidy (td, td_trig, lat0, lam0, val)

short *td, *td_trig;                   /* color-fills partially-drawn */
double lat0, lam0;                     /*   regions                    */
long val;

{

   int i;
   double lat, lam, c0, s0, c1, s1, c2;
   double zp, hp, scale, fac2, fac3, h1d, h2d;
   short h1, h2;
   long x, y, color;
   static double fac = 1./32767.0;

   if (val==GLOBE)  {                  /* ordinary globe view */
      hp = 0.;
      scale = 1.;
      fac3 = 1.;
   }
   else  {                             /* orbital globe view */
      hp = etap;
      scale = sqrt (1.-etap*etap);
      fac3 = (facp/(facp-hp)) * scale;
   }
   lat0 *= rad;
   c0 = cos (lat0);
   s0 = sin (lat0);
   i = 0;
   while (1)  {
      if (td[i]==0 && td[i+1]==0)      /* check for end of array */
         break;
      lat = td[i];                     /* latitude */
      lat = (lat/100.) * rad;
      lam = td[i+1];                   /* longitude */
      lam = (lam/100.-lam0) * rad;
      if (lam<-pi)
         lam += twopi;
      if (lam>pi)
         lam -= twopi;
      c1 = td_trig[i];
      c1 *= fac;
      s1 = td_trig[i+1];
      s1 *= fac;
      c2 = cos (lam);
      zp = s1*s0 + c1*c0*c2;
      if (zp>=hp)  {                   /* in view, so get screen coords */
         h1d = HRADIUS * c1 * sin (lam);
         h2d = -VRADIUS * (s1*c0-c1*s0*c2);
         if (val!=GLOBE)  {            /* orbital view */
            fac2 = (facp/(facp-zp)) * scale;
            h1d *= fac2;
            h2d *= fac2;
         }
         h1 = h1d;                     /* flood fill */
         h2 = h2d;
         x = h1 + CENTERX;
         y = h2 + CENTERY;
         if ((color = ReadPixel (rp, x, y)) == BLUE)
            Flood (rp, 1, x, y);
      }
      i += 2;
   }
}

 /* ============================================================= */

void stars ()            /* draws stars into black background */
{
   static int nmax = 150;
   unsigned int t;
   short x, y;
   int nstars;
   long oldpen;

   oldpen = rp->FgPen;
   SetAPen (rp, WHITE);
   nstars = 0;
   do  {
      t = rand();       /* Random number: Range 0 to INT_MAX on Lattice, 0 to 32768 on Aztec */
      x = t % WWIDTH + 1;
      t = rand();
      y = t % WHEIGHT + 1;
/*      if (x<0)        * no need for this in a WINDOW *
         x = 0;
      if (x>WWIDTH-1)
         x = WWIDTH-1;
      if (y<0)
         y = 0;
      if (y>WHEIGHT-1)
         y = WHEIGHT-1; */
      if (ReadPixel (rp, x, y) == BLACK)  {
         WritePixel (rp, x, y);
         ++nstars;
      }
   } while (nstars<=nmax);
   SetAPen (rp, oldpen);
}

/* ============================================================= */

void floodfill (color)                      /* flood fills an area based */
short color;                                       /*   on mouse position       */
{
   struct IntuiMessage *msgf;
   short x, y, oldpen;

   while (1)  {
      WaitPort (w->UserPort);             /* wait for message */
      msgf = (struct IntuiMessage *) GetMsg (w->UserPort);
      if (msgf==NULL)
         continue;
      else if (msgf->Code==SELECTDOWN){
            x = msgf->MouseX;                   /*  get mouse coordinates  */
            y = msgf->MouseY;                   /*    and flood fill       */
            ReplyMsg( (struct Message *) msgf);
            oldpen=rp->FgPen;
            SetPointer (w, waiter, waiter_size/4-2, 16, waiter_x_offset, waiter_y_offset);
            SetAPen(rp,color);
            Flood (rp, 1, x, y);
            SetAPen(rp,oldpen);
            SetPointer (w, arrow, arrow_size/4-2, 16,arrow_x_offset, arrow_y_offset);
            break;
      }
      else if (msgf->Code==MENUDOWN){
            ReplyMsg((struct Message *) msgf);
            return;                         /* Return if RIGHT button pressed*/
      }
      else{
            ReplyMsg((struct Message *) msgf);  /* unknown message */
      }
   }
}

/* ============================================================= */

void shadow ()                         /* makes shadowed screens */

{
   int modb0, modb1, color0, color1;
   int bcolor0, bcolor1;
   int j, k, k2, m, bitlast;
   unsigned int byte0, byte1;
   unsigned int byte0b0, byte1b0, byte0b1, byte1b1;
   long color;
   static int blackcolor0, blackcolor1, disp;
   static int bluecolor0, bluecolor1, Ocolor0, Ocolor1;
   static unsigned int bitval[] = {1, 2, 4, 8, 16, 32, 64, 128};
   static short ytable[SHEIGHT];       /* offsets from beginning of */
                                 /*   each screen row  (WHY ?!?!?)  */
   static char first = NOT_OK;

   if (first==NOT_OK)  {               /* initialize color values once */
      first = OK;
      color = BLACK;
      blackcolor0 = color&1L;
      blackcolor1 = (color&2L)>>1;
      color = BLUE;
      bluecolor0 = color&1L;
      bluecolor1 = (color&2L)>>1;
      color = ORANGE;
      Ocolor0 = color&1L;
      Ocolor1 = (color&2L)>>1;
      disp = SHADOW_DISP * rowoffset;  /* offset to shadowed row */
      ytable[0] = 0;                   /* initialize screen offsets */
      /* rowoffset = WWIDTH/8;      * #defined above * */
      for (color=1; color<SHEIGHT; ++color)
        ytable[color] = ytable[color-1] + rowoffset;
   }
   for (k=ytable[WYOFFS]; k<ytable[WHEIGHT+WYOFFS-SHADOW_DISP-1]; k+=rowoffset)  {
                                       /* do each row                  */
      k2 = k + disp;                   /* displacement to shadowed row */
      for (j=0; j<rowoffset; ++j)  {   /* do each byte in row          */
         byte0 = bp[0][k+j];           /* current row, planes 0 and 1  */
         byte1 = bp[1][k+j];
         byte0b0 = bp[0][k2+j];        /* shadowed row, planes 0 and 1 */
         byte1b0 = bp[1][k2+j];
         byte0b1 = bp[0][k2+j+1];      /* shadowed row, adjacent byte, */
         byte1b1 = bp[1][k2+j+1];      /*   planes 0 and 1             */
                                       /* if last byte in row, don't   */
                                       /*   need adjacent bytes        */
         ((j<rowoffset-1) ? (bitlast=0) : (bitlast=SHADOW_DISP));
         modb0 = NOT_OK;
         modb1 = NOT_OK;
         for (m=7; m>=bitlast; --m)  { /* check each bit, left to right */
            color0 = BITVAL(byte0,m);  /* current pixel color           */
            color1 = BITVAL(byte1,m);
            if (color0==Ocolor0 && color1==Ocolor1)  {
               if (m>SHADOW_DISP-1)  {           /* get color of pixel in   */
                  bcolor0 = BITVAL(byte0b0,m-SHADOW_DISP);  /* shadowed row */
                  bcolor1 = BITVAL(byte1b0,m-SHADOW_DISP);
               }
               else  {                 /* use adjacent byte */
                  bcolor0 = BITVAL(byte0b1,m+8-SHADOW_DISP);
                  bcolor1 = BITVAL(byte1b1,m+8-SHADOW_DISP);
               }
               if (bcolor0==bluecolor0 && bcolor1==bluecolor1)  {
                  if (m>SHADOW_DISP-1)  {  /* if blue, set color to black */
                     BITSTORE(byte0b0,m-SHADOW_DISP,blackcolor0);
                     BITSTORE(byte1b0,m-SHADOW_DISP,blackcolor1);
                     modb0 = OK;
                  }
                  else  {              /* use adjacent byte */
                     BITSTORE(byte0b1,m+8-SHADOW_DISP,blackcolor0);
                     BITSTORE(byte1b1,m+8-SHADOW_DISP,blackcolor1);
                     modb1 = OK;
                  }
               }
            }
         }                             /* end bit test */
         if (modb0==OK)  {             /* restore only modified bytes */
            bp[0][k2+j] = byte0b0;
            bp[1][k2+j] = byte1b0;
         }
         if (modb1==OK)  {
            bp[0][k2+j+1] = byte0b1;
            bp[1][k2+j+1] = byte1b1;
         }
      }                                /* end of row */
   }                                   /* last row   */
}

/* ============================================================= */

int getbox (x0, y0, x, y)              /* selects a region to draw to */
                                       /*   larger scale              */
int *x0, *y0, *x, *y;

{

   extern void drawbox();
   struct IntuiMessage *msgf;
   int xd, yd, x1, x2, y1, y2;
   char selectbutton;
   selectbutton = FALSE;
   SetDrMd (rp, JAM2 | COMPLEMENT);    /* turn on complement mode and */
   ModifyIDCMP (w, MOUSEBUTTONS | MOUSEMOVE); /* enable mouse events    */
   while (1)  {
      WaitPort (w->UserPort);
      msgf = (struct IntuiMessage *) GetMsg (w->UserPort);
      if (msgf==NULL)
         continue;
      else if (msgf->Code==SELECTDOWN)  { /* if user pressed left button, */
         x1 = msgf->MouseX;               /*   get initial mouse position */
         y1 = msgf->MouseY;
         xd = x1;
         yd = y1;
         selectbutton = TRUE;
      }
      else if (selectbutton==TRUE && msgf->Class==MOUSEMOVE)  {
         x2 = msgf->MouseX;
         y2 = msgf->MouseY;
         drawbox (x1, y1, xd, yd);     /* erase old box */
         xd = x2;
         yd = y2;
         drawbox (x1, y1, xd, yd);     /* draw new box */
      }
      else if (selectbutton==TRUE && msgf->Code==SELECTUP)
         break;

      ReplyMsg((struct Message *)msgf);
   }
   x2 = msgf->MouseX;                  /* erase current box */
   y2 = msgf->MouseY;
   ReplyMsg((struct Message *)msgf);
   drawbox (x1, y1, xd, yd);
   SetDrMd (rp, JAM2);                 /* restore original drawing mode */
   ModifyIDCMP (w, IDCMPFLAGS);        /*   and disable mouse events    */
   *x0 = x1;
   *y0 = y1;
   *x = x2;
   *y = y2;
   if (x1==x2 || y1==y2)               /* error if box is of zero area */
      return (NOT_OK);
   if (x1>x2 && y1>y2)  {              /* ensure that the vertices of */
      *x0 = x2;                        /*   the box are in the proper */
      *y0 = y2;                        /*   order                     */
      *x = x1;
      *y = y1;
   }
   else if (x1<x2 && y1>y2)  {
      *x0 = x1;
      *y0 = y2;
      *x = x2;
      *y = y1;
   }
   else if (x1>x2 && y1<y2)  {
      *x0 = x2;
      *y0 = y1;
      *x = x1;
      *y = y2;
   }
   return (OK);
}

/* ============================================================= */

void drawbox (x1, y1, x2, y2)          /* draws a box */

int x1, y1, x2, y2;

{

   Move (rp, x1, y1);
   Draw (rp, x2, y1);
   Draw (rp, x2, y2);
   Draw (rp, x1, y2);
   Draw (rp, x1, y1);
}

/* ============================================================= */

void box (ws, latp, lamp, fill)        /* draws areas contained within */
                                       /*   a rectangular region       */
short *ws;
double *latp, *lamp;
int fill;

{

   extern void plotpoint(), drawbox(), box_tidy();
   char first, prev_in_view, in_view, is_lake;
   short h1, h1c, h1prev;              /* x-dist. (pix) from center */
   short h2, h2c, h2prev;              /* y-dist. (pix) from center */
   short np, xs, ys, nrim_in, nrim_out;
   int i, j, k, narea;
   long x, y, pen, first_color;
   double lam, lamc, lamprev;          /* longitude */
   double lat, latc, latprev;          /* latitude  */
   double bwidth, bheight, bcx, bcy, xscale, yscale;
   double lat1, lat2, lam1, lam2;

   lat1 = latp[0];                     /* store values for box corners */
   lat2 = latp[1];                     /*   locally                    */
   lam1 = lamp[0];
   lam2 = lamp[1];
   bwidth = lam2 - lam1;               /* box width (degrees)         */
   bheight = lat1 - lat2;              /* box height (degrees)        */
   bcx = (lam1 + lam2)/2.;             /* x-coord of box center (deg) */
   bcy = (lat1 + lat2)/2.;             /* y-coord of box center (deg) */
   xscale = WWIDTH / bwidth;           /* horizontal scale (pix/deg)  */
   yscale = (WHEIGHT) / bheight;    /* vertical scale (pix/deg)    */
   j = 0;
   np= 0;
   narea = 0;
   nrim_in=0;
   first = TRUE;
   pen = ORANGE;
   SetAPen (rp, pen);
   first_color = BLACK;

   drawbox (0, 0, WWIDTH-1, WHEIGHT); /* outline the box */

   for (i=0; i<MAXVAL; i+=2)  {
      if (ws[i]==0 && ws[i+1]==0)  {   /* if end of area, then */
         ++narea;
         if (np>0 && fill==FILL)  {    /* color-fill if requested */
            if (nrim_in==0)  {
               is_lake = FALSE;
               for (k=0; k<num_lakes; ++k)
                  if (narea==lakes[k])  {
                     is_lake = TRUE;
                     if (first_color==ORANGE)
                        pen = BLUE;
                     break;
                  }
               if (is_lake==FALSE || (is_lake==TRUE && pen==BLUE))  {
                  xs = CENTERX + area[0];
                  ys = CENTERY + area[1];
                  if (np==1)
                     plotpoint (xs, ys);
                  else
                     afill (np, pen);
               }
            }
         }
         j = 0;
         np = 0;
         nrim_in = 0;
         nrim_out = 0;
         pen = ORANGE;
         first_color = BLACK;
         first = TRUE;
         continue;                     /* skip to next point */
      }
      lat = ws[i];                     /* latitude */
      lat = lat/100.;
      lam = ws[i+1];                   /* longitude */
      lam = lam/100.;
      in_view = FALSE;                 /* get status of current point */
      if ( (lat<=lat1 && lat>=lat2)
        && (lam>=lam1 && lam<=lam2))  {
         in_view = TRUE;
         h1 = (lam-bcx) * xscale;
         h2 = - (lat-bcy) * yscale;
      }
      if (first==TRUE)  {              /* check first point */
         first = FALSE;
         if (in_view==TRUE)  {         /* if first point is in view, */
            x = h1 + CENTERX;          /*   move pen to first point  */
            y = h2 + CENTERY;          /*   and plot it              */
            Move (rp, x, y);
            first_color = ReadPixel (rp, x, y);
            xs = x;
            ys = y;
            plotpoint (xs, ys);
            h1prev = h1;
            h2prev = h2;
            area[0] = h1;
            area[1] = h2;
            j = 2;
            np = 1;
         }
         prev_in_view = in_view;       /* save status of first point */
         latprev = lat;
         lamprev = lam;
         continue;
      }
      if (in_view==TRUE)  {
         if (prev_in_view==FALSE)  {   /* if prev. point was not in view, */
            if (lamprev<=lam1)  {      /*   find rim point                */
               lamc = lam1;
               if (latprev<=lat2)      /* lower left */
                  latc = lat2;
               else if (latprev>=lat1) /* upper left */
                  latc = lat1;
               else                    /* left center */
                  latc = lat + (latprev-lat)*(lamc-lam)/(lamprev-lam);
            }
            else if (lamprev>=lam2)  {
               lamc = lam2;
               if (latprev>=lat1)      /* upper right */
                  latc = lat1;
               else if (latprev<=lat2) /* lower right */
                  latc = lat2;
               else                    /* right center */
                  latc = lat + (latprev-lat)*(lamc-lam)/(lamprev-lam);
            }
            else  {
               if (latprev>=lat1)      /* top center */
                  latc = lat1;
               else                    /* bottom center */
                  latc = lat2;
               lamc = lam + (lamprev-lam)*(latc-lat)/(latprev-lat);
            }
            h1c = (lamc-bcx) * xscale;
            h2c = - (latc-bcy) * yscale;
            x = h1c + CENTERX;         /* move to rim point & plot it */
            y = h2c + CENTERY;
            Move (rp, x, y);
            xs = x;
            ys = y;
            plotpoint (xs, ys);
            h1prev = h1c;
            h2prev = h2c;
            area[j] = h1;
            area[j+1] = h2;
            j += 2;
            ++nrim_in;
            ++np;
         }
         if (h1!=h1prev || h2!=h2prev)  {
            x = h1 + CENTERX;          /* draw to current point */
            y = h2 + CENTERY;
            Draw (rp, x, y);
            area[j] = h1;
            area[j+1] = h2;
            j += 2;
            ++np;
         }
         h1prev = h1;
         h2prev = h2;
      }
      else  {                          /* else out of view */
         if (prev_in_view==TRUE)  {    /* if previous point was in view, */
            if (lam<=lam1)  {          /*   find rim point                */
               lamc = lam1;
               if (lat<=lat2)          /* lower left */
                  latc = lat2;
               else if (lat>=lat1)     /* upper left */
                  latc = lat1;
               else                    /* left center */
                  latc = lat + (latprev-lat)*(lamc-lam)/(lamprev-lam);
            }
            else if (lam>=lam2)  {
               lamc = lam2;
               if (lat>=lat1)          /* upper right */
                  latc = lat1;
               else if (lat<=lat2)     /* lower right */
                  latc = lat2;
               else                    /* right center */
                  latc = lat + (latprev-lat)*(lamc-lam)/(lamprev-lam);
            }
            else  {
               if (lat>=lat1)          /* top center */
                  latc = lat1;
               else                    /* bottom center */
                  latc = lat2;
               lamc = lam + (lamprev-lam)*(latc-lat)/(latprev-lat);
            }
            h1c = (lamc-bcx) * xscale;
            h2c = - (latc-bcy) * yscale;
            x = h1c + CENTERX;         /* draw to rim point */
            y = h2c + CENTERY;
            Draw (rp, x, y);
            area[j] = h1;
            area[j+1] = h2;
            j += 2;
            ++nrim_out;
            ++np;
         }
      }
      prev_in_view = in_view;          /* save status of current point */
      latprev = lat;
      lamprev = lam;
   }
   if (fill==FILL)
      box_tidy (lat1, lam1, lat2, lam2, /* fill partial areas */
                bcx, bcy, xscale, yscale);
}

/* ============================================================= */

void box_tidy (lat1, lam1, lat2, lam2, bcx, bcy, xscale, yscale)
                                       /* color-fills partially-drawn */
                                       /*   areas in box-view         */
double lat1, lam1, lat2, lam2, bcx, bcy, xscale, yscale;

{
   double lat, lam;
   int i;
   short h1, h2;
   long x, y, color;

   i = 0;
   while (1)  {                        /* check each special point */
      if (td[i]==0 && td[i+1]==0)      /* if end of special points, */
         break;                        /*   then all done           */
      lat = td[i];
      lat /= 100.;
      lam = td[i+1];
      lam /= 100.;
      if ((lat<=lat1 && lat>=lat2) &&  /* if point is in view,  */
          (lam>=lam1 && lam<=lam2))  { /*   then get its screen */
         h1 = (lam-bcx) * xscale;      /*   coordinates         */
         h2 = -(lat-bcy) * yscale;
         x = h1 + CENTERX;             /* color-fill if current color */
         y = h2 + CENTERY;             /*   is blue                   */
         if ((color = ReadPixel (rp, x, y)) == BLUE)
            Flood (rp, 1, x, y);
      }
      i += 2;
   }
}

/* ============================================================= */

void do_text (msgin, color)              /* get user text input */
struct IntuiMessage *msgin;
short color;
{
   extern void drawbox();
   struct IntuiMessage *msg, *msg1;
   struct Gadget *g;
   static char title_setdown[] = "   Press LEFT button to position text | RIGHT button to CANCEL";
   int x, y, xold, yold, pixlength;
   long oldpen;
   BOOL abort=FALSE;

   x = msgin->MouseX - GAD_LEFT-8;     /* position the requester */
   y = msgin->MouseY - GAD_TOP-12;
   if ((x+TWIDTH) >= WWIDTH)
      x = WWIDTH-TWIDTH-15;
   if (x < 10)
      x = 10;
   if ((y+THEIGHT) >= WHEIGHT)
      y = WHEIGHT-THEIGHT-15;
   if (y<5)
      y = 5;
   req.LeftEdge = x;
   req.TopEdge = y;
   oldpen = rp->FgPen;
   SetAPen(rp,WHITE);
   Request (&req, w);                  /* issue the request */
   ModifyIDCMP (w, GADGETUP);          /* disable all but gadgetup event */
   ActivateGadget (&gad, w, &req);
   do  {
      WaitPort (w->UserPort);             /* wait for gadgetup event */
      msg = (struct IntuiMessage *) GetMsg (w->UserPort);
      if (msg == NULL)
         continue;
      else if (msg->Class == GADGETUP)  { /* check for correct gadget */
         g = (struct Gadget *) (msg->IAddress);
         if (g->GadgetID != GAD_FIRST)
            continue;
         pixlength = TextLength (rp, userinput, strlen(userinput));
         SetWindowTitles (w, (char *) -1,title_setdown);
         SetDrMd (rp, JAM2 | COMPLEMENT);
         SetPointer (w, transparent, transparent_size/4-2, 16,
                     transparent_x_offset, transparent_y_offset);
         xold = msg->MouseX;           /* current mouse position */
         yold = msg->MouseY;
         drawbox (xold, yold, xold+pixlength, yold-8);
         ModifyIDCMP (w, MOUSEBUTTONS | MOUSEMOVE);
         do  {
            WaitPort (w->UserPort);       /* wait for mouse button  */
            msg1 = (struct IntuiMessage *) GetMsg (w->UserPort);
            if (msg1 == NULL)
               continue;
            else  {
               x = msg1->MouseX;       /* get current mouse position */
               y = msg1->MouseY;       /*   and erase old box        */
               if (msg1->Class == MOUSEBUTTONS )  {
                  drawbox (xold, yold, xold+pixlength, yold-8);
                                    /* done if select button pressed */
                  if (msg1->Code == SELECTDOWN)  {
                     SetDrMd (rp, JAM1);
                     SetAPen (rp, color);          /* draw text in active color */
                     Move (rp, x, y-1);              /* move to current mouse position */
                     Text (rp, userinput, strlen(userinput));
                     abort=TRUE;
                  }
                  else if (msg1->Code == MENUDOWN)  {
                     SetDrMd (rp, JAM1);
                     abort=TRUE;         /* right button cancels */
                  }
               }
               else if (msg1->Class == MOUSEMOVE)  {  /* else draw box at current position */
                  drawbox (xold, yold, xold+pixlength, yold-8);
                  drawbox (x, y, x+pixlength, y-8);
                  xold = x;
                  yold = y;
               }
            }
            ReplyMsg ( (struct Message *) msg1);
         } while(abort==FALSE);
         break;
      }
   } while (TRUE);
   SetAPen (rp, oldpen);
   SetPointer (w, arrow, arrow_size/4-2, 16,
                  arrow_x_offset, arrow_y_offset);

   ReplyMsg ( (struct Message *) msg);
}

/* ================================================================ */

void afill (pairs, pen)                /* draws and fills a region  */
                                       /*   using AreaDraw function */
short pairs;                            /* how many pairs of words */
long pen;                              /* pen number to use       */

{

   short i, j;
   long x, y, oldpen;

   oldpen = rp->FgPen;
   SetAPen (rp, pen);
   x = area[0] + CENTERX;
   y = area[1] + CENTERY;
 /*  if (x<0)     * unneeded in a WINDOW *
      x = 0;
   if (x>WWIDTH-1)
      x = WWIDTH-1;
   if (y<0)
      y = 0;
   if (y>WHEIGHT-1)
      y = WHEIGHT-1; */
   AreaMove (rp, x, y);
   j = 2;
   for (i=1; i<pairs; i++)  {
      if (area[j]==0 && area[j+1]==0)
         break;
      x = area[j] + CENTERX;
      y = area[j+1] + CENTERY;
/*      if (x<0)
         x = 0;
      if (x>WWIDTH-1)
         x = WWIDTH-1;
      if (y<0)
         y = 0;
      if (y>WHEIGHT-1)
         y = WHEIGHT-1; */
      AreaDraw (rp, x, y);
      j += 2;
   }
   AreaEnd (rp);
   SetAPen (rp, oldpen);
}

/* ============================================================= */

void adraw (pairs)                     /* draws area outlines */

short pairs;

{

   short i, j;
   long x, y, oldpen;

   oldpen = rp->FgPen;
   SetAPen (rp, ORANGE);
   x = area[0] + CENTERX;
   y = area[1] + CENTERY;
 /*  if (x<0)
      x = 0;
   if (x>WWIDTH-1)
      x = WWIDTH-1;
   if (y<0)
      y = 0;
   if (y>WHEIGHT-1)
      y = WHEIGHT-1; */
   Move (rp, x, y);
   j = 2;
   for (i=1; i<pairs; ++i)  {
      if (area[j]==0 && area[j+1]==0)
         break;
      x = area[j] + CENTERX;
      y = area[j+1] + CENTERY;
    /*  if (x<0)          * Unnecessary in a normal WINDOW *
         x = 0;
      if (x>WWIDTH-1)
         x = WWIDTH-1;
      if (y<0)
         y = 0;
      if (y>WHEIGHT-1)
         y = WHEIGHT-1; */
      Draw (rp, x, y);
      j += 2;
   }
   SetAPen (rp, oldpen);
}

/* ============================================================= */

void plotpoint (x, y)                  /* plots a single point */

short x, y;

{

/*   if (x<0)     * Unnecessary because we use a WINDOW *
      x = 0;
   if (x>WWIDTH-1)
      x = WWIDTH-1;
   if (y<0)
      y = 0;
   if (y>WHEIGHT-1)
      y = WHEIGHT-1; */
   WritePixel (rp, x, y);
}
/* ============================================================= */

void drawline(color)                /* draws a line on mouse positions */
short color;
{
    struct IntuiMessage *msg;
    short y,x, oldpen;
    ULONG code;

    msg=NULL;
    oldpen = rp->FgPen;
    ModifyIDCMP (w, MOUSEBUTTONS);
    do{
        WaitPort (w->UserPort);       /* wait for mouse button  */
        msg = (struct IntuiMessage *) GetMsg (w->UserPort);
        if (msg==NULL){
            continue;
        }
        code=msg->Code;        /* must be a MOUSEBUTTONS message */
        x = msg->MouseX;       /* get current mouse position */
        y = msg->MouseY;
        ReplyMsg((struct Message *) msg);
        if (code == SELECTDOWN){
            SetAPen(rp, color);
            WritePixel(rp,x,y);
            Move(rp,x,y);
            ModifyIDCMP(w, MOUSEBUTTONS | MOUSEMOVE );
            do {
                WaitPort(w->UserPort);
                msg = ((struct IntuiMessage *) GetMsg (w->UserPort));
                if (msg == NULL){
                    continue;
                }

                if (msg->Class == MOUSEMOVE){
                    x = msg->MouseX;       /* get current mouse position */
                    y = msg->MouseY;
                    Draw(rp,x,y);
                    code=NULL;
                }
                else{
                    code=msg->Code;        /* This must be a MOUSEBUTTONs message*/
                }
                ReplyMsg((struct Message *) msg);
            } while (code != SELECTUP);
            continue;
        }
    } while (code != MENUDOWN);
    SetAPen (rp, oldpen);
    ModifyIDCMP (w, IDCMPFLAGS);  /* enable original event types */
}
/* ============================================================= */

VOID setwin(w, traprmb,idcmpflags,title)  /* sets window title, window */
                                              /*  and IDCMP flags */
struct Window* w;
ULONG traprmb;
ULONG idcmpflags;
UBYTE *title;
{
    Forbid();
    if (traprmb==RMBTRAP){
        w->Flags|=RMBTRAP;
    }
    else{
        w->Flags&=~RMBTRAP;
    }
    Permit();
    ModifyIDCMP (w, idcmpflags );
    SetWindowTitles (w, (char *) -1, title);
    SetWindowTitles (wt, (char *)-1, title);
}


/* ============================================================= */

LONG dump(win)                      /* dumps displayed map to printer */
struct Window *win;
{
   struct IODRPReq    *ioreq;
   struct MsgPort  *printerPort;
   ULONG signal,winsig, printsig;
   BYTE abort = NULL;
    #define NOABORT 1<<1
    #define U_ABORT 1<<2
    #define P_ABORT 1<<3

   LONG returncode= NOT_OK;
   struct IntuiMessage *msg;
   UWORD dpY;
   if(printerPort = CreatePort("drmapdump",0)) {
      if(ioreq=(struct IODRPReq *) CreateExtIO(printerPort,sizeof(struct IODRPReq))) {
         if(!(OpenDevice("printer.device",0,(struct IORequest *)ioreq,0))) {
            ioreq->io_Command = CMD_FLUSH;
            DoIO((struct IORequest *) ioreq);
            if (ioreq->io_Error == PDERR_NOERR){
                winsig= 1 << win->UserPort->mp_SigBit;
                printsig= 1 << printerPort->mp_SigBit;
                ioreq->io_Command = PRD_DUMPRPORT;
                ioreq->io_RastPort = rp;
                ioreq->io_ColorMap = vp->ColorMap;
                ioreq->io_Modes = HIRES|LACE;         /* vp->Modes;*/
            /*  ioreq->io_SrcX = 0; CLEARED by MEMF_CLEAR */
            /*  ioreq->io_SrcY = 0;                       */
                ioreq->io_SrcWidth = WWIDTH;
                ioreq->io_SrcHeight = WHEIGHT;
            /*  ioreq->io_DestCols = 0;                   */
            /*  ioreq->io_DestRows = 0;                   */
                ioreq->io_Special = SPECIAL_ASPECT|SPECIAL_FULLROWS;

                Forbid();
                dpY=GfxBase->NormalDPMY;
                GfxBase->NormalDPMY=1267;
                    /* Dots per Meter on Display for WHEIGHT=390 */
                Permit();


                SendIO((struct IORequest *)ioreq);
                while (abort==NULL){
                    signal=Wait(printsig | winsig);
                    if (signal & winsig){
                        while (msg=(struct IntuiMessage *)GetMsg(win->UserPort)){
                            if (msg->Class==CLOSEWINDOW){
                                setwin (w, RMBTRAP, CLOSEWINDOW, "   Printing canceled. Please wait ...");
                                abort|=U_ABORT;
                            }
                            ReplyMsg((struct Message *) msg);
                        }
                    }
                    if (signal & printsig){
                        if (ioreq->io_Error != PDERR_NOERR){
                            setwin (w, RMBTRAP, CLOSEWINDOW, "   PRINTER ERROR. Screendump aborted");
                            abort|=P_ABORT;
                        }
                        else{
                            abort|=NOABORT;  /* ahem, not aborted, but ended OK */
                        }
                    }
                }
                if (abort == U_ABORT){
                /* WAIT A MOMENT, crashes if printer.device is being loaded */
                /* and printing is canceled */
                    DisplayBeep(0);
                    Delay (8 * TICKS_PER_SECOND);
                    AbortIO((struct IORequest *)ioreq);
                    WaitIO((struct IORequest *)ioreq);
                }
                else if (abort & NOABORT){
                    returncode=OK;
                }
                while ((struct MsgPort *)GetMsg(printerPort))
                            ;

                Forbid();
                GfxBase->NormalDPMY=dpY;
                Permit();
            }

            CloseDevice((struct IORequest *)ioreq);
         }
         DeleteExtIO((struct IORequest *)ioreq);
      }
      DeletePort(printerPort);
   }
   return(returncode);
}

/* ============================================================= */

VOID CloseCon(conioreq)         /* support routines for displayhelp() */
struct IOStdReq *conioreq;
{
    struct MsgPort  *conPort;

    conPort=conioreq->io_Message.mn_ReplyPort;
    while ((struct MsgPort *)GetMsg(conPort))
                            ;
    CloseDevice(conioreq);
    DeleteExtIO(conioreq);
    DeletePort(conPort);
}

struct IOStdReq *OpenCon(win)
struct Window *win;
{
    struct IOStdReq *conioreq=NULL;
    struct MsgPort  *conPort=NULL;
    if(conPort = CreatePort("drmpcon",0)) {
        if(conioreq=(struct IOReq *)CreateExtIO(conPort, sizeof(struct IOStdReq))) {
            conioreq->io_Data = (APTR) win;
            conioreq->io_Length = sizeof (struct Window);
            if(!(OpenDevice("console.device",0,(struct IOStdRequest *)conioreq,0))) {
                return(conioreq);
            }
            DeleteExtIO(conioreq);
        }
        DeletePort(conPort);
    }
    return(NULL);
}

VOID WriteCon(conioreq,data,length) /* length=-1 -> write till \0 */
struct IOStdReq *conioreq;
UBYTE *data;
LONG length;
{
    conioreq->io_Command = CMD_WRITE;
    conioreq->io_Data = (APTR) data;
    conioreq->io_Length = length;
    DoIO(conioreq);
}

/* ============================================================= */

VOID displayhelp()      /* help routine: displays file DRAWMAP.HELP (ANSI)*/
{
   struct IntuiMessage *msg;
   LONG errabort=TRUE;
   struct IOStdReq *conioreq;
   struct Window *helpw;
   UBYTE helpbuffer[HELPBUF];
   LONG helplenght;

   BPTR helpfile;

   extern struct Screen *s;
   extern struct NewWindow newhelpw;
   extern struct Window *w;
   extern void setwin();

   newhelpw.Screen=s;
   if ( helpw=OpenWindow(&newhelpw) ){
        DrawBorder(helpw->RPort, &border, 0,0 );
        if(NULL!=(conioreq=OpenCon(helpw))){
            WriteCon( conioreq,"\x9b\x30\x20\x70", -1);
                               /* cursor off   */
            helpfile=Open("Drawmap.help",MODE_OLDFILE);
            if (helpfile!=NULL){
                do{
                    if ((helplenght=Read(helpfile,helpbuffer,HELPBUF))>0)
                        WriteCon(conioreq,helpbuffer, helplenght);
                } while (HELPBUF == helplenght);
                Close(helpfile);

                do{
                    WaitPort(helpw->UserPort);
                    msg=(struct IntuiMessage *)GetMsg(helpw->UserPort);
                    if (msg==NULL)      continue;
                    if (msg->Class==MOUSEBUTTONS)
                        errabort=FALSE;
                    ReplyMsg((struct Message *) msg);
                } while (errabort==TRUE);
            }
            CloseCon(conioreq);
        }
        CloseWindow (helpw);
   }
   if (errabort==TRUE){
    SetWindowTitles (w, (char *) -1, "   Can't display help information !");
   }

}

/* ============================================================= */



LONG save(filename)         /* saves displayed map as IFF FORM */
UBYTE    *filename;
{
   extern IFFP PutAnILBM();
   ULONG IconBase;
   LONG            file;
   struct BitMap    *picBitMap;
   ULONG            picViewModes;
   WORD             *picColorTable;
   extern struct Screen *s;
   IFFP            iffp = NO_FILE;
   LONG returncode=NOT_OK;

   if (!(file = Open(filename, MODE_NEWFILE)))
      return (returncode);

   Write(file,"x",1);  /* 1.1 so Seek to beginning works ? (?!?!???)*/

   picBitMap = (struct BitMap*)vp->RasInfo->BitMap;
   picColorTable = (WORD *)vp->ColorMap->ColorTable;
   picViewModes = (ULONG)vp->Modes;

   iffp=PutAnILBM(file, picBitMap,
                picColorTable, picBitMap->Depth, picViewModes);

   Close(file);

   if (iffp == IFF_OKAY) {
      IconBase = (ULONG)OpenLibrary("icon.library",0);
      if (IconBase!=NULL) {
        if(NULL!=PutDiskObject(filename,&ILBMobject)) {
            returncode=OK;
        }
        else{
            DisplayBeep(s);
        }
      CloseLibrary((struct Library *) IconBase);
      }
   }
   return (returncode);
}


#define CkErr(expression)  {if (ifferr == IFF_OKAY) ifferr = (expression);}

IFFP PutAnILBM(file, bitmap, colorMap, depth,
                                viewmodes)
      LONG file;
      struct BitMap *bitmap;
      WORD *colorMap; UBYTE depth;
      ULONG viewmodes;
{
   BYTE buffer[bufsize];
   BitMapHeader bmHdr;
   CamgChunk    camgChunk;
   GroupContext fileContext, formContext;
   IFFP ifferr;

   ifferr = InitBMHdr(&bmHdr, bitmap, mskNone,
                      cmpByteRun1, 0, WWIDTH, SHEIGHT);
   bmHdr.y = WYOFFS;
   bmHdr.h = WHEIGHT;

   camgChunk.ViewModes = viewmodes & CAMGMASK;

   CkErr( OpenWIFF(file, &fileContext, szNotYetKnown) );
   CkErr( StartWGroup(&fileContext, FORM, szNotYetKnown, ID_ILBM, &formContext));

   CkErr( PutBMHD(&formContext, &bmHdr) );
   CkErr( PutCAMG(&formContext, &camgChunk) );
   CkErr( PutCMAP(&formContext, colorMap, depth) );
   CkErr( PutBODY(&formContext, bitmap, mskNone, &bmHdr, buffer, bufsize) );

   CkErr( EndWGroup(&formContext) );
   CkErr( CloseWGroup(&fileContext) );
   return( ifferr );
}

/* ============================================================= */

#include "libraries/arp.h"

/* MUST be careful including ARP stuff if ARP is not used always */
/* (else the ARP functions for Close, Open would be used !!!) */


#ifdef NO_ASL
#include "libraries/arpbase.h"
/* -> do not include if using ASL, too */
/* -> compiler fails because of duplicate STRUCT FILEREQUEST definition */
#endif
/*  NOTE :   */
/*  Rename all rf_xxx to fr_xxx to use filerequester with ARP includes */

#ifndef NO_ASL
struct AslBase *AslBase;
#endif
struct ArpBase *ArpBase=NULL;
struct FileRequester *filereq=NULL;

VOID FreeArpRequest(freq)
struct FileRequester *freq;
{
    if (freq!=NULL){
#ifndef NO_ASL
        if (freq->rf_File!=NULL)    FreeMem (freq->rf_File, MAXLENGHT+1);
        if (freq->rf_Dir!=NULL)     FreeMem (freq->rf_Dir, MAXLENGHT+1);
#else
        if (freq->fr_File!=NULL)    FreeMem (freq->fr_File, MAXLENGHT+1);
        if (freq->fr_Dir!=NULL)     FreeMem (freq->fr_Dir, MAXLENGHT+1);
#endif
        FreeMem (freq, sizeof(struct FileRequester));
    }
    if (ArpBase!=NULL)    CloseLibrary(ArpBase);
    ArpBase=NULL;
}

/* ============================================================= */

struct FileRequester *AllocArpRequest(fname)
UBYTE *fname;
{
    extern struct ArpBase *ArpBase;
    extern struct Window *w;

    struct FileRequester *freq;
    UBYTE *filemem, *dirmem;

    if (NULL==(freq=AllocMem(sizeof(struct FileRequester), MEMF_CLEAR | MEMF_PUBLIC))){
        FreeArpRequest(NULL);
        return (NULL);
    }
    if (NULL==(filemem=AllocMem(MAXLENGHT+1, MEMF_CLEAR | MEMF_PUBLIC))){
        FreeArpRequest(freq);
        return (NULL);
    }
    stccpy( filemem, fname, MAXLENGHT);
#ifndef NO_ASL
    freq->rf_File=filemem;
#else
    freq->fr_File=filemem;
#endif

    if (NULL==(dirmem=AllocMem(MAXLENGHT+1, MEMF_CLEAR | MEMF_PUBLIC))){
        FreeArpRequest(freq);
        return (NULL);
    }
#ifndef NO_ASL
    freq->rf_Dir=dirmem;

    freq->rf_Window=w;
    freq->rf_Hail="+# Save As ";
    freq->rf_FuncFlags=RFF_DOCOLOR;
    freq->rf_Flags2=FR2F_LONGPATH;
#else
    freq->fr_Dir=dirmem;

    freq->fr_Window=w;
    freq->fr_Hail="+# Save As ";
    freq->fr_FuncFlags=FRF_DOCOLOR;
/*     freq->fr_Flags2=FR2F_LONGPATH; */
#endif
    return (freq);
}

/* ============================================================= */


LONG saveas(fname)    /* should return length of filenamestring */
UBYTE *fname;
{
    LONG ssize;
    extern struct FileRequester *filereq;

    if (ArpBase==NULL
#ifndef NO_ASL
                   && AslBase==NULL
#endif
#ifndef NO_ASL
                                       ){
        if (AslBase=(struct AslBase *)OpenLibrary("asl.library",0)){
            filereq=AllocFileRequest();
            if (filereq==NULL){
                CloseLibrary(AslBase);
                AslBase=NULL;
                return (NULL);
            }
            stccpy( filereq->rf_File, fname, MAXLENGHT);

            filereq->rf_Window=w;
            filereq->rf_Hail="+# Save As ";
            filereq->rf_Flags2=FR2F_LONGPATH;
        }
#endif
        else if (NULL!=(ArpBase=(struct ArpBase *) OpenLibrary("arp.library", 34L))){
            filereq=AllocArpRequest(fname);
            if (filereq==NULL){ /* if NULL, arp.library is closed */
                return (NULL);
            }
        }
        else{
            return(NULL);
        }
    }
#ifndef NO_ASL
    if (AslBase != NULL){
        if (RequestFile( filereq )==NULL)
            return (NULL);
    }
    else {
#endif
        if (FileRequest( filereq )==NULL)
            return (NULL);
#ifndef NO_ASL
    }
#endif

            /* I do not distinguish between Arp & Als Requesterstruct */
                        /* (because IT IS THE SAME structure)     :-? */
#ifndef NO_ASL
    ssize=stccpy(fname, filereq->rf_Dir, MAXLENGHT) -1;
#else
    ssize=stccpy(fname, filereq->fr_Dir, MAXLENGHT) -1;
#endif
    if (ssize!=0 &&  *(fname+(ssize-1))!=':'){
        /* if stccpy has copied more than one \0 byte and
           not only a volume (link "df0 :(!)") has been selected ...*/
        *(fname+ssize)='/'; /* add slash between dir + filename */
        ssize++;
    }
    /* allow only MAXLENGHT BYTES for full name */
#ifndef NO_ASL
    ssize+=stccpy(fname+(ssize), filereq->rf_File, MAXLENGHT-ssize)-1;
#else
    ssize+=stccpy(fname+(ssize), filereq->fr_File, MAXLENGHT-ssize)-1;
#endif
    return(ssize);
}



