//
//  XTPrefsWindowController.m
//  TadsTerp
//
//  Created by Rune Berg on 14/10/14.
//  Copyright (c) 2014 Rune Berg. All rights reserved.
//

#import "XTPrefsWindowController.h"
#import "XTFontManager.h"
#import "XTParameterizedFont.h"
#import "XTUIUtils.h"
#import "XTNotifications.h"
#import "XTLogger.h"
#import "XTAllocDeallocCounter.h"
#import "XTLoggerAndLevel.h"


@interface XTPrefsWindowController ()

@property XTPrefs *prefs;
@property XTFontManager *fontManager;

@property (weak) IBOutlet NSTabView *tabView;
@property IBOutlet NSTabViewItem *devModeTabViewItem;
	// this is shown/hidden dynamically, so keep a ref. to it

// Folder / Files tab:

@property NSArray *selectableDirectoryModesForGames;
@property NSArray *selectableDirectoryModes; // for saves, transcripts, and cmd scripts
@property NSArray *selectableFileNameModesForSaves;
@property NSArray *selectableFileNameModesForTranscripts;
@property NSArray *selectableFileNameModesForCommandScripts;

@property NSArray *selectableIOSafetyModesForRead;
@property NSArray *selectableIOSafetyModesForWrite;

@property (weak) IBOutlet NSTextField *gamesDirectoryTextField;
@property (weak) IBOutlet NSTextField *savesDirectoryTextField;
@property (weak) IBOutlet NSTextField *transcriptsDirectoryTextField;
@property (weak) IBOutlet NSTextField *commandScriptsDirectoryTextField;

// Fonts tab:

@property NSString *parameterizedFontBeingSelected;
	//TODO nil when...

@property (weak) IBOutlet NSTextField *defaultGameFontTextField;
@property (weak) IBOutlet NSButton *inputFontSameAsDefaultGameFontButton;
@property (weak) IBOutlet NSTextField *minAllowedFontSize;
@property (weak) IBOutlet NSTextField *maxAllowedFontSize;

// Colors tab:

@property (weak) IBOutlet NSColorWell *statusLineTextColorWell;
@property (weak) IBOutlet NSColorWell *statusLineBackgroundColorWell;
@property (weak) IBOutlet NSColorWell *outputAreaTextColorWell;
@property (weak) IBOutlet NSColorWell *outputAreaInputColor;
@property (weak) IBOutlet NSColorWell *outputAreaBackgroundColor;

// Layout tab:

@property NSArray *selectableGameWindowStartModes;

// Misc. tab:

@property NSArray *selectableScrollbackBufferSizes;
@property NSArray *selectableTads2Encodings;

// Dev mode tab:

@property (weak) IBOutlet NSTableView *logLevelTableView;
@property NSArray *selectableLogLevels;
@property NSMutableArray *logLevelPerLogger; // ...of XTLoggerAndLevel, sorted on class name

@property IBOutlet NSArrayController* selectableLogLevelsArrayController;
	// https://stackoverflow.com/questions/14708947/nspopupbutton-in-view-based-nstableview-getting-bindings-to-work
@property IBOutlet NSArrayController* logLevelsSortedOnClassNameArrayController; // binds to logLevelPerLogger

// "View" fields, just for the purpose of the Prefs dialog:

@property NSURL *visibleGamesDirectory;
@property NSURL *visibleSavesDirectory;
@property NSURL *visibleTranscriptsDirectory;
@property NSURL *visibleCommandScriptsDirectory;

@end


@implementation XTPrefsWindowController

#define KEY_MODE @"mode"
#define KEY_LABEL @"label"

#define KEY_LEVEL @"level"

static XTLogger* logger;

static NSRange noSelectionRange;

+ (void)initialize
{
	logger = [XTLogger loggerForClass:[XTPrefsWindowController class]];
	noSelectionRange = NSMakeRange(0, 0);
}

OVERRIDE_ALLOC_FOR_COUNTER

