//******************************************************************************
//
// MIDITrail / MTWindowSizeCfgDlg
//
// ウィンドウサイズ設定ダイアログ
//
// Copyright (C) 2010-2017 WADA Masashi. All Rights Reserved.
//
//******************************************************************************

#import "MTParam.h"
#import "MTWindowSizeCfgDlg.h"


//##############################################################################
// ウィンドウサイズクラス
//##############################################################################
@implementation MTWindowSize

//******************************************************************************
// 初期化
//******************************************************************************
- (id)init
{
	[super init];
	
	m_Width = 0;
	m_Height = 0;
	
	return self;
}

//******************************************************************************
// サイズ登録：横
//******************************************************************************
- (void)setWidth:(unsigned int)width
{
	m_Width = width;
}

//******************************************************************************
// サイズ登録：縦
//******************************************************************************
- (void)setHeight:(unsigned int)height
{
	m_Height = height;
}

//******************************************************************************
// サイズ取得：横
//******************************************************************************
- (unsigned int)width
{
	return m_Width;
}

//******************************************************************************
// サイズ取得：縦
//******************************************************************************
- (unsigned int)height
{
	return m_Height;
}

@end


//##############################################################################
// ウィンドウサイズテキストフィールドクラス（エディットボックス）
//##############################################################################
@implementation MTWindowSizeTextField

//******************************************************************************
// テキストフィールド編集終了前イベント
//******************************************************************************
- (BOOL)textShouldEndEditing:(NSText *)textObject
{
	BOOL isOK = NO;
	
	isOK = [self isCorrectValue:[textObject string]];
	if (!isOK) {
		NSBeep();
	}
	
	return isOK;
}

//******************************************************************************
// 文字列チェック
//******************************************************************************
- (BOOL)isCorrect
{
	BOOL isOK = NO;
	
	isOK = [self isCorrectValue:[self stringValue]];
	
	return isOK;
}

//******************************************************************************
// 指定文字列チェック（内部処理用）
//******************************************************************************
- (BOOL)isCorrectValue:(NSString*)pValue
{
	BOOL isOK = NO;
	NSInteger value = 0;
	NSString* pStrValue = nil;
	
	//数値文字列かつ範囲内であることを確認
	value = [pValue integerValue];
	pStrValue = [[NSNumber numberWithInt:(int)value] stringValue];
	if ([pValue isEqualToString:pStrValue]) {
		if ((value >= MT_WINDOW_SIZE_MIN) && (value <= MT_WINDOW_SIZE_MAX)) {
			isOK = YES;
		}
	}
	return isOK;
}

@end


//##############################################################################
// ウィンドウサイズ設定ダイアログクラス
//##############################################################################
@implementation MTWindowSizeCfgDlg

//******************************************************************************
// 生成
//******************************************************************************
- (id)init
{
	id selfid = nil;
	
	//Nibファイルを指定してウィンドウコントローラを生成
	selfid = [super initWithWindowNibName:@"WindowSizeCfgDlg"];
	
	return selfid;
}

//******************************************************************************
// 破棄
//******************************************************************************
- (void)dealloc
{
	[m_pTableView setDataSource:nil];
	[m_pUserConf release];
	[super dealloc];
}

//******************************************************************************
// ウィンドウ読み込み完了
//******************************************************************************
- (void)windowDidLoad
{
	int result = 0;
	NSNotificationCenter* pCenter = nil;
	
	//ウィンドウ表示項目初期化
	//  モーダル終了後に再度モーダル表示してもwindowDidLoadは呼び出されない
	result = [self initDlg];
	if (result != 0) goto EXIT;
	
	//テーブルビュー選択のイベントハンドラ登録
	pCenter = [NSNotificationCenter defaultCenter];
	[pCenter addObserver:self
				selector:@selector(tableViewSelectionDidChange:)
					name:NSTableViewSelectionDidChangeNotification
				  object:m_pTableView];
	
EXIT:;
	if (result != 0) YN_SHOW_ERR();
	return;
}

//******************************************************************************
// モーダルウィンドウ表示
//******************************************************************************
- (void)showModalWindow
{
	m_isChanged = NO;
	
	//モーダルウィンドウ表示
	[NSApp runModalForWindow:[self window]];
	
	//モーダル表示終了後はウィンドウを非表示にする
	[[self window] orderOut:self];
}

//******************************************************************************
// 変更確認
//******************************************************************************
- (BOOL)isCahnged
{
	return m_isChanged;
}

