//
//  XTUIUtils.m
//  TadsTerp
//
//  Created by Rune Berg on 29/09/14.
//  Copyright (c) 2014 Rune Berg. All rights reserved.
//

#import "osxtads.h"
#import "osifc.h"
#import "XTUIUtils.h"
#import "XTNotifications.h"
#import "XTLogger.h"
#import "XTScrollView.h"
#import "XTMainTextView.h"


@implementation XTUIUtils

static XTLogger* logger;

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

+ (void)showModalErrorDialogInWindow:(NSWindow *)window
						 messageText:(NSString *)messageText
{
	NSAlert *alert = [[NSAlert alloc] init];
	[alert setMessageText:messageText];
	NSAlertStyle alertStyle = NSWarningAlertStyle; //NSInformationalAlertStyle;
	[alert setAlertStyle:alertStyle];
	//TODO ideally call setIcon too
	[alert addButtonWithTitle:@"OK"];
	
	[XTNotifications notifyModalPanelOpened:self];

	if (window != nil) {
		// modal dialog box attached to top of <window>
		[self runModalSheet:alert forWindow:window];
	} else {
		// free-standing modal dialog box
		[alert runModal];
	}

	[XTNotifications notifyModalPanelClosed:self];
}

+ (BOOL)confirmAbortRunningGameInWindow:(NSWindow *)window
							messageText:(NSString *)messageText
						informativeText:(NSString *)informativeText
			  continuePlayingButtonText:(NSString *)continuePlayingButtonText
				  quitPlayingButtonText:(NSString *)quitPlayingButtonText
{
	XT_DEF_SELNAME;
	
	BOOL res = NO; // default is: "continue playing"
	
	NSAlert *alert = [[NSAlert alloc] init];
	[alert setMessageText:messageText];
	[alert setInformativeText:informativeText];
	[alert addButtonWithTitle:continuePlayingButtonText];
	[alert addButtonWithTitle:quitPlayingButtonText];
	[alert setAlertStyle:NSWarningAlertStyle];
	
	NSInteger buttonIdx = [self runModalSheet:alert forWindow:window];

	if (buttonIdx != NSAlertFirstButtonReturn) {
		res = YES;
	}
	
	XT_TRACE_1(@"-> %d", res);
	
	return res;
}

+ (NSInteger)runModalSheet:(NSAlert *)sheet forWindow:(NSWindow *)window
{
	// beginSheetModalForWindow doesn't block, but I found a solution here:
	// http://stackoverflow.com/questions/604768/wait-for-nsalert-beginsheetmodalforwindow
	// (Note: blocks in a app-global fashion, but we can live with that :-))

	XT_DEF_SELNAME;
	
	[XTNotifications notifyModalPanelOpened:self];

	[sheet beginSheetModalForWindow:window completionHandler:^(NSModalResponse returnCode) {
		[NSApp stopModalWithCode:returnCode];
	}];
	
	NSInteger modalCode = [NSApp runModalForWindow:window];
	
	[XTNotifications notifyModalPanelClosed:self];

	XT_TRACE_1(@"-> %d", modalCode);
	
	return modalCode;
}

+ (NSURL *)runModalOpenDirectorySheetForWindow:(NSWindow *)window
						   defaultDirectoryUrl:(NSURL *)defaultDirectoryUrl
{
	XT_DEF_SELNAME;

	NSOpenPanel* panel = [NSOpenPanel openPanel];
	[panel setTitle:@"Select Directory"];
	[panel setCanChooseFiles:NO];
	[panel setCanChooseDirectories:YES];
	[panel setDirectoryURL:defaultDirectoryUrl];
	//TODO try to hide files
	
	NSURL* __block tempDirUrl = nil;

	[XTNotifications notifyModalPanelOpened:self];
	
	[panel beginSheetModalForWindow:window completionHandler:^(NSModalResponse returnCode) {
		tempDirUrl = [[panel URLs] objectAtIndex:0];
		XT_TRACE_2(@"completionHandler got: \"%@\" (%ld)", tempDirUrl, returnCode);
		[NSApp stopModalWithCode:returnCode];
	}];
	
	NSInteger modalCode = [NSApp runModalForWindow:window];
	
	[XTNotifications notifyModalPanelClosed:self];
	
	NSURL*  dirUrl = nil;
	if (modalCode == 1) {
		// "Open" selected
		dirUrl = tempDirUrl;
	}
	
	XT_TRACE_2(@"-> modalCode=%ld, dirUrl=\"%@\"", modalCode, dirUrl);
	
	return dirUrl;
}

+ (BOOL)buttonHasKeyEquiv:(NSButton *)button
{
	NSString *keyEquiv = button.keyEquivalent;
	BOOL res = ([keyEquiv length] >= 1);
	return res;
}