OVERRIDE_DEALLOC_FOR_COUNTER

- (id)initWithWindowNibName:(NSString *)windowNibName
{
	self = [super initWithWindowNibName:windowNibName];
	if (self) {
		[self myCustomInit];
	}
	return self;
}

- (void)myCustomInit
{
	_fontManager = [XTFontManager fontManager];
	
	_selectableDirectoryModesForGames = @[
		@{KEY_MODE: XTPREFS_DIRECTORY_MODE_NONE,
		  KEY_LABEL: @"Whatever"},
		@{KEY_MODE: XTPREFS_DIRECTORY_MODE_LAST_SELECTED,
		  KEY_LABEL: @"Last folder used for this:"},
		@{KEY_MODE: XTPREFS_DIRECTORY_MODE_SPECIFIC,
		  KEY_LABEL: @"Specific folder selected below: "}
	];
	
	_selectableDirectoryModes =	@[
		@{KEY_MODE: XTPREFS_DIRECTORY_MODE_NONE,
		  KEY_LABEL: @"Whatever"},
		@{KEY_MODE: XTPREFS_DIRECTORY_MODE_LAST_SELECTED,
		  KEY_LABEL: @"Last folder used for this:"},
		@{KEY_MODE: XTPREFS_DIRECTORY_MODE_CURRENT_GAMEFILE,
		  KEY_LABEL: @"Running game's folder"},
		@{KEY_MODE: XTPREFS_DIRECTORY_MODE_SPECIFIC,
		  KEY_LABEL: @"Specific folder selected below:"}
	];
	
	_selectableFileNameModesForSaves = @[
		@{KEY_MODE: XTPREFS_FILE_NAME_MODE_DATE_TIME,
		  KEY_LABEL: @"<game file>-<timestamp>.sav|t3v"},
		@{KEY_MODE: XTPREFS_FILE_NAME_MODE_GAME_FILE,
		  KEY_LABEL: @"<game file>.sav|t3v"},
		@{KEY_MODE: XTPREFS_FILE_NAME_MODE_UNTITLED,
		  KEY_LABEL: @"untitled.sav|t3v"}
	];
	
	_selectableFileNameModesForTranscripts = @[
		@{KEY_MODE: XTPREFS_FILE_NAME_MODE_DATE_TIME,
		  KEY_LABEL: @"<game file>-<timestamp>.txt"},
		@{KEY_MODE: XTPREFS_FILE_NAME_MODE_GAME_FILE,
		  KEY_LABEL: @"<game file>.txt"},
		@{KEY_MODE: XTPREFS_FILE_NAME_MODE_UNTITLED,
		  KEY_LABEL: @"untitled.txt"}
	 ];
	
	_selectableFileNameModesForCommandScripts = @[
	   @{KEY_MODE: XTPREFS_FILE_NAME_MODE_DATE_TIME,
		 KEY_LABEL: @"<game file>-<timestamp>.cmd"},
	   @{KEY_MODE: XTPREFS_FILE_NAME_MODE_GAME_FILE,
		 KEY_LABEL: @"<game file>.cmd"},
	   @{KEY_MODE: XTPREFS_FILE_NAME_MODE_UNTITLED,
		 KEY_LABEL: @"untitled.cmd"}
	   ];
	
	_selectableIOSafetyModesForRead = @[
		@{KEY_MODE: XTPREFS_IO_SAFETY_MODE_NO_ACCESS,
		  KEY_LABEL: @"None"},
		@{KEY_MODE: XTPREFS_IO_SAFETY_MODE_GAME_DIR_ONLY,
		  KEY_LABEL: @"Running game's folder only"},
		@{KEY_MODE: XTPREFS_IO_SAFETY_MODE_ANYWHERE,
		  KEY_LABEL: @"Anywhere"}
	];
	
	_selectableIOSafetyModesForWrite = @[
		@{KEY_MODE: XTPREFS_IO_SAFETY_MODE_NO_ACCESS,
		  KEY_LABEL: @"None"},
		@{KEY_MODE: XTPREFS_IO_SAFETY_MODE_GAME_DIR_ONLY,
		  KEY_LABEL: @"Running game's folder only"},
		@{KEY_MODE: XTPREFS_IO_SAFETY_MODE_ANYWHERE,
		  KEY_LABEL: @"Anywhere"}
	];
	
	_selectableGameWindowStartModes = @[
		@{KEY_MODE: XTPREFS_GAME_WINDOW_START_MODE_SAME_AS_LAST,
		  KEY_LABEL: @"Same as last game window "},
		@{KEY_MODE: XTPREFS_GAME_WINDOW_START_MODE_NICE_IN_MIDDLE,
		  KEY_LABEL: @"Nicely in the middle of the screen "},
		@{KEY_MODE: XTPREFS_GAME_WINDOW_START_MODE_WHATEVER,
		  KEY_LABEL: @"Whatever "}
	];
	
	_selectableScrollbackBufferSizes = @[
		@{KEY_MODE: [NSNumber numberWithInteger:XTPREFS_SCROLLBACK_BUFFER_SIZE_50KB],
		  KEY_LABEL: @"50 KB"},
		@{KEY_MODE: [NSNumber numberWithInteger:XTPREFS_SCROLLBACK_BUFFER_SIZE_100KB],
		  KEY_LABEL: @"100 KB"},
		@{KEY_MODE: [NSNumber numberWithInteger:XTPREFS_SCROLLBACK_BUFFER_SIZE_200KB],
		  KEY_LABEL: @"200 KB"},
		@{KEY_MODE: [NSNumber numberWithInteger:XTPREFS_SCROLLBACK_BUFFER_SIZE_500KB],
		  KEY_LABEL: @"500 KB"},
		@{KEY_MODE: [NSNumber numberWithInteger:XTPREFS_SCROLLBACK_BUFFER_SIZE_1000KB],
		  KEY_LABEL: @"1 MB"},
		@{KEY_MODE: [NSNumber numberWithInteger:XTPREFS_SCROLLBACK_BUFFER_SIZE_2000KB],
		  KEY_LABEL: @"2 MB"},
		@{KEY_MODE: [NSNumber numberWithInteger:XTPREFS_SCROLLBACK_BUFFER_SIZE_5000KB],
		  KEY_LABEL: @"5 MB"}
	];
	
	// Looks hairy, eh? Remember, we're building an array of dicts, each dict with two entries.
	NSMutableArray *tempSelectableTads2Encodings = [NSMutableArray array];
	const NSStringEncoding *encodingsZeroTermd = [NSString availableStringEncodings];
	for (const NSStringEncoding *enc = encodingsZeroTermd; *enc != 0; enc++) {
		NSNumber *encKey = [NSNumber numberWithUnsignedInteger:*enc];
		NSString *encName = [NSString localizedNameOfStringEncoding:*enc];
		if ([encName localizedCaseInsensitiveContainsString:@"UTF"] ||
			[encName localizedCaseInsensitiveContainsString:@"Unicode"]) {
			// Multi-byte encodings aren't relevant for T2
			continue;
		}
		NSMutableDictionary *tempEncEntry = [NSMutableDictionary dictionary];
		[tempEncEntry setObject:encKey forKey:KEY_MODE];
		[tempEncEntry setObject:encName forKey:KEY_LABEL];
		NSDictionary *encEntry = [NSDictionary dictionaryWithDictionary:tempEncEntry]; // so it's r/o
		[tempSelectableTads2Encodings addObject:encEntry];
	}
	_selectableTads2Encodings = tempSelectableTads2Encodings;

	_selectableLogLevels = @[
		@{KEY_LEVEL: [NSNumber numberWithInteger:XT_LEVEL_TRACE],
		  KEY_LABEL: @"Trace [" XT_LEVEL_LETTER_TRACE @"]"},
		@{KEY_LEVEL: [NSNumber numberWithInteger:XT_LEVEL_DEBUG],
		  KEY_LABEL: @"Debug [" XT_LEVEL_LETTER__DEBUG @"]"},
		@{KEY_LEVEL: [NSNumber numberWithInteger:XT_LEVEL_INFO],
		  KEY_LABEL: @"Info [" XT_LEVEL_LETTER_INFO @"]"},
		@{KEY_LEVEL: [NSNumber numberWithInteger:XT_LEVEL_WARN],
		  KEY_LABEL: @"Warning [" XT_LEVEL_LETTER_WARN @"]"},
		@{KEY_LEVEL: [NSNumber numberWithInteger:XT_LEVEL_ERROR],
		  KEY_LABEL: @"Error [" XT_LEVEL_LETTER_ERROR @"]"},
		@{KEY_LEVEL: [NSNumber numberWithInteger:XT_LEVEL_FATAL],
		  KEY_LABEL: @"Fatal [" XT_LEVEL_LETTER_FATAL @"]"},
		@{KEY_LEVEL: [NSNumber numberWithInteger:XT_LEVEL_NONE],
		  KEY_LABEL: @"(Print none)"}
	 ];

	_logLevelPerLogger = [NSMutableArray arrayWithCapacity:100];

	_parameterizedFontBeingSelected = nil;
}

