//
//  XTOutputTextView.m
//  TadsTerp
//
//  Created by Rune Berg on 13/06/14.
//  Copyright (c) 2014 Rune Berg. All rights reserved.
//

#import "XTOutputTextView.h"
#import "XTGameWindowController.h"
#import "XTOutputTextHandler.h"
#import "XTPrefs.h"
#import "XTLogger.h"


@interface XTOutputTextView ()

@property XTPrefs *prefs;

@end


@implementation XTOutputTextView

static XTLogger* logger;

+ (void)initialize
{
	logger = [XTLogger loggerForClass:[XTOutputTextView class]];
}

- (id)init
{
    self = [super init];
    if (self) {
        [self customInit];
    }
    return self;
}

- (id)initWithFrame:(NSRect)frameRect textContainer:(NSTextContainer *)container
{
	self = [super initWithFrame:frameRect textContainer:container];
    if (self) {
        [self customInit];
    }
    return self;
}

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self customInit];
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
	self = [super initWithCoder:aDecoder];
    if (self) {
        [self customInit];
    }
    return self;
}

- (void)customInit
{
	_prefs = [XTPrefs prefs];

	_showCursor = YES;

	_leftRightInset = 8.0;
	_topBottomInset = 8.0;
	
	// don't propagate our font to NSFontPanel
	[self setUsesFontPanel:NO];
	
	[self setAutomaticSpellingCorrectionEnabled:NO];

	[self syncWithPrefs];

	NSSize insetOutput = NSMakeSize(_leftRightInset, _topBottomInset);
		//TODO from prefs / defaults
	[self setTextContainerInset:insetOutput];
	
	[_prefs startObservingChangesToAll:self];
}

- (void)dealloc
{
	//TODO why never called?
	_outputTextHandler = nil;

	[_prefs stopObservingChangesToAll:self];
}

- (void)observeValueForKeyPath:(NSString *)keyPath
					  ofObject:(id)object
						change:(NSDictionary *)change
					   context:(void *)context
{
	XT_DEF_SELNAME;
	XT_TRACE_1(@"keyPath=\"%@\"", keyPath);
	
	if (object == self.prefs) {
		[self syncWithPrefs];
	} else {
		XT_TRACE_0(@"%@ OTHER");
	}
}

- (BOOL)displaysLinkToolTips
{
	return self.prefs.linksShowToolTips.boolValue;
}

- (void)syncWithPrefs
{
	BOOL spellCheck = self.prefs.spellCheckGameText.boolValue;
	[self setContinuousSpellCheckingEnabled:spellCheck];
	BOOL gramCheck = self.prefs.grammarCheckGameText.boolValue;
	[self setGrammarCheckingEnabled:gramCheck];
}

- (void)paste:(id)sender
{
	/* Make sure we only paste plain text:
	 http://stackoverflow.com/questions/7101920/when-i-paste-text-to-a-nstextview-how-to-paste-plain-text-only
	 http://stackoverflow.com/questions/8198767/how-can-you-intercept-pasting-into-a-nstextview-to-remove-unsupported-formatting
	 http://stackoverflow.com/questions/11937726/nstextview-paste-how-to-paste-bar-instead-when-foo-is-pasted
	 */
	NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
	NSString *pastedText = [pasteboard readObjectsForClasses: @[[NSString class],[NSAttributedString class]] options:nil].lastObject;
	if ([pastedText isKindOfClass:[NSAttributedString class]]) {
		// get rid of any colours, fonts, etc.
		pastedText = [(NSAttributedString *)pastedText string];
	}

	// We don't have the information to format the pasted text
	// according to the selected input font, but our XTOutputTextHandler does,
	// so let that object handle it.
	// (Ideally, we should intercept the paste event a higher level,
	// so that we wouldn't need to call back to our XTOutputTextHandler.)
	
	[self.outputTextHandler appendInput:pastedText];
}

- (BOOL)shouldDrawInsertionPoint
{
	return self.showCursor;
}

- (void)complete:(id)sender
{
	// nothing - prevent Esc / F5 from showing auto-complete popup menu
}

- (NSArray *)completionsForPartialWordRange:(NSRange)charRange indexOfSelectedItem:(NSInteger *)index
{
	return nil;
}

- (void)selectAll:(id)sender
{
	XTGameWindowController *delegate = (XTGameWindowController*)self.delegate;
	BOOL handled = [delegate handleSelectAll];
	if (! handled) {
		[super selectAll:sender];
	}
	
	//TODO why couldn't this be handled in controller's textView:doCommandBySelector ?
}

- (void)changeFont:(id)sender
{
	// Nothing - we don't want NSFontPanel to directly change our font
}

- (CGFloat)findHeight
{
	CGFloat res = self.frame.size.height;
	return res;
}

//
// Find lower end of insertion point, on "flipped" y-axis (0 being top of view)
//
- (CGFloat)findYCoordOfInsertionPoint
{
	XT_DEF_SELNAME;
	
	// http://stackoverflow.com/questions/7554472/gettting-window-coordinates-of-the-insertion-point-cocoa
	
	// -firstRectForCharacterRange:actualRange returns a frame rectangle
	// containing the insertion point or, in case there's a selection,
	// the first line of that selection. The origin of the frame rectangle is
	// in screen coordinates
	NSRange ipRange = [self selectedRange];
	NSRect ipRectScreen = [self firstRectForCharacterRange:ipRange actualRange:NULL];
	
	CGFloat res;

	if (ipRectScreen.origin.y == 0.0) {

		// Sometimes, after certain keystrokes at the more prompt (space, arrow-*, page-*), we get
		// an empty ipRectScreen. I haven't managed to understand why, but this is a way to compensate for that.
		// adhoc test game:
		//		only seems to happen at end of output, when called via resetForGameHasEndedMsg
		//		seems ins pos is somehow affected by those keys...
		//			visually, they behave different too...
		// dearbrian startup
		//		for ditto keys

		XT_WARN_0(@"got empty rectangle from firstRectForCharacterRange, using frame height - 2");
		CGFloat selfHeight = self.frame.size.height;
		res = selfHeight - 2;
		// Note: with pagination based on ins pt y coord being recalc'd after every text insertion,
		// we got this a lot more often, no matter what key is pressed :-(

	} else {
		
		// Normal case.

		// -convertRectFromScreen: converts from screen coordinates to window coordinates
		NSRect ipRectWindow = [self.window convertRectFromScreen:ipRectScreen];
		
		// The origin is the lower left corner of the frame rectangle containing the insertion point
		NSPoint ipPointWindow = ipRectWindow.origin;
		
		NSPoint ipPointSelf = [self convertPoint:ipPointWindow fromView:nil];
		// Note: NSTextView uses a flipped y-axis, so this is wrt top of frame
		
		res = ipPointSelf.y;
		
	}
	
	XT_TRACE_1(@"--> %f", res);
	return res;
}

@end
