//  Created by Joe Becker on 3/7/05.
//  Copyright 2005 __MyCompanyName__. All rights reserved.

#import "GraphView.h"
#import "TrackingGraphView.h"
#import "DataView.h"
#import "StatView.h"
#import "Segment.h"
#import "GmtShipTrackRecord.h"
#import "GmtShipTrack.h"
#import "Controller.h"
#import "DragRect.h"


@implementation TrackingGraphView

- (id)initWithFrame:(NSRect)frame
{
	[super initWithFrame:frame];
	
	annotations = [[NSMutableArray alloc] init];
	
	trackingRectTag = [self addTrackingRect:[self visibleRect] owner:self userData:0 assumeInside:NO];
	
	tagOfInterest = MEASURED_TAG;
	
	distanceToLine = 30.;
	
	dataMissingLastTime = NO;
	
	return self;
}

- (void)dealloc
{
	[super dealloc];
}

- (NSRect) selectedRect
{
	return selectedRect;
}

- (int)dataTypeBeingPlotted
{
	return dataTypeBeingPlotted;
}

- (void)addAnnotation:(id)obj
{
	[annotations addObject:obj];
	[self addGraphElement:obj];
//	[self display];
	[self displayIfNeeded];
}

- (void)removeAnnotations
{
	NSEnumerator *en = [annotations objectEnumerator];
	id obj;
	
	while(obj = [en nextObject]) {
		[displayList removeObject:obj];	
		[self setNeedsDisplayInRect:[obj bounds] ];
		[self displayIfNeeded];
	}
//	[displayList removeObjectsInArray:annotations];	
	[annotations removeAllObjects];
}

- (void)getFormAndScaleView
{
	[self removeTrackingRect:trackingRectTag]; // remove the old
	[super getFormAndScaleView];
	trackingRectTag = [self addTrackingRect:[self visibleRect] owner:self userData:0 assumeInside:NO];
}

- (void)mouseEntered:(NSEvent *)theEvent
{
	[[self window] setAcceptsMouseMovedEvents:YES];
	[[self window] makeFirstResponder:self];
}

- (void)mouseExited:(NSEvent *)theEvent
{
	[self removeAnnotations];
	[[self window] setAcceptsMouseMovedEvents:NO];
}

-(void)mouseDragged:(NSEvent *)theEvent
{
	NSPoint p = [self convertPoint:[theEvent locationInWindow] fromView:nil];
	
	selectedRect = NSMakeRect( MIN(mouseDownPoint.x, p.x),
							   MIN(mouseDownPoint.y, p.y),
							   fabs(mouseDownPoint.x-p.x) + FLT_MIN,
							   fabs(mouseDownPoint.y-p.y) + FLT_MIN);
	
	[self removeAnnotations];  // Remove the old drag rect
	
	id box = [[DragRect alloc] initFrom:selectedRect];
	
	[self addAnnotation:box];
	[box setColor:[NSColor blueColor] ];
	
	return;				
}

-(void)mouseDown:(NSEvent *)theEvent
{
	mouseDownPoint = [self convertPoint: [theEvent locationInWindow] fromView:nil];
	weBeFlagging = NO;	// some sub view flag, others zoom on a drag
}

-(void)mouseUp:(NSEvent *)theEvent
{
	mouseUpPoint = [self convertPoint: [theEvent locationInWindow] fromView:nil];
	
	selectedRect = NSMakeRect( MIN(mouseDownPoint.x,mouseUpPoint.x),
							   MIN(mouseDownPoint.y,mouseUpPoint.y),
							   fabs(mouseDownPoint.x-mouseUpPoint.x) + FLT_MIN,
							   fabs(mouseDownPoint.y-mouseUpPoint.y) + FLT_MIN);
	
	if (NSEqualPoints(mouseUpPoint, mouseDownPoint)) {
		// center the graph on a single click
		[self getForm];
		[self pageBy:mouseDownPoint.x-(xmax+xmin)/2:mouseDownPoint.y-(ymax+ymin)/2];
		
		return;
	}
	
	if (weBeFlagging) {
		//[self flagRect:selectedRect];
	} else {
		[self zoomToRect:selectedRect];
	}
}

- (void)dataMissing
{
	if (dataMissingLastTime) {
		return;
	}
	
	dataMissingLastTime = YES;
	[self removeAnnotations];
//	[self displayIfNeeded];
	
	[xCell setStringValue:@"x: missing"];
	[yCell setStringValue:@"y: missing"];
	[tCell setStringValue:@"t: missing"];
	
	hotSpotFound = NO;			// i.e. "dataMissing" is drawn at hot spot
}