+ (XTPrefsWindowController *)controllerWithPrefs:(XTPrefs *)prefs
{
	XT_TRACE_ENTRY;
	
	XTPrefsWindowController *wc = [[XTPrefsWindowController alloc] initWithWindowNibName:@"XTPrefsWindowController"];
	wc.prefs = prefs;
	[wc.prefs startObservingChangesToAll:wc];
		// no stop... needed for this

	return wc;
}

- (void)windowDidLoad
{
	XT_TRACE_ENTRY;

	[super windowDidLoad];

	[self initLoglevelsFromPrefs];
	[self syncVisibleDirectoryFields];
	[self showOrHideDevModeTabViewItem];
	
	// Disallow selecting rows
	[self.logLevelTableView deselectAll:nil];
}

- (void)windowWillClose:(NSNotification *)notification
{
	XT_TRACE_ENTRY;
	
	[XTNotifications notifyPrefsWindowClosed:self];
}

//------- NSTableViewDelegate -------

// Disallow selecting rows
- (BOOL)tableView:(NSTableView *)aTableView shouldSelectRow:(NSInteger)rowIndex
{
	return NO;
}

//------- UI event handlers -------

- (IBAction)selectGamesDirectory:(id)sender
{
	NSURL *dirUrl = [XTUIUtils runModalOpenDirectorySheetForWindow:self.window
											   defaultDirectoryUrl:self.prefs.gamesDirectoryWhenSpecific.value];
	if (dirUrl != nil) {
		self.prefs.gamesDirectoryWhenSpecific.value = dirUrl;
	}
	[self deselectTextIn:self.gamesDirectoryTextField];
}

