/* TreeView.m - Copyright 1992  Steve Ludtke  All Rights Reserved       */
/* This object displays each Root as a circle in the x-y plane with	*/
/* the current location displayed as a cross.				*/

#import "MapView.h"
#import <appkit/View.h>
#import <appkit/Window.h>
#import <appkit/Control.h>
#import <appkit/Application.h>
#import <strings.h>
#import <dpsclient/psops.h>
#import <math.h>
#import <libc.h>

#define SQR(x) ((x)*(x))
@implementation MapView

/* initialize */
- initFrame:(NXRect *)myrect
{
    [super initFrame:myrect];
    bgColor = NX_WHITE;
    fgColor = NX_BLACK;

    xsca = NX_WIDTH(&bounds) / 2.0;  /* set scaling for display */
    zsca = NX_HEIGHT(&bounds) / 2.0; /* changing the view coordinate system */
    xof = NX_MIDX(&bounds);	     /* would be better */
    zof = NX_MIDY(&bounds);

    myx = myy = 0.0;
    return self;
}

/* One step in time. Just refresh the display */ 
- step:(Branch *) myloc
{

    [self refresh:myloc :80];
    return self;
}

/* We want keyboard/mouse events */
- (BOOL)acceptsFirstResponder
{
    return YES;
}

/* parse keyboard input */
- keyDown:(NXEvent *)event
{
    char                c;

    c = event->data.key.charCode;
    switch (c) {
	break;
    }
    return (self);
}

- keyUp:(NXEvent *)event
{
    char                c;

    c = event->data.key.charCode;
    switch (c) {
    }
    return (self);
}

/* The "meat" of the MapView */
- drawSelf:(NXRect *)rects :(int)rectCount
{
    Root               *cur;

/* bounding box for DPSDoUserPath */
    bbox[0] = bbox[1] = 50.0;
    bbox[2] = bbox[3] = 51.0;


/* clear the view */
    PSsetlinewidth(0.0);
    PSsetgray(NX_BLACK);
    NXRectFill(&bounds);
    PSsetgray(fgColor = NX_WHITE);

    cur = top;
    pathc = 0;

    while (cur != NULL) {
	if (cur->drawme) {		/* only draw if drawme is true */
	/* draw the "map" display */
	    PSarc(cur->branch.x / 32768.0 * xsca, cur->branch.y / 32768.0 * zsca, 2.0, 0, 360.0);
	    PSstroke();
	}
    /* repeat for all Roots */
	cur = cur->next;
    }

 /* in map mode we want a + where we are */
    PSmoveto(myx / 32768.0 * xsca - 4.0, myy / 32768.0 * zsca);
    PSlineto(myx / 32768.0 * xsca + 4.0, myy / 32768.0 * zsca);
    PSmoveto(myx / 32768.0 * xsca, myy / 32768.0 * zsca + 4.0);
    PSlineto(myx / 32768.0 * xsca, myy / 32768.0 * zsca - 4.0);
    PSstroke();

/* if we've used a userpath, this will draw it. Currently unused */
    if (pathc != 0)
	DPSDoUserPath(path, pathc * 2, dps_float, com, pathc, bbox, dps_ustroke);
    return self;
}

/* 2d routine to add lines to the view, for future expansion */
- addline:(float)x1 :(float)y1 :(float)x2 :(float)y2
{
    static float        lastx, lasty;

    if (x1 != lastx || y1 != lasty) {
	com[pathc] = dps_moveto;
	path[pathc * 2] = x1;
	path[pathc * 2 + 1] = y1;
	pathc++;
	if (x1 > bbox[2])
	    bbox[2] = x1;
	if (y1 > bbox[3])
	    bbox[3] = y1;
	if (x1 < bbox[0])
	    bbox[0] = x1;
	if (y1 < bbox[1])
	    bbox[1] = y1;
    }
    com[pathc] = dps_lineto;
    path[pathc * 2] = x2;
    path[pathc * 2 + 1] = y2;
    pathc++;
    if (x2 > bbox[2])
	bbox[2] = x2;
    if (y2 > bbox[3])
	bbox[3] = y2;
    if (x2 < bbox[0])
	bbox[0] = x2;
    if (y2 < bbox[1])
	bbox[1] = y2;

    if (pathc >= 1500) {
	DPSDoUserPath(path, pathc * 2, dps_float, com, pathc, bbox, dps_ustroke);
	bbox[0] = bbox[1] = 50.0;
	bbox[2] = bbox[3] = 51.0;
	pathc = 0;
    }
    lastx = x2;
    lasty = y2;
    return (self);
}

/* handles movement between branches */
- refresh:(Branch *) myloc :(int)speed;
{
    float               xs, ys, f, xls;
    static Branch      *last = NULL;
    float               sp2;

    if (myloc == NULL) {
	myloc = &top->branch;
	last = NULL;
    }
    if (last == NULL) {
	last = myloc;
	myx = myloc->x;
	myy = myloc->y;
    }
    sp2 = 51.2;
    if (speed <= 80)
	sp2 = 97.0;
    if (speed <= 60)
	sp2 = 182.0;
    if (speed <= 40)
	sp2 = 273.0;
    if (speed <= 20)
	sp2 = 400.0;
    if (speed == 0)
	sp2 = 30000.0;

/* we moved !!! */
    if (last != myloc) {
	if (last->root != myloc->root) {
	/* zoom over to the new tree */
	    xs = (myloc->x - last->x);
	    ys = (myloc->y - last->y);
	    xls = sqrt(SQR(xs) + SQR(ys)) / sp2;
	    if (xls > 200.0)
		xls /= 4.0;
	    for (f = xls; f >= 0.0; f -= 1.0) {
		myx = myloc->x - 2.0 - xs / xls * f;
		myy = myloc->y - 2.0 - ys / xls * f;

		[self display];
		usleep(20000);
	    }
	    myx = myloc->x;
	    myy = myloc->y;
	}
    }
/* make sure we're looking at the right place */
    [self display];

    last = myloc;

    return self;
}

/* Receive useful pointers */
- start:(Root *) Ptop :Pobject :(char *)path
{
    top = Ptop;
    object = Pobject;
    return self;
}

/* no prefs yet ...*/
- preferences:sender
{
    return self;
}

/* display help */
- (char *)help:window :browser
{
    return ("MapView - Steve Ludtke  May 1992\n\nSimple view that draws a circle for each site and a cross at the current location. Eventually I'll probably expand this one myself to support zooming, rotating, etc...  For now it's a good, simple example.");
}

@end