- (NSPoint)dataPtAtRecord:(GmtShipTrackRecord *)obj
{
	return NSMakePoint(NAN,NAN);
}

- (void)moveCursorToRecord:(GmtShipTrackRecord *)obj
{
	float timeAtCursor = [obj time] - [[[[controller gmtShipTrack] gmtShipTrackRecordList] objectAtIndex:0] time];
	[self moverCursorToHotSpot:[self dataPtAtRecord:obj]];
	[tCell setStringValue:[NSString stringWithFormat:@"t: %12.5f", timeAtCursor] ];
}

- (void)moveCursorToTime:(float)time
{
	[self moveCursorToRecord:[[controller gmtShipTrack] objectAt:TIME_FIELD:time:nil]];
}

- (void)moverCursorToHotSpot:(NSPoint)hotSpot
{
	[self removeAnnotations];  // Remove the old
	
	// Horizontal line intersecting cursor hot spot
	
	id seg = [[Segment alloc] initFrom:NSMakePoint(NSMinX([self bounds]), hotSpot.y) to:NSMakePoint(NSMaxX([self bounds]), hotSpot.y) view:self record:nil];
	
	[seg setColor:[NSColor purpleColor]];
	[self addAnnotation:seg];
	
	// Vertical line intersecting cursor hot spot
	
	seg = [[Segment alloc] initFrom:NSMakePoint(hotSpot.x, NSMinY([self bounds])) to:NSMakePoint(hotSpot.x, NSMaxY([self bounds])) view:self record:nil];
	
	[seg setColor:[NSColor purpleColor]];
	[self addAnnotation:seg];
	
	// Update positions in the x and y text fields
	
	[xCell setStringValue:[NSString stringWithFormat:@"x: %12.5f", hotSpot.x] ];
	[yCell setStringValue:[NSString stringWithFormat:@"y: %12.5f", hotSpot.y] ];
	
	[self displayIfNeeded];
	dataMissingLastTime = NO;
	
	return;
}

- (void)mouseMoved:(NSEvent *)theEvent {
	
	NSEnumerator *en = [displayList objectEnumerator];
	id obj;
	while (obj = [en nextObject]) {
		
		NSPoint hotSpot;
		hotSpotFound = NO;
		
		// Note this "&" will select one or more columns since we have bit fields here...
		if ([obj tag] & (FLAG_TAG | tagOfInterest)) {
			
			if (hotSpotIsCenterOfSegment) 
			{
				hotSpot = [(Segment *)obj center];				
			} else 
			{
				hotSpot = [(Segment *)obj end];	
			}
			
			// Are we inside the bounding rect of this segment
			// if (NSPointInRect(pt, [obj bounds])) {
			
			NSPoint mouseLocInPixels = [theEvent locationInWindow];
			NSPoint hotSpotInPixels = [self convertPoint:hotSpot toView: nil];
			//NSPoint mouseInReal = [self convertPoint:mouseLocInPixels fromView: nil];
			//hotSpotInReal==hotSpot so this is worthless --> NSPoint hotSpotInReal = [self convertPoint:hotSpotInPixels fromView: nil];
			
			// Are we within distanceToLine pixels of the line in screen coordinates?
			double distSqr = (mouseLocInPixels.x - hotSpotInPixels.x)*(mouseLocInPixels.x - hotSpotInPixels.x) + 
				(mouseLocInPixels.y - hotSpotInPixels.y)*(mouseLocInPixels.y - hotSpotInPixels.y);
			
			if (distSqr < (distanceToLine*distanceToLine)) {
				
				hotSpotFound = YES;
				xAtCursor = hotSpot.x;
				yAtCursor = hotSpot.y;
				objAtCursor = [obj shipTrackRecord];
				
				[self removeAnnotations];  // Remove the old
				
				// Horizontal line intersecting cursor hot spot
				
				Segment *seg = [[Segment alloc] initFrom:NSMakePoint(NSMinX([self bounds]), hotSpot.y) 
													  to:NSMakePoint(NSMaxX([self bounds]), hotSpot.y) 
													view:self record:nil];
				[seg setColor:[NSColor purpleColor]];
				[self addAnnotation:seg];
				
				// Vertical line intersecting cursor hot spot
				
				seg = [[Segment alloc] initFrom:NSMakePoint(hotSpot.x, NSMinY([self bounds])) 
											 to:NSMakePoint(hotSpot.x, NSMaxY([self bounds])) 
										   view:self record:nil];
				[seg setColor:[NSColor purpleColor]];
				[self addAnnotation:seg];
				
				// Update positions in the x and y text fields
				
				[xCell setStringValue:[NSString stringWithFormat:@"x: %12.5f", xAtCursor] ];
				[yCell setStringValue:[NSString stringWithFormat:@"y: %12.5f", yAtCursor] ];
								
				return;
			}
		}
	}
	
	// No segment should be highlighted
	[self dataMissing];
}