- (IBAction)selectSavesDirectory:(id)sender
{
	NSURL *dirUrl = [XTUIUtils runModalOpenDirectorySheetForWindow:self.window
											   defaultDirectoryUrl:self.prefs.savesDirectoryWhenSpecific.value];
	if (dirUrl != nil) {
		self.prefs.savesDirectoryWhenSpecific.value = dirUrl;
	}
	[self deselectTextIn:self.savesDirectoryTextField];
}

- (IBAction)selectTranscriptsDirectory:(id)sender
{
	NSURL *dirUrl = [XTUIUtils runModalOpenDirectorySheetForWindow:self.window
											   defaultDirectoryUrl:self.prefs.transcriptsDirectoryWhenSpecific.value];
	if (dirUrl != nil) {
		self.prefs.transcriptsDirectoryWhenSpecific.value = dirUrl;
	}
	[self deselectTextIn:self.transcriptsDirectoryTextField];
}

- (IBAction)selectCommandScriptsDirectory:(id)sender
{
	NSURL *dirUrl = [XTUIUtils runModalOpenDirectorySheetForWindow:self.window
											   defaultDirectoryUrl:self.prefs.commandScriptsDirectoryWhenSpecific.value];
	if (dirUrl != nil) {
		self.prefs.commandScriptsDirectoryWhenSpecific.value = dirUrl;
	}
	[self deselectTextIn:self.commandScriptsDirectoryTextField];
}

