/*
** xmap.c - Bill's version of ...
**
** xgif.c - displays GIF pictures on an X11 display
**
** Author:    John Bradley, University of Pennsylvania
**               (bradley@cis.upenn.edu)
*/

#define MAIN
#include "xmap.h"

main(argc, argv)
int   argc;
char *argv[];

{
    int i,j;
    char *display, *geom, *fname, *strind, *worldsize, *p;
    XEvent event;

    cmd = argv[0];
    display = geom = fname = worldsize = NULL;

    political = 0; expand = 1;  strip = 0;  nostrip = 0;
    expImage = NULL;

    for (i=1; i<argc; i++) {
        if (!strncmp(argv[i],"-g",2))           geom = argv[++i];
        else if (argv[i][0] == '=') 	        geom = argv[i];
        else if (!strncmp(argv[i],"-d",2))      display = argv[++i];
	else if ((strind=index(argv[i],':')))	display = argv[i];
	else if (argv[i][0] != '-')		fname = argv[i];
        else if (!strcmp(argv[i],"-e")) 	expand = atoi(argv[++i]);
        else if (!strcmp(argv[i],"-s"))		strip = atoi(argv[++i]);
        else if (!strcmp(argv[i],"-ns"))	nostrip++;
	else if (!strcmp(argv[i],"-w"))		worldsize = argv[++i];
        else if (!strcmp(argv[i],"-p")) {
            while (argv[++i] && isdigit(*argv[i]) && political<100) {
                j = polizone[political++] = atoi(argv[i]);
                printf("%d ",j);
                for (p=argv[i]; *p && *p!='-'; p++);
                if (*p && isdigit(p[1])) {
                    int k = atoi(p+1);
                    while (++j<=k && political<100) {
                        polizone[political++] = j;
                        printf("%d ",j);
                    }
                }
            }
            i--;
            printf("\n");
        }
        else Syntax(cmd);
    }

    if (fname==NULL) fname="-";

    if (expand<1 || expand>MAXEXPAND) Syntax(cmd);
    if (strip<0 || strip>7) Syntax(cmd);

    if ( (theDisp=XOpenDisplay(display)) == NULL) {
        fprintf(stderr, "%s: Can't open display `%s'\n",
		argv[0],display);
        exit(1);
    }

    theScreen = DefaultScreen(theDisp);
    theCmap   = DefaultColormap(theDisp, theScreen);
    rootW     = RootWindow(theDisp,theScreen);
    theGC     = DefaultGC(theDisp,theScreen);
    fcol      = WhitePixel(theDisp,theScreen);
    bcol      = BlackPixel(theDisp,theScreen);
    theVisual = DefaultVisual(theDisp,theScreen);

    dispcells = DisplayCells(theDisp, theScreen);
    if (dispcells<=2) 
        FatalError("This program requires a color display.");
    
    i = strlen(fname);

    if (i>=6 && !strcmp(fname+i-6,"sector"))
	LoadMAP(fname,worldsize,0);
    else if (i>=8 && !strncmp(fname+i-8,"bigmap",6))
	LoadMAP(fname,worldsize,1);
    else if (!LoadGIF(fname))
	LoadMAP(fname,worldsize,2);

    iWIDE = theImage->width;
    iHIGH = theImage->height;

    eWIDE = iWIDE * expand;
    if (eWIDE > DisplayWidth(theDisp,theScreen)) 
        eWIDE = DisplayWidth(theDisp,theScreen);

    eHIGH = iHIGH * expand;
    if (eHIGH > DisplayHeight(theDisp,theScreen)) 
        eHIGH = DisplayHeight(theDisp,theScreen);

    /*
    ** Create/Open X Resources
    */
    if ((mfinfo = XLoadQueryFont(theDisp,"variable"))==NULL)
       FatalError("couldn't open 'variable' font\n");
    mfont=mfinfo->fid;

    XSetFont(theDisp,theGC,mfont);
    XSetForeground(theDisp,theGC,fcol);
    XSetBackground(theDisp,theGC,bcol);

    CreateMainWindow(cmd,geom,argc,argv);
    Resize(eWIDE,eHIGH);

    XSelectInput(theDisp, mainW, ExposureMask | KeyPressMask 
		 | StructureNotifyMask);
    XMapWindow(theDisp,mainW);

    for (;;) {
        XNextEvent(theDisp, &event);
        HandleEvent(&event);
    }
}