- (void)zoomToRect:(NSRect)rect 
{
	xmin = rect.origin.x;
	ymin = rect.origin.y;
	xmax = xmin + rect.size.width;
	ymax = ymin + rect.size.height;
	
	[xminCell  setDoubleValue:xmin];
	[xmaxCell  setDoubleValue:xmax];
	
	[yminCell  setDoubleValue:ymin];
	[ymaxCell  setDoubleValue:ymax];
	
	[self setBounds:(NSMakeRect(xmin, ymin, xmax-xmin, ymax-ymin) ) ];
	[self setNeedsDisplay:YES];
}

- (void)zoomBy:(double)xScale:(double)yScale
{	
	double xRange = (xmax - xmin) * xScale;
	double yRange = (ymax - ymin) * yScale;
	
	xmin -= xRange; //FIXME if (xmin < 0) xmin = 0.;
	xmax += xRange;
	ymin -= yRange;
	ymax += yRange;
	
	[xminCell  setDoubleValue:xmin];
	[xmaxCell  setDoubleValue:xmax];
	[yminCell  setDoubleValue:ymin];
	[ymaxCell  setDoubleValue:ymax];
	
	[self getForm];
	[self getFormAndScaleView];	
}

- (IBAction)zoomOut:(id)sender 
{
	double xScale = 0.5;
	double yScale = xScale;
	
	[self zoomBy:xScale:yScale];
}

- (IBAction)zoomIn:(id)sender {
	double xScale = -0.25;
	double yScale = xScale;
	
	[self zoomBy:xScale:yScale];
}

- (void)pageBy:(double)deltaX:(double)deltaY
{	
	xmin += deltaX; 
	xmax += deltaX;
	ymin += deltaY;
	ymax += deltaY;
	
	[xminCell  setDoubleValue:xmin];
	[xmaxCell  setDoubleValue:xmax];
	[yminCell  setDoubleValue:ymin];
	[ymaxCell  setDoubleValue:ymax];
	
	[self getFormAndScaleView];	
}

- (IBAction)pageRight:(id)sender
{
	[self getForm];
	[self pageBy:(xmax - xmin)*xstep:0];
	
}

- (IBAction)pageLeft:(id)sender
{
	[self getForm];
	[self pageBy:-(xmax - xmin)*xstep:0];
	
	
}

- (id)stretch:(double)dx:(double)dy
{
	// keep left/bottom edge in current location...
	[xminCell  setDoubleValue:xmin];
	[xmaxCell  setDoubleValue:xmax-2*dx];
	[yminCell  setDoubleValue:ymin];
	[ymaxCell  setDoubleValue:ymax-2*dy];
	[self getFormAndScaleView];
	return self;
}

- (IBAction)stretchX:(id)sender
{	
	[self getForm];
	[self stretch:(xmax - xmin)*xstep/2:0];
}

- (IBAction)stretchY:(id)sender
{	
	[self getForm];
	[self stretch:0:(ymax - ymin)*xstep/2];
}

- (IBAction)shrinkX:(id)sender
{	
	[self getForm];
	[self stretch:-(xmax - xmin)*xstep/2:0];
}

- (IBAction)shrinkY:(id)sender
{	
	[self getForm];
	[self stretch:0:-(ymax - ymin)*xstep/2];
}

- (IBAction)pageToFirst:(id)sender
{
	[self getForm];
	[self pageBy:-xmin:0];	
}

- (IBAction)pageToLast:(id)sender
{
	// overridden if available
}

- (IBAction)pageUp:(id)sender
{
	[self getForm];
	[self pageBy:0:(ymax - ymin)*xstep];
	
}

- (IBAction)pageDown:(id)sender
{
	[self getForm];
	[self pageBy:0:-(ymax - ymin)*xstep];
	
}

-(BOOL)isOpaque { return NO; }   // Because DataView, and StatView are opaque

@end
