//
//  IKImageView.m
//  ImageKit
//
//  Created by H. Nikolaus Schaller on 16.11.07.
//  Copyright 2007 Golden Delicious Computers GmbH&Co. KG. All rights reserved.
//

#import "IKImageView.h"

NSString *IKToolModeMove=@"IKToolModeMove";
NSString *IKToolModeSelect=@"IKToolModeSelect";
NSString *IKToolModeCrop=@"IKToolModeCrop";
NSString *IKToolModeRotate=@"IKToolModeRotate";
NSString *IKToolModeAnnotate=@"IKToolModeAnnotate";

@implementation IKImageView

- (id) initWithFrame:(NSRect) frame
{
    if((self = [super initWithFrame:frame]))
		{
        // Initialization code here.
		}
    return self;
}

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

- (void) drawRect:(NSRect) rect
{
    // Drawing code here.
}

- (BOOL) autohidesScrollers; { return _autohidesScrollers; }
- (BOOL) autoresizes; { return _autoresizes; }
- (NSColor *) backgroundColor; { return _backgroundColor; }
- (NSString *) currentToolMode; { return _currentToolMode; }
- (id) delegate; { return _delegate; }
- (BOOL) doubleClickOpensImageEditPanel; { return _doubleClickOpensImageEditPanel; }
- (BOOL) editable; { return _editable; }
- (BOOL) hasHorizontalScroller; { return [_scrollView hasHorizontalScroller]; }
- (BOOL) hasVerticalScroller; { return [_scrollView hasVerticalScroller]; }
- (CIFilter *) imageCorrection; { return nil; }
- (CGFloat) rotationAngle; { return _rotationAngle; }
- (BOOL) supportsDragAndDrop; { return _supportsDragAndDrop; }
- (CGFloat) zoomFactor; { return _zoomFactor; }

- (void) setAutohidesScrollers:(BOOL) flag; { }
- (void) setAutoresizes:(BOOL) flag; { _autoresizes=flag; }
- (void) setBackgroundColor:(NSColor *) color; { }
- (void) setCurrentToolMode:(NSString *) mode; { }
- (void) setDelegate:(id) delegate; { _delegate=delegate; }
- (void) setDoubleClickOpensImageEditPanel:(BOOL) flag; { _doubleClickOpensImageEditPanel=flag; }
- (void) setEditable:(BOOL) flag; { _editable=flag; }
- (void) setHasHorizontalScroller:(BOOL) flag; { [_scrollView setHasHorizontalScroller:flag]; }
- (void) setHasVerticalScroller:(BOOL) flag; { [_scrollView setHasVerticalScroller:flag]; }
- (void) setImageCorrection:(CIFilter *) filter; { }
- (void) setRotationAngle:(CGFloat) angle; { _rotationAngle=angle; }
- (void) setSupportsDragAndDrop:(BOOL) flag; { _supportsDragAndDrop=flag; }
- (void) setZoomFactor:(CGFloat) zoom; { _zoomFactor=zoom; }

- (NSPoint) convertImagePointToViewPoint:(NSPoint) pnt; { }
- (NSRect) convertImageRectToViewRect:(NSRect) pnt; { }
- (NSPoint) convertViewPointToImagePoint:(NSPoint) pnt; { }
- (NSRect) convertViewRectToImageRect:(NSRect) pnt; { }
- (void) flipImageHorizontal:(id) sender; { }
- (void) flipImageVertical:(id) sender; { }
- (CGImageRef) image; { }
- (NSDictionary *) imageProperties; { }
- (NSSize) imageSize; { }
- (LKLayer *) overlayForType:(NSString *) type; { return nil; }
- (void) scrollToPoint:(NSPoint) pnt; { }
- (void) scrollToRect:(NSRect) rect; { }
- (void) setImage:(CGImageRef) image imageProperties:(NSDictionary *) meta; { }
- (void) setImageWithURL:(NSURL *) url; { }
- (void) setImageZoomFactor:(CGFloat) zoom centerPoint:(NSPoint) center; { }
- (void) setOverlay:(LKLayer *) layer forType:(NSString *) type; { }
- (void) setRotationAngle:(CGFloat) angle centerPoint:(NSPoint) center; { }
- (void) zoomImageToActualSize:(id) sender; { }
- (void) zoomImageToFit:(id) sender; { }
- (void) zoomImageToRect:(NSRect) rect; { }