//******************************************************************************
// OKボタン押下
//******************************************************************************
- (IBAction)onOK:(id)sender
{
	int result = 0;
	
	//エディットボックスの入力値確認
	if (![m_pEditWidth isCorrect] || ![m_pEditHeight isCorrect]) {
		//問題ありの場合はダイアログを閉じない
		NSBeep();
		goto EXIT;
	}
	
	//設定保存
	result = [self save];
	if (result != 0) goto EXIT;
	
	//ダイアログを閉じる
	m_isChanged = YES;
	[NSApp stopModal];
	
EXIT:;
	if (result != 0) YN_SHOW_ERR();
	return;
}

//******************************************************************************
// Cancelボタン押下：またはESCキー押下
//******************************************************************************
- (IBAction)onCancel:(id)sender
{
	//モーダル表示終了
	[NSApp stopModal];
}

//******************************************************************************
// クローズボタン押下
//******************************************************************************
- (void)windowWillClose:(NSNotification*)aNotification
{
	//モーダル表示終了
	[NSApp stopModal];
}

//******************************************************************************
// ダイアログ初期化
//******************************************************************************
- (int)initDlg
{
	int result = 0;
	
	//設定ファイル初期化
	result = [self initConfFile];
	if (result != 0) goto EXIT;
	
	//ウィンドウサイズテーブル初期化
	result = [self initWindowSizeTable];
	if (result != 0) goto EXIT;
	
	result = [self initWindowSizeEditBox];
	if (result != 0) goto EXIT;
	
EXIT:;
	return result;
}

//******************************************************************************
// ウィンドウサイズテーブル初期化
//******************************************************************************
- (int)initWindowSizeTable
{
	int result = 0;
	int curWidth = 0;
	int curHeight = 0;
	int selectedIndex = -1;
	int index = 0;
	NSIndexSet* indexset = nil;
	MTWindowSize* pCurWindowSize = nil;
	MTWindowSize* pWindowSize = nil;
	
	//ウィンドウサイズ配列生成
	result = [self createWindowSizeArray];
	if (result != 0) goto EXIT;
	
	//ユーザ設定ウィンドウサイズ取得
	pCurWindowSize = [[MTWindowSize alloc] init];
	result = [self getConfWindowSize:pCurWindowSize];
	if (result != 0) goto EXIT;
	
	//ユーザ選択ウィンドウサイズ取得
	curWidth = [pCurWindowSize width];
	curHeight = [pCurWindowSize height];
	
	//ウィンドウサイズ配列から現在選択中のインデックスを探す
	index = 0;
	for (pWindowSize in m_pWindowSizeArray) {
		if (([pWindowSize width] == curWidth) && ([pWindowSize height] == curHeight)) {
			selectedIndex = index;
			break;
		}
		index++;
	}
	
	//リスト一致するサイズが見つかった場合は選択状態にする
	if (selectedIndex >= 0) {		
		//選択行を設定
		indexset = [[NSIndexSet alloc] initWithIndex:selectedIndex];
		[m_pTableView selectRowIndexes:indexset byExtendingSelection:NO];
	}
	
	//複数選択を許さない
	[m_pTableView setAllowsMultipleSelection:NO];
	
	//未選択状態を許さない
	[m_pTableView setAllowsEmptySelection:NO];
	
EXIT:;
	[pCurWindowSize release];
	return result;
}