+ (void)addInputDialogButton:(NSString *)title toAlert:(NSAlert *)alert
{
	[alert addButtonWithTitle:title];
}

+ (void)addInputDialogCustomButton:(NSString *)s toAlert:(NSAlert *)alert
{
	NSRange rangeShortcutMarker = [s rangeOfString:@"&"];
	NSString *prefix = nil;
	NSString *shortcutKey = nil;
	NSString *suffix = nil;
	
	if (rangeShortcutMarker.location == NSNotFound) {
		prefix = s;
	} else {
		prefix = [s substringToIndex:rangeShortcutMarker.location];
		if (rangeShortcutMarker.location + 1 < s.length) {
			NSRange rangeShortcutKey = NSMakeRange(rangeShortcutMarker.location + 1, 1);
			shortcutKey = [s substringWithRange:rangeShortcutKey];
			if (rangeShortcutKey.location + 1 < s.length) {
				suffix = [s substringFromIndex:rangeShortcutKey.location + 1];
			}
		}
	}
	
	NSButton *button = [alert addButtonWithTitle:@"temp"];
	NSMutableString *title = [NSMutableString string];
	
	if (prefix != nil && prefix.length >= 1) {
		[title appendString:prefix];
	}
	if (shortcutKey != nil) {
		[title appendString:shortcutKey];
		NSString *shortcutKeyLowerCase = [shortcutKey lowercaseString];
		[button setKeyEquivalent:shortcutKeyLowerCase];
	}
	if (suffix != nil && suffix.length >= 1) {
		[title appendString:suffix];
	}
	
	[button setTitle:title];
}

+ (NSUInteger)runModalInputDialogForWindow:(NSWindow *)window
									 title:(NSString *)title
					   standardButtonSetId:(NSUInteger)standardButtonSetId
						 customButtomSpecs:(NSArray *)customButtomSpecs
							  defaultIndex:(NSUInteger)defaultIndex
							   cancelIndex:(NSUInteger)cancelIndex
									iconId:(XTadsInputDialogIconId)iconId
{
	XT_DEF_SELNAME;
	
	NSUInteger res = 0; // defalt result, in case anything goes wrong
	
	NSUInteger numberOfButtons = 0;
	
	NSAlert *alert = [[NSAlert alloc] init];
	[alert setMessageText:title];
	
	// Create the buttons
	
	switch (standardButtonSetId) {
		case OS_INDLG_OK:
			[self addInputDialogButton:@"OK" toAlert:alert];
			numberOfButtons = 1;
			break;
		case OS_INDLG_OKCANCEL:
			[self addInputDialogButton:@"Cancel" toAlert:alert];
			[self addInputDialogButton:@"OK" toAlert:alert];
			numberOfButtons = 2;
			break;
		case OS_INDLG_YESNO:
			[self addInputDialogButton:@"No" toAlert:alert];
			[self addInputDialogButton:@"Yes" toAlert:alert];
			numberOfButtons = 2;
			break;
		case OS_INDLG_YESNOCANCEL:
			[self addInputDialogButton:@"Cancel" toAlert:alert];
			[self addInputDialogButton:@"No" toAlert:alert];
			[self addInputDialogButton:@"Yes" toAlert:alert];
			numberOfButtons = 3;
			break;
		default: {
			// Custom buttons
			NSEnumerator *en = [customButtomSpecs reverseObjectEnumerator];
			for (NSString *buttonSpec = [en nextObject]; buttonSpec != nil; buttonSpec = [en nextObject]) {
				[self addInputDialogCustomButton:buttonSpec toAlert:alert];
				numberOfButtons += 1;
			}
			break;
		}
	}
	
	NSArray *buttons = alert.buttons;
	if (buttons == nil || buttons.count == 0) {
		XT_WARN_0(@"no buttons");
		return res;
	}
	
	// Neuter any built-in handling of Return and Esc
	
	for (NSButton *btn in buttons) {
		NSString *keyEquiv = [btn keyEquivalent];
		BOOL isDefaultButton = [keyEquiv isEqualToString:@"\r"];  // Return
		BOOL isCancelButton = [keyEquiv isEqualToString:@"\033"]; // octal for Esc
		if (isDefaultButton || isCancelButton) {
			[btn setKeyEquivalent:@""];
		}
	}
	
	// Set key equivs for default (Return) and cancel (Esc) if so requested,
	// but only if they don't conflict with &...-spec'd key equivs.
	// (Stock NSAlert doesn't let us add explicit NSButton objects,
	// so we can't add a specialized NSButton that would support
	// multiple key equivs.)
	
	if (defaultIndex >= 1 && defaultIndex <= buttons.count) {
		NSUInteger defaultIndexRightToLeft = buttons.count - defaultIndex;
		NSButton *defaultButton = buttons[defaultIndexRightToLeft];
		if (! [self buttonHasKeyEquiv:defaultButton]) {
			[defaultButton setKeyEquivalent:@"\r"]; // Return
		}
	}
	
	if (cancelIndex >= 1 && cancelIndex <= buttons.count) {
		NSUInteger cancelIndexRightToLeft = buttons.count - cancelIndex;
		NSButton *cancelButton = buttons[cancelIndexRightToLeft];
		if (! [self buttonHasKeyEquiv:cancelButton]) {
			[cancelButton setKeyEquivalent:@"\033"]; // octal for Esc
		}
	}
	
	// Alert style (lhs icon)
	
	NSAlertStyle alertStyle = NSInformationalAlertStyle;
	if (iconId == XTadsInputDialogIconIdError) {
		alertStyle = NSCriticalAlertStyle;
	}
	[alert setAlertStyle:alertStyle];
	//TODO? ideally call setIcon too
	
	// Run the popup modally, and figure out which button was pressed
	
	NSInteger buttonIndex = [self runModalSheet:alert forWindow:window];
	
	NSUInteger resIndexRightToLeft = (buttonIndex - NSAlertFirstButtonReturn);
	res = numberOfButtons - resIndexRightToLeft;

	return res;
}