@end

#if MATERIAL

- (NSView *) hitTest:(NSPoint)aPoint
{ // this is used to prevent clicks to reach the scrolled document
	NSView *v=[super hitTest:aPoint];
	if ([v isDescendantOf:[self contentView]])
		return self;	// block content view and its content - but not our scrollers
	return v;
}

- (void) mouseDown:(NSEvent *)theEvent
{
#if 0
	NSLog(@"mouseDown - loc=%@", NSStringFromPoint([theEvent locationInWindow]));
#endif
	startPt = [theEvent locationInWindow];
	if ([theEvent clickCount] == 2) {
		NSPoint pt = [self convertPoint:startPt fromView:nil];
		NSRect frame = [self frame];
#if 0
		NSLog(@"double click");
#endif
		startOrigin = [self centredPointInDocView];	
		[self scrollPointToCentre:NSMakePoint(startOrigin.x + (pt.x - (frame.origin.x+frame.size.width/2.0))*_scale/2.0,
											  startOrigin.y - (pt.y - (frame.origin.y+frame.size.height/2.0))*_scale/2.0)];	// initial move
	}
	startOrigin = [self centredPointInDocView];	
	[self setDocumentCursor:[NSCursor closedHandCursor]];
}

- (void)mouseDragged:(NSEvent *)theEvent
{
#if 0
	NSLog(@"mouseDragged - loc=%@", NSStringFromPoint([theEvent locationInWindow]));
#endif	
    [self scrollPointToCentre:
	 NSMakePoint(startOrigin.x - ([theEvent locationInWindow].x - startPt.x),
				 startOrigin.y - ([theEvent locationInWindow].y - startPt.y))];
}

- (void) mouseUp:(NSEvent *)theEvent
{
#if 0
	NSLog(@"mouseUp");
#endif	
	[self setDocumentCursor:[NSCursor pointingHandCursor]];
}

- (id) initWithFrame:(NSRect)frame
{
    if ((self = [super initWithFrame:frame])) {
		[self awakeFromNib];	// initialize everything
	}
    return self;
}

- (void) setFrameSize:(NSSize) size;
{ // keep position of document view stable even if view is resized
#if DEBUG
	NSLog(@"setframesize = %@", NSStringFromSize(size));
#endif
	[super setFrameSize:size];
}

- (void) setFrame:(NSRect) frame;
{ // keep position of document view stable even if view is resized
	NSPoint p=[self centredPointInDocView];
	// FIXME: this might resize the document view and the clip view and reset their scaling
	[super setFrame:frame];
	[self scrollPointToCentre:p];	// keep center point stable during resize of the scrollview
	//	[self zoomViewByFactor:1.0/_scale andCentrePoint:p];	// use current scale
	[self setNeedsDisplay:YES];	
}

- (void) awakeFromNib
{
	_scale = 1.0;	// initial scale as assumed by view hierarchy
	//	[self zoomViewToAbsoluteScale:[[NSUserDefaults standardUserDefaults] floatForKey:@"zoom"]];	// as defined by user defaults
	[self zoomViewToAbsoluteScale:[[[NSUserDefaultsController sharedUserDefaultsController] valueForKeyPath:@"values.zoom"] floatValue]];	// as defined by user defaults
	[[self contentView] setCopiesOnScroll:NO];	// we may have changed the scale
	if (control) 	{ // adjust
		[control setAction:@selector(zoomToValueOfControl:)];
		[control setTarget:self];
		[self reflectInControl:_scale];
	}
	[self center:nil];
	[self setDocumentCursor:[NSCursor pointingHandCursor]];
}

- (IBAction) center:(id) sender;
{
	NSRect  fr = [[self documentView] frame];
	NSPoint cp;
	cp.x = (fr.origin.x + fr.size.width / 2.0);
	cp.y = (fr.origin.y + fr.size.height / 2.0);
	[self scrollPointToCentre:cp];	// show center point
}

- (IBAction) zoomIn: (id) sender
{
	// zooms the view IN by a factor of 2 (command/action)
	
	[self zoomViewByFactor:sqrt(2.0)];
}

- (IBAction) zoomOut: (id) sender
{
	// zooms the view OUT by a factor of 2 (command/action)
	
	[self zoomViewByFactor:sqrt(0.5)];
}

- (IBAction) zoomToActualSize: (id) sender
{
	// zooms the view to 100% (command/action)
	
	[self zoomViewToAbsoluteScale:1.0];
}