- (IBAction)selectDefaultGameFont:(id)sender
{
	[self handleSelectFont:[self.fontManager xtadsDefaultParameterizedFontName] sender:sender];
}

- (IBAction)selectFixedWidthFont:(id)sender
{
	[self handleSelectFont:[self.fontManager xtadsFixedWidthParameterizedFontName] sender:sender];
}

- (IBAction)selectSerifedFont:(id)sender
{
	[self handleSelectFont:[self.fontManager tadsSerifParameterizedFontName] sender:sender];
}

- (IBAction)selectSansSerifFont:(id)sender
{
	[self handleSelectFont:[self.fontManager tadsSansParameterizedFontName] sender:sender];
}

- (IBAction)selectScriptFont:(id)sender
{
	[self handleSelectFont:[self.fontManager tadsScriptParameterizedFontName] sender:sender];
}

- (IBAction)selectTypeWriterFont:(id)sender
{
	[self handleSelectFont:[self.fontManager tadsTypewriterParameterizedFontName] sender:sender];
}

- (IBAction)toggleInputSameAsDefaultGameFont:(id)sender
{
	NSInteger buttonState = [sender state];
	
	if (buttonState == NSOnState) {
		[self.prefs updateInputFontWithName:self.prefs.defaultFontName.value
									   size:self.prefs.defaultFontSize.value.floatValue];
		self.prefs.inputFontUsedEvenIfNotRequestedByGame.value = [NSNumber numberWithBool:YES];
	} else {
		// leave input font as it is
	}
}

- (IBAction)selectInputFont:(id)sender
{
	[self handleSelectFont:[self.fontManager tadsInputParameterizedFontName] sender:sender];
}

- (IBAction)resetDefaultDirsAndFiles:(id)sender
{
	[self.prefs resetDefaultDirsAndFiles];
}

- (IBAction)resetDefaultFonts:(id)sender
{
	[self.prefs resetDefaultFonts];
}

- (IBAction)resetDefaultColors:(id)sender
{
	[self.prefs resetDefaultColors];
}

- (IBAction)resetDefaultLayout:(id)sender
{
	[self.prefs resetDefaultLayout];
}

- (IBAction)resetDefaultIOSafetyModes:(id)sender {
	[self.prefs resetDefaultIOSafetyModes];
}

- (IBAction)resetDefaultMisc:(id)sender {
	[self.prefs resetDefaultMisc];
	[self showOrHideDevModeTabViewItem];
}

- (IBAction)resetDefaultDevMode:(id)sender {
	[self.prefs resetDefaultDevMode];
	[self initLoglevelsFromPrefs];

	// Disallow selecting rows
	[self.logLevelTableView deselectAll:nil];
}

// If user left field blank, fill in default value
- (IBAction)selectMinAllowedFontSize:(id)sender {

	NSString *s = [self.minAllowedFontSize stringValue];
	if (s == nil || s.length == 0) {
		NSInteger i = self.prefs.minMinAllowedFontSize.integerValue;
		[self.minAllowedFontSize setIntegerValue:i];
	}
}

// If user left field blank, fill in default value
- (IBAction)selectMaxAllowedFontSize:(id)sender {
	
	NSString *s = [self.maxAllowedFontSize stringValue];
	if (s == nil || s.length == 0) {
		NSInteger i = self.prefs.maxMaxAllowedFontSize.integerValue;
		[self.maxAllowedFontSize setIntegerValue:i];
	}
}

- (IBAction)setEnableDevModeFeatures:(id)sender {
	
	[self showOrHideDevModeTabViewItem];
}