+ (NSOpenPanel *)makeFileOpenPanelWithTitle:(NSString *)title
						  allowedExtensions:(NSArray *)allowedExtensions
								 defaultDir:(NSURL *)defaultDir
{
	NSOpenPanel* panel = [NSOpenPanel openPanel];
	[panel setTitle:title];
	[panel setPrompt:@"Open"];
	[panel setMessage:title];
	[panel setShowsTagField:NO];
	BOOL allowOtherFileTypes = (allowedExtensions == nil);
	[panel setAllowsOtherFileTypes:allowOtherFileTypes];
	//[panel setExtensionHidden:NO];
	//[panel setCanSelectHiddenExtension:YES];
	[panel setAllowedFileTypes:allowedExtensions];
	if (defaultDir != nil) {
		[panel setDirectoryURL:defaultDir];
	}
	return panel;
}

+ (NSSavePanel *)makeFileSavePanelWithTitle:(NSString *)title
						  allowedExtensions:(NSArray *)allowedExtensions
								 defaultDir:(NSURL *)defaultDir
							defaultBasename:(NSString *)defaultBasename
{
	NSSavePanel* panel = [NSSavePanel savePanel];
	[panel setTitle:title];
	[panel setPrompt:@"Save"];
	[panel setMessage:title];
	[panel setShowsTagField:NO];
	BOOL allowOtherFileTypes = (allowedExtensions == nil);
	[panel setAllowsOtherFileTypes:allowOtherFileTypes];
	[panel setExtensionHidden:NO];
	[panel setCanSelectHiddenExtension:YES];
	[panel setAllowedFileTypes:allowedExtensions];
	if (defaultDir != nil) {
		[panel setDirectoryURL:defaultDir];
	}
	if (defaultBasename != nil) {
		[panel setNameFieldStringValue:defaultBasename];
	}
	return panel;
}

+ (NSScrollView*)createScrollViewWithTextViewForMainOutputArea:(id<NSTextViewDelegate>)textViewDelegate
{
	NSRect tempFrame = NSMakeRect(0.0, 0.0, 0.0, 0.0);
	XTScrollView *scrollView = [[XTScrollView alloc] initWithFrame:tempFrame];
	//scrollView.allowUserScrolling = NO;
	// allow mouse scroll wheel in main output area
	
	NSSize contentSize = [scrollView contentSize];
	[scrollView setBorderType:NSNoBorder];
	
	[scrollView setHasVerticalScroller:YES];
	[scrollView setHasHorizontalScroller:NO];
	
	[scrollView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
	[scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];
	
	NSRect tvFrame = NSMakeRect(0.0, 0.0, 0.0, 0.0);
	NSTextView *textView = [[XTMainTextView alloc] initWithFrame:tvFrame];
	[textView setMinSize:NSMakeSize(0.0, contentSize.height)];
	[textView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
	[textView setVerticallyResizable:YES];
	[textView setHorizontallyResizable:NO];
	[textView setAutoresizingMask:NSViewWidthSizable];
	NSTextContainer *textContainer = [textView textContainer];
	[textContainer setWidthTracksTextView:YES];
	
	[scrollView setDocumentView:textView];

	textView.delegate = textViewDelegate;

	return scrollView;
}

@end