//******************************************************************************
// ウィンドウサイズ配列生成
//******************************************************************************
- (int)createWindowSizeArray
{
	int result = 0;
	unsigned int width = 0;
	unsigned int height = 0;
	CGDirectDisplayID displayId = 0;
	CFArrayRef modeArray = NULL;
	CFIndex index = 0;
	NSMutableDictionary* pDictionary = nil;
	NSString* pKey = nil;
	NSArray* pAllKeys = nil;
	NSArray* pSortedKeys = nil;
	MTWindowSize* pWindowSize = nil;;

	//----
	//CFDictionaryRef modeRef = NULL;
	//CFNumberRef numRef = NULL;
	//---- Available in Mac OS X v10.6 and later.
	CGDisplayModeRef modeRef = NULL;
	//----
	
	//ウィンドウサイズ配列の生成
	m_pWindowSizeArray = [[NSMutableArray alloc] init];
	
	//メインディスプレイID
	displayId = CGMainDisplayID();
	
	//ディスプレイモード配列取得
	//---- Deprecated in Mac OS X v10.6
	//modeArray = CGDisplayAvailableModes(displayId);
	//---- Available in Mac OS X v10.6 and later.
	modeArray = CGDisplayCopyAllDisplayModes(displayId, NULL);
	//----	
	if (modeArray == NULL) {
		result = YN_SET_ERR(@"CoreGraphics API error.", 0, 0);
		goto EXIT;
	}
	
	//ディスプレイモードごとの画面解像度を取得して辞書を作成する
	pDictionary = [[NSMutableDictionary alloc] init];
	for (index = 0; index < CFArrayGetCount(modeArray); index++) {
		//ディスプレイモードの縦横サイズ
		//---- Deprecated in Mac OS X v10.6
		//modeRef = (CFDictionaryRef)CFArrayGetValueAtIndex(modeArray, index);
		//numRef = (CFNumberRef)CFDictionaryGetValue(modeRef, kCGDisplayWidth);
		//if (numRef == NULL) {
		//	result = YN_SET_ERR(@"Program error.", 0, 0);
		//	goto EXIT;
		//}
		//CFNumberGetValue(numRef, kCFNumberLongType, &width);
		//numRef = (CFNumberRef)CFDictionaryGetValue(modeRef, kCGDisplayHeight);
		//if (numRef == NULL) {
		//	result = YN_SET_ERR(@"Program error.", 0, 0);
		//	goto EXIT;
		//}
		//CFNumberGetValue(numRef, kCFNumberLongType, &height);
		//---- Available in Mac OS X v10.6 and later.
		modeRef = (CGDisplayModeRef)CFArrayGetValueAtIndex(modeArray, index);
		width = (unsigned int)CGDisplayModeGetWidth(modeRef);
		height = (unsigned int)CGDisplayModeGetHeight(modeRef);
		//----
		
		//縦横サイズを文字列に変換：例 "00800-00600"
		pKey = [NSString stringWithFormat:@"%05d-%05d", width, height];
		
		//キーとして辞書登録する：重複するサイズを取り除くため辞書を利用している
		pWindowSize = [[MTWindowSize alloc] init];
		[pWindowSize setWidth:width];
		[pWindowSize setHeight:height];
		[pDictionary setObject:pWindowSize forKey:pKey];
		[pWindowSize release];
	}
	
	//キーの一覧を取得して昇順ソートする
	pAllKeys = [pDictionary allKeys];
	pSortedKeys = [pAllKeys sortedArrayUsingSelector:@selector(compare:)];
	
	//ウィンドウサイズ一覧作成
	for (pKey in pSortedKeys) {
		pWindowSize = [pDictionary objectForKey:pKey];
		[m_pWindowSizeArray addObject:pWindowSize];
	}
	
EXIT:;
	//CGDisplayAvailableModesで取得した配列は破棄してはならない
	//破棄すると配列を再度取得したときに破壊された配列が返される
	//if (modeArray != NULL) CFRelease(modeArray);
	[pDictionary release];
	return result;
}

//******************************************************************************
// ウィンドウサイズエディットボックス初期化
//******************************************************************************
- (int)initWindowSizeEditBox
{
	int result = 0;
	MTWindowSize* pWindowSize = nil;
	NSString* pStrWidth = nil;
	NSString* pStrHeight = nil;
	int applyToViewArea = 0;
	
	//ユーザ設定ウィンドウサイズ取得
	pWindowSize = [[MTWindowSize alloc] init];
	result = [self getConfWindowSize:pWindowSize];
	if (result != 0) goto EXIT;
	
	//ウィンドウサイズエディットボックス設定
	pStrWidth = [[NSNumber numberWithInt:[pWindowSize width]] stringValue];
	pStrHeight = [[NSNumber numberWithInt:[pWindowSize height]] stringValue];
	[m_pEditWidth setStringValue:pStrWidth];
	[m_pEditHeight setStringValue:pStrHeight];
	
	//ビュー領域適用フラグ取得
	applyToViewArea = [m_pUserConf intValueForKey:@"ApplyToViewArea" defaultValue:0];
	
	//ビュー領域適用チェックボックス初期化
	if (applyToViewArea == 0) {
		[m_pCheckBtnApplyToView setState:NSOffState];
	}
	else {
		[m_pCheckBtnApplyToView setState:NSOnState];
	}
	
EXIT:;
	return result;
}

//******************************************************************************
// テーブルビュー：表示項目数取得
//******************************************************************************
- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
{
	return [m_pWindowSizeArray count];
}