- (IBAction) zoomToValueOfControl: (id) sender;
{
#if 0
	NSLog(@"temp disabled");
	return;
#endif
	if ([control respondsToSelector:@selector(minValue)]) { // stepper or slider
		double val = ([control doubleValue]-[(NSSlider *)control minValue])/([(NSSlider *)control maxValue]-[(NSSlider *)control minValue]);	// % of slider scale
#if 0
		NSLog(@"slider %.2f %%", val);
#endif
		val = exp(val*(log([self maximumScale])-log([self minimumScale]))+log([self minimumScale]));
#if 0
		NSLog(@"scale %.2f %%", val);
#endif
		[self zoomViewToAbsoluteScale:val];	
	}
	else {
		[self zoomViewToAbsoluteScale:[sender floatValue]];
	}
}

- (IBAction) zoomFitInWindow: (id) sender
{
	// zooms the view to fit within the current window (command/action)
	NSRect  sfr = [[self contentView] frame];
	[self zoomViewToFitRect:sfr];
	[self center:nil];
}

- (void) zoomViewByFactor: (float) factor
{
	NSRect  fr = [[self contentView] documentVisibleRect];
	NSPoint cp;
	
	//	cp.x = (fr.origin.x + (fr.size.width / 2.0)*factor)*_scale;	// center point before zooming
	//	cp.y = (fr.origin.y + (fr.size.height / 2.0))*_scale;
	
	cp.x = (fr.origin.x*_scale + (fr.size.width / 2.0)*_scale)*factor;	// new center point after zooming
	cp.y = (fr.origin.y*_scale + (fr.size.height / 2.0)*_scale)*factor;
	
	[self zoomViewByFactor:factor andCentrePoint:cp];
}

- (void) zoomViewToAbsoluteScale: (float) newScale
{
	// zooms the view to the scale <newScale> e.g. 2.0 = 200%, etc. The currently centred point remains centred.
	
	float factor = newScale / [self scale];
	[self zoomViewByFactor:factor];
}

- (void) zoomViewToFitRect: (NSRect) aRect
{
	NSRect  fr = [[self documentView] frame];
	
	float sx, sy;
	
	sx = aRect.size.width / fr.size.width;
	sy = aRect.size.height / fr.size.height;
	float s = MIN( sx, sy );
	
	[self zoomViewByFactor:s andCentrePoint:[self centredPointInDocView]];
}

- (void) zoomViewToRect: (NSRect) aRect;
{
	NSRect  fr = [[self contentView] documentVisibleRect];
	NSPoint cp;
	
	float sx, sy;
	
	sx = fr.size.width / aRect.size.width;
	sy = fr.size.height / aRect.size.height;
	
	cp.x = aRect.origin.x + aRect.size.width / 2.0;
	cp.y = aRect.origin.y + aRect.size.height / 2.0;
	
	[self zoomViewByFactor:MIN( sx, sy ) andCentrePoint:cp];
}

- (void)	zoomViewByFactor: (float) factor andCentrePoint:(NSPoint) p
{
#if 0
	NSLog(@"zoomViewByFactor:%.6lf andCentrePoint:%@", factor, NSStringFromPoint(p));
#endif
	if ( factor != 0.0 ) {
		NSSize  newSize;
		NSRect  fr;
		float   sc;
		
		sc = factor * [self scale];
		
		if ( sc <= [self minimumScale]+0.01) {
			sc = [self minimumScale];
			factor = sc / [self scale];
		}
		
		if ( sc >= [self maximumScale]-0.01) {
			sc = [self maximumScale];
			factor = sc / [self scale];
		}
		
		if ( sc != [self scale]) { // change scale
			_scale = sc;
			//			[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithFloat:_scale] forKey:@"zoom"];
			[[NSUserDefaultsController sharedUserDefaultsController] setValue:[NSNumber numberWithFloat:_scale] forKeyPath:@"values.zoom"];
#if 0
			NSLog(@"scale=%lf", sc);
#endif
			[self reflectInControl:_scale];
			
			fr = [[self documentView] frame];
			
			newSize.width = newSize.height = factor;
			
			[[self documentView] scaleUnitSquareToSize:newSize];
			
			fr.size.width *= factor;
			fr.size.height *= factor;
			
			[[self documentView] setFrame:fr];
			[[self documentView] setNeedsDisplay:YES];
			
			[self scrollPointToCentre:p];
			[self setNeedsDisplay:YES];
		}
	}
}

