// By Judy D. Halchin, Educational Computing Services, Allegheny College.
// You may freely copy, distribute and reuse this code. 
// Allegheny College and the author disclaim any warranty of any kind, 
// expressed or implied, as to its fitness for any particular use.
// This work was partially supported by a Teacher Preparation grant from the 
// National Science Foundation.

#import "PtrNumberLine.h"
#import "drawPointer.h"
#import <appkit/NXImage.h>
#import <appkit/Application.h>
#import <appkit/nextstd.h>

@implementation PtrNumberLine

- initFrame:(NXRect *)frameRect
{
	NXSize pointerSize, imageSize;
	float unscaleFactor;
	
	[super initFrame:frameRect];
	
	//initialize all instance variables
	  x = 0.25;
	  target = nil;
	  	
	//make an NXImage to hold the pointer and draw the pointer in it
	  pointerSize.width = POINTERSIZE;   // must be square for pointer to be
	  pointerSize.height = POINTERSIZE;  // centered correctly with the square
	  pointerNXImage = [[NXImage alloc] initSize:&pointerSize];
	  [pointerNXImage lockFocus];
	  drawPointer(POINTERSIZE);
	  [pointerNXImage unlockFocus];

	//keep track of where the pointer image is, in our coordinates
	  [numberLineNXImage getSize:&imageSize];
	  unscaleFactor = bounds.size.width 
	  								/ MAX(imageSize.width, imageSize.height);
		  
	  pointerRect.size.width = pointerSize.width * unscaleFactor;
	  pointerRect.size.height = pointerSize.height;
	  pointerRect.origin.x = x - (pointerSize.width/2 * unscaleFactor);
	  pointerRect.origin.y = -pointerSize.height;

	return self;
}

- drawSelf:(const NXRect *)rects :(int)rectCount
{
	[numberLineNXImage composite:NX_SOVER toPoint:&bounds.origin];
	[pointerNXImage  composite:NX_SOVER toPoint:&pointerRect.origin];
	return self;
}

- (float)x
{
	return x;
}

- setX:(float)newX
{
	x = newX;
	pointerRect.origin.x = x - pointerRect.size.width/2;
	return self;
}

- pointerNXImage
{
	return pointerNXImage;
}

- (NXPoint)pointerLocation
{
	return pointerRect.origin;
}

- mouseDown:(NXEvent *)theEvent
{
	BOOL mouseWentUp;
	NXEvent *nextEvent;
	NXPoint mousePoint, oldMousePoint;
	NXSize imageSize;
	int oldEventMask;
	float offset, unscaleFactor;
	
	[numberLineNXImage getSize:&imageSize];
	unscaleFactor = bounds.size.width / MAX(imageSize.width, imageSize.height);

	mousePoint = theEvent -> location;
	[self convertPoint:&mousePoint fromView:nil];
	if ([self mouse:&mousePoint inRect:&pointerRect])
	{
		oldEventMask = [window addToEventMask:NX_LMOUSEDRAGGEDMASK];
		offset = pointerRect.origin.x - mousePoint.x;
	    mouseWentUp = NO;
		while (!mouseWentUp)
	    {
	       	nextEvent = [NXApp getNextEvent:
									(NX_LMOUSEUPMASK|NX_LMOUSEDRAGGEDMASK)];
	       	if (nextEvent->type == NX_LMOUSEUP)
	           	mouseWentUp = YES;
	       	else   
	       	{
				//save old and new mouse point
			      oldMousePoint = mousePoint;
				  mousePoint = nextEvent -> location;
				  
				//calculate new rectangle for where pointer is drawn
	       		  [self convertPoint:&mousePoint fromView:nil];
				  pointerRect.origin.x = mousePoint.x + offset;
	
				//calculate new x value from pointer position
				  x = pointerRect.origin.x + pointerRect.size.width/2;			  

				//if x is out of view, revert to previous point
				  if ((x < bounds.origin.x) 
				  				|| (x > bounds.origin.x + bounds.size.width))
				  {
				  	  mousePoint = oldMousePoint;  // this has been converted
				  	  pointerRect.origin.x = mousePoint.x + offset;
				  	  x = pointerRect.origin.x + pointerRect.size.width/2;			  
				  }  
				  
				//redraw if we're supposed to
				  if (!vFlags.disableAutodisplay)
				  	  [self display];

				//notify target that x has changed
				  if (target != nil)
					  if ([target respondsTo:action])
						  [target perform:action with:self];
	    	} 
		}
		[window setEventMask:oldEventMask];		
	}	
	return self;
}

- target
{
	return target;
}

- (SEL)action
{
	return action;
}

- setTarget:anObject
{
	target = anObject;
	return self;
}

- setAction:(SEL)anAction
{
	action = anAction;
	return self;
}

- setMin:(float)newMin max:(float)newMax
{
	BOOL saveDisplayMode;
	float unscaleFactor;
	NXSize imageSize;
	

	saveDisplayMode = vFlags.disableAutodisplay;
	if (!saveDisplayMode)
		[self setAutodisplay:NO];

	[super setMin:newMin max:newMax];

	[numberLineNXImage getSize:&imageSize];
	unscaleFactor = bounds.size.width / MAX(imageSize.width, imageSize.height);
	pointerRect.size.width = POINTERSIZE * unscaleFactor;
	
	if (x < bounds.origin.x) 
		x = bounds.origin.x;
	if (x > bounds.origin.x + bounds.size.width) 
		x = bounds.origin.x + bounds.size.width;
		
	pointerRect.origin.x = x - pointerRect.size.width/2;
	
	if (!saveDisplayMode)
	{
		[self setAutodisplay:YES];
		[self display];
	}
	return self;
}

- (BOOL)acceptsFirstMouse
{
	return YES;
}

@end