- (IBAction)setLogLevel:(id)sender {
	for (XTLoggerAndLevel *lal in self.logLevelPerLogger) {
		lal.level = [self logLevelForlabel:lal.levelLabel];
	}
	[self.prefs updateLogLevels:self.logLevelPerLogger];
}

//----------- Misc. ------------

- (void)showOrHideDevModeTabViewItem
{
	BOOL isShowingDevModeItem = (self.tabView.tabViewItems.count == 7);
	
	if (self.prefs.enableDevelopmentModeFeatures.value.boolValue) {
		if (! isShowingDevModeItem) {
			[self.tabView addTabViewItem:self.devModeTabViewItem];
		}
	} else {
		if (isShowingDevModeItem) {
			[self.tabView removeTabViewItem:self.devModeTabViewItem];
			// Turning off dev mode features, so reset them to defaults:
			[self.prefs resetDefaultDevMode];
			[self initLoglevelsFromPrefs];
		}
	}
}

- (void)handleSelectFont:(NSString *)parameterizedFontName sender:(id)sender
{
	XT_DEF_SELNAME;
	XT_TRACE_1(@"parameterizedFontName=\"%@\"", parameterizedFontName);

	// Remove focus from the text fields - otherwise our changeFont: isn't called.
	[[self.minAllowedFontSize window] makeFirstResponder:nil];
	
	//TODO check that pFN exists
	
	self.parameterizedFontBeingSelected = parameterizedFontName;
	
	NSFontManager *fontManager = [NSFontManager sharedFontManager];
	//[fontManager setDelegate:self];
	NSFont *oldFont = [self.fontManager getFontWithParameterizedName:parameterizedFontName];
	//TODO make method in xtads f.m. class
	
	XT_TRACE_1(@"oldFont=\"%@\"", oldFont.description);
	
	[fontManager setSelectedFont:oldFont isMultiple:NO];
	
	NSFontPanel *fontPanel = [NSFontPanel sharedFontPanel];
	[fontPanel makeKeyAndOrderFront:sender];
	
	// [fontManager setTarget:self]; ???
}

- (void)changeFont:(id)sender
{
	XT_DEF_SELNAME;

	NSString *paramFontName = self.parameterizedFontBeingSelected;

	NSFont *oldFont = [self.fontManager getFontWithParameterizedName:paramFontName];
		//TODO make method in xtads f.m. class
		//TODO ...or mv to f.m.
	
	XT_TRACE_1(@"oldFont=\"%@\"", oldFont.description);
	
	NSFont *newFont = [sender convertFont:oldFont];
	
	[self.fontManager setFont:newFont forParameterizedName:paramFontName];

	[self toggleInputSameAsDefaultGameFont:self.inputFontSameAsDefaultGameFontButton];
}