- (void)	zoomWithScrollWheelDelta:(float) delta toCentrePoint:(NSPoint) cp
{
	float factor = 1.0;
	if ( delta > 0.5 )
		factor = 0.9;
	else if (delta < -0.5)
		factor = 1.1;
	
	[self zoomViewByFactor:factor andCentrePoint:cp ];
}

- (void)	scrollWheel:(NSEvent *)theEvent
{
	if (([theEvent modifierFlags] & NSAlternateKeyMask) != 0 ) {   
		// note to self - using the current mouse position here makes zooming really difficult, contrary
		// to what you might think. It's more intuitive if the centre point remains constant
		
		NSPoint p = [self centredPointInDocView];
		[self zoomWithScrollWheelDelta:[theEvent deltaY] toCentrePoint:p];
	}
	else {
		// [super scrollWheel: theEvent]; - NO: this moves the scrollers only if they are visible at all!
		NSPoint p = [self centredPointInDocView];
		p.x += [theEvent deltaX];
		p.y -= [theEvent deltaY];
		[self scrollPointToCentre:p];
	}
}

- (NSPoint)	centredPointInDocView
{
	NSRect  fr = [[self contentView] documentVisibleRect];
	NSPoint cp;
	
	cp.x = (fr.origin.x + (fr.size.width / 2.0))*_scale;
	cp.y = (fr.origin.y + (fr.size.height / 2.0))*_scale;
	return cp;
}

- (void) scrollPointToCentre:(NSPoint) aPoint
{
	// given a point in view coordinates, the view is scrolled so that the point is centred in the
	// current document view
	
	NSRect  fr = [[self contentView] documentVisibleRect];	// frame of the clip view in document view's coordinates
	NSPoint sp;
#if 0
	NSRect  dv = [[self documentView] frame];
	NSLog(@"target center=%@", NSStringFromPoint(aPoint));
	NSLog(@"scale=%f", _scale);
	NSLog(@"[self frame]=%@", NSStringFromRect([self frame]));
	NSLog(@"[self centredPointInDocView]=%@", NSStringFromPoint([self centredPointInDocView]));
	NSLog(@"[contentView frame]=%@", NSStringFromRect([[self contentView] frame]));
	NSLog(@"[contentView bounds]=%@", NSStringFromRect([[self contentView] bounds]));
	NSLog(@"[documentView frame]=%@", NSStringFromRect([[self documentView] frame]));
	NSLog(@"[documentView bounds]=%@", NSStringFromRect([[self documentView] bounds]));
	NSLog(@"[contentView documentVisibleRect]=%@", NSStringFromRect(fr));
	
#endif
	sp.x = (aPoint.x - ( fr.size.width / 2.0 ) *_scale);
	sp.y = (aPoint.y - ( fr.size.height / 2.0 ) *_scale);
#if 0
	NSLog(@"scroll to point=%@", NSStringFromPoint(sp));
#endif
	//	[self scrollPoint:sp];
	[[self contentView] scrollToPoint:sp];
	[[self documentView] setNeedsDisplay:YES];
	[self reflectScrolledClipView:[self contentView]];
#if 0
	if (!NSEqualPoints(aPoint, [self centredPointInDocView])) {
		NSLog(@"scroll point to center failed!!!");
		NSLog(@"[self frame]=%@", NSStringFromRect([self frame]));
		NSLog(@"[contentView frame]=%@", NSStringFromRect([[self contentView] frame]));
		NSLog(@"[contentView bounds]=%@", NSStringFromRect([[self contentView] bounds]));
		NSLog(@"[documentView frame]=%@", NSStringFromRect([[self documentView] frame]));
		NSLog(@"[documentView bounds]=%@", NSStringFromRect([[self documentView] bounds]));
		NSLog(@"[contentView documentVisibleRect]=%@", NSStringFromRect(fr));
		NSLog(@"target=%@", NSStringFromPoint(aPoint));
		NSLog(@"result=%@", NSStringFromPoint([self centredPointInDocView]));
	}
#endif
}

- (float) scale
{
	// returns the current scaling factor. 1.0 = 100%, i.e. actual size.
	if (_scale == 0.0) {
		NSLog(@"!!! scale == 0.0 !!!");
	}
	return _scale;
}

#endif