//******************************************************************************
// テーブルビュー：表示文字列取得
//******************************************************************************
- (id)tableView:(NSTableView*)aTableView
		objectValueForTableColumn:(NSTableColumn*)aTableColumn
			row:(NSInteger)rowIndex
{
	int result = 0;
	NSString* pStr = @"";
	MTWindowSize* pSize = nil;
	
	if ([[aTableColumn identifier] isEqual:@"colSize"]) {
		if (rowIndex >= [m_pWindowSizeArray count]) {
			result = YN_SET_ERR(@"Program error.", 0, 0);
			goto EXIT;
		}
		pSize = [m_pWindowSizeArray objectAtIndex:rowIndex];
		pStr = [NSString stringWithFormat:@"%u x %u", [pSize width], [pSize height]];
	}
	
EXIT:;
	if (result != 0) YN_SHOW_ERR();
	return pStr;
}

//******************************************************************************
// 設定ファイル初期化
//******************************************************************************
- (int)initConfFile
{
	int result = 0;
	
	//ユーザ設定情報初期化
	[m_pUserConf release];
	m_pUserConf = [[YNUserConf alloc] init];
	if (m_pUserConf == nil) {
		YN_SET_ERR(@"Could not allocate memory.", 0, 0);
		goto EXIT;
	}
	
	//カテゴリ／セクション設定
	[m_pUserConf setCategory:MT_CONF_CATEGORY_VIEW];
	[m_pUserConf setSection:MT_CONF_SECTION_WINDOWSIZE];
	
EXIT:;
	return result;
}

//******************************************************************************
// 設定ファイル保存
//******************************************************************************
- (int)save
{
	int result = 0;
	int width = 0;
	int height = 0;
	int applyToViewArea = 0;
	
	//エディットボックスからウィンドウサイズを取得
	width = (int)[[m_pEditWidth stringValue] integerValue];
	height = (int)[[m_pEditHeight stringValue] integerValue];
	
	//ビュー領域適用チェックボックス設定を取得
	if ([m_pCheckBtnApplyToView state] == NSOnState) {
		applyToViewArea = 1;
	}
	else {
		applyToViewArea = 0;
	}
	
	//設定保存
	[m_pUserConf setInt:width forKey:@"Width"];
	[m_pUserConf setInt:height forKey:@"Height"];
	[m_pUserConf setInt:applyToViewArea forKey:@"ApplyToViewArea"];
	
EXIT:;
	return result;
}

//******************************************************************************
// ウィンドウサイズ設定値取得
//******************************************************************************
- (int)getConfWindowSize:(MTWindowSize*)pWindowSize
{
	int result = 0;
	int width = 0;
	int height = 0;
	
	if (pWindowSize == nil) {
		result = YN_SET_ERR(@"Program error.", 0, 0);
		goto EXIT;
	}
	
	//ウィンドウサイズ設定値取得
	width = [m_pUserConf intValueForKey:@"Width" defaultValue:0];
	height = [m_pUserConf intValueForKey:@"Height" defaultValue:0];
	
	//サイズが異常な場合は初回起動時のウィンドウサイズに更新
	if ((width <= 0)
		|| (height <= 0)
		|| (width > MT_WINDOW_SIZE_MAX)
		|| (height > MT_WINDOW_SIZE_MAX)) {
		//初回起動時のウィンドウサイズ
		width = 800;
		height = 600;
	}
	
	//ウィンドウサイズ返却
	[pWindowSize setWidth:width];
	[pWindowSize setHeight:height];
	
EXIT:;
	return result;
}

//******************************************************************************
// テーブルビュー選択完了イベント
//******************************************************************************
- (void)tableViewSelectionDidChange:(NSNotification*)pNotification
{
	NSTableView* pTableView = [pNotification object];
	int result = 0;
	NSUInteger selectedIndex = 0;
	MTWindowSize* pSize = nil;
	NSString* pStrWidth = nil;
	NSString* pStrHeight = nil;
	
	//選択項目のインデックスを取得
	selectedIndex = [[pTableView selectedRowIndexes] firstIndex];
	
	//インデックスに対応する縦横サイズを取得
	if (selectedIndex >= [m_pWindowSizeArray count]) {
		result = YN_SET_ERR(@"Program error.", 0, 0);
		goto EXIT;
	}
	pSize = [m_pWindowSizeArray objectAtIndex:selectedIndex];
	
	//数値を文字列に変換
	pStrWidth = [[NSNumber numberWithInt:[pSize width]] stringValue];
	pStrHeight = [[NSNumber numberWithInt:[pSize height]] stringValue];
	
	//エディットボックスに選択されたウィンドウサイズを反映
	[m_pEditWidth setStringValue:pStrWidth];
	[m_pEditHeight setStringValue:pStrHeight];
	
EXIT:;
	return;
}

@end