- (void)syncVisibleDirectoryFields {
	
	NSURL *tempVisibleGamesDirectory = nil;
	if ([XTPREFS_DIRECTORY_MODE_SPECIFIC isEqualToString:self.prefs.gamesDirectoryMode.value]) {
		tempVisibleGamesDirectory = self.prefs.gamesDirectoryWhenSpecific.value;
	} else if ([XTPREFS_DIRECTORY_MODE_LAST_SELECTED isEqualToString:self.prefs.gamesDirectoryMode.value]) {
		tempVisibleGamesDirectory = self.prefs.gamesDirectoryLastUsed.value;
	}
	self.visibleGamesDirectory = tempVisibleGamesDirectory;
	
	NSURL *tempVisibleSavesDirectory = nil;
	if ([XTPREFS_DIRECTORY_MODE_SPECIFIC isEqualToString:self.prefs.savesDirectoryMode.value]) {
		tempVisibleSavesDirectory = self.prefs.savesDirectoryWhenSpecific.value;
	} else if ([XTPREFS_DIRECTORY_MODE_LAST_SELECTED isEqualToString:self.prefs.savesDirectoryMode.value]) {
		tempVisibleSavesDirectory = self.prefs.savesDirectoryLastUsed.value;
	}
	self.visibleSavesDirectory = tempVisibleSavesDirectory;
	
	NSURL *tempVisibleTranscriptsDirectory = nil;
	if ([XTPREFS_DIRECTORY_MODE_SPECIFIC isEqualToString:self.prefs.transcriptsDirectoryMode.value]) {
		tempVisibleTranscriptsDirectory = self.prefs.transcriptsDirectoryWhenSpecific.value;
	} else if ([XTPREFS_DIRECTORY_MODE_LAST_SELECTED isEqualToString:self.prefs.transcriptsDirectoryMode.value]) {
		tempVisibleTranscriptsDirectory = self.prefs.transcriptsDirectoryLastUsed.value;
	}
	self.visibleTranscriptsDirectory = tempVisibleTranscriptsDirectory;
	
	NSURL *tempVisibleCommandScriptsDirectory = nil;
	if ([XTPREFS_DIRECTORY_MODE_SPECIFIC isEqualToString:self.prefs.commandScriptsDirectoryMode.value]) {
		tempVisibleCommandScriptsDirectory = self.prefs.commandScriptsDirectoryWhenSpecific.value;
	} else if ([XTPREFS_DIRECTORY_MODE_LAST_SELECTED isEqualToString:self.prefs.commandScriptsDirectoryMode.value]) {
		tempVisibleCommandScriptsDirectory = self.prefs.commandScriptsDirectoryLastUsed.value;
	}
	self.visibleCommandScriptsDirectory = tempVisibleCommandScriptsDirectory;
}

- (void)deselectTextIn:(NSTextField *)textField
{
	textField.currentEditor.selectedRange = noSelectionRange;
}

- (NSString *)labelForLogLevel:(NSNumber *)logLevel
{
	NSString *res = @"???";
	for (NSDictionary *dict in self.selectableLogLevels) {
		if ([logLevel isEqual:dict[KEY_LEVEL]]) {
			res = dict[KEY_LABEL];
			break;
		}
	}
	return res;
}

- (NSNumber *)logLevelForlabel:(NSString *)label
{
	NSNumber *res = nil;
	for (NSDictionary *dict in self.selectableLogLevels) {
		if ([label isEqual:dict[KEY_LABEL]]) {
			res = dict[KEY_LEVEL];
			break;
		}
	}
	return res;
}

- (void)initLoglevelsFromPrefs
{
	// Out with the old...
	NSArray *oldLogLevels = [self.logLevelsSortedOnClassNameArrayController arrangedObjects];
	[self.logLevelsSortedOnClassNameArrayController removeObjects:oldLogLevels];
	
	// ...and in with the new
	NSArray *loggerAndLevelArray = [self.prefs logLevelsSortedOnClassName]; // of XTLoggerAndLevel
	for (XTLoggerAndLevel *loggerAndLevel in loggerAndLevelArray) {
		loggerAndLevel.levelLabel = [self labelForLogLevel:loggerAndLevel.level];
		[self.logLevelsSortedOnClassNameArrayController addObject:loggerAndLevel];
	}
}

//------- KVO on Prefs object -------

- (void)observeValueForKeyPath:(NSString *)keyPath
					  ofObject:(id)object
						change:(NSDictionary *)change
					   context:(void *)context
{
	XT_DEF_SELNAME;
	XT_TRACE_1(@"keyPath=\"%@\"", keyPath);
	
	if ([object isKindOfClass:[XTPrefsItem class]]) {
		[self.prefs persist];
	} else {
		XT_WARN_1(@"called for object not XTPrefsItem, keyPath=%@", keyPath);
	}
	
	// Refresh members that are bound to the dialog window:
	[self syncVisibleDirectoryFields];
	
	if ([object isKindOfClass:[XTPrefsItem class]]) {
		XTPrefsItem *prefsItem = (XTPrefsItem *) object;
		[XTNotifications notifyPrefsChanged:self forPrefsItem:prefsItem];
	} else {
		int brkpt = 1;
	}
}

@end