HandleEvent(event)
XEvent *event;
{
    XKeyEvent *key_event;
    XComposeStatus status;
    XExposeEvent *exp_event;
    XConfigureEvent *conf_event;
    char buf[128];
    KeySym ks;
	
    switch (event->type) {
    case Expose:
	exp_event = (XExposeEvent *) event;
	if (exp_event->window==mainW) 
	    DrawWindow(exp_event->x,exp_event->y,
		       exp_event->width, exp_event->height);
	break;
	
    case KeyPress:
	key_event = (XKeyEvent *) event;
	XLookupString(key_event,buf,128,&ks,&status);
	if (buf[0]=='q' || buf[0]=='Q') Quit();
	break;
	
    case ConfigureNotify:
	conf_event = (XConfigureEvent *) event;
	if (conf_event->window == mainW && 
	    (conf_event->width != eWIDE || conf_event->height != eHIGH))
	    Resize(conf_event->width, conf_event->height);
	break;
	
    case CirculateNotify:
    case MapNotify:
    case DestroyNotify:
    case GravityNotify:
    case ReparentNotify:
    case UnmapNotify:       break;

    default:
	printf("event type=%ld\n",event->type); 
	FatalError("Unexpected X_Event");
	
    }  /* end of switch */
}


Syntax()
{
    printf("Usage: %s filename [[-geometry] geom] [[-display] display]\n",cmd);
    exit(1);
}


FatalError (identifier)
    char *identifier;
{
    fprintf(stderr, "%s: %s\n",cmd, identifier);
    exit(-1);
}


Quit()
{
    exit(0);
}


DrawWindow(x,y,w,h)
{
    XPutImage(theDisp,mainW,theGC,expImage,x,y,x,y,w,h);
}


Resize(w,h)
int w,h;
{
    int  ix,iy,ex,ey;
    byte *ximag,*ilptr,*ipptr,*elptr,*epptr;
    static char *rstr = "Resizing Image.  Please wait...";
    
    /* warning:  this code'll only run machines where int=32-bits */

    if (w==iWIDE && h==iHIGH) {		/* very special case */
        if (expImage != theImage) {
            if (expImage) XDestroyImage(expImage);
            expImage = theImage;
            eWIDE = iWIDE;  eHIGH = iHIGH;
	}
    }
    
    else {
        /* if it's a big image, this'll take a while.  mention it */
        if (w*h > (500*500)) {
            XDrawImageString(theDisp,mainW,theGC,CENTERX(mfinfo,w/2,rstr),
			     CENTERY(mfinfo,h/2),rstr, strlen(rstr));
            XFlush(theDisp);
	}
	
	/* first, kill the old expImage, if one exists */
	if (expImage && expImage != theImage) {
            free(expImage->data);  expImage->data = NULL;
            XDestroyImage(expImage);
	}
	
        /* create expImage of the appropriate size */
        eWIDE = w;  eHIGH = h;
        ximag = (byte *) malloc(w*h);
        expImage = XCreateImage(theDisp,theVisual,8,ZPixmap,0,ximag,
				eWIDE,eHIGH,8,eWIDE);
	
        if (!ximag || !expImage) {
            fprintf(stderr,"ERROR: unable to create a %dx%d image\n",w,h);
            exit(0);
	}
	
        elptr = epptr = (byte *) expImage->data;
        for (ey=0;  ey<eHIGH;  ey++, elptr+=eWIDE) {
            iy = (iHIGH * ey) / eHIGH;
            epptr = elptr;
            ilptr = (byte *) theImage->data + (iy * iWIDE);
            for (ex=0;  ex<eWIDE;  ex++,epptr++) {
                ix = (iWIDE * ex) / eWIDE;
                ipptr = ilptr + ix;
                *epptr = *ipptr;
	    }
	}
    }
}
                

CreateMainWindow(name,geom,argc,argv)
char *name,*geom,**argv;
int   argc;
{
    XSetWindowAttributes xswa;
    unsigned int xswamask;
    XSizeHints hints;
    int i,x,y,w,h;

    x=y=w=h=1;
    i=XParseGeometry(geom,&x,&y,&w,&h);
    if (i&WidthValue)  eWIDE = w;
    if (i&HeightValue) eHIGH = h;

    if (i&XValue || i&YValue) hints.flags = USPosition;  
                         else hints.flags = PPosition;

    hints.flags |= USSize;

    if (i&XValue && i&XNegative) 
        x = XDisplayWidth(theDisp,theScreen)-eWIDE-abs(x);
    if (i&YValue && i&YNegative) 
        y = XDisplayHeight(theDisp,theScreen)-eHIGH-abs(y);

    hints.x=x;
    hints.y=y;
    hints.width = eWIDE;
    hints.height = eHIGH;
    hints.max_width = DisplayWidth(theDisp,theScreen);
    hints.max_height = DisplayHeight(theDisp,theScreen);
    hints.flags |= PMaxSize;

    xswa.background_pixel = bcol;
    xswa.border_pixel     = fcol;
    xswa.colormap	  = newCmap;
    xswamask = CWColormap | CWBackPixel | CWBorderPixel;

    mainW = XCreateWindow(theDisp,rootW,x,y,eWIDE,eHIGH,2,0,
			  CopyFromParent,CopyFromParent,
			  xswamask, &xswa);

    XSetStandardProperties(theDisp,mainW,"xmap","xmap",None,
                            argv,argc,&hints);

    if (!mainW) FatalError("Can't open main window");
}


