//******************************************************************************
//
// MIDITrail / MTFileViewCtrl
//
// ファイルビュー制御クラス
//
// Copyright (C) 2012-2021 WADA Masashi. All Rights Reserved.
//
//******************************************************************************

#import "YNBaseLib.h"
#import "MTFileViewCtrl.h"
#import "MTParam.h"
#import "MTURLAccessUtil.h"


//##############################################################################
// ファイル検索制御クラス
//##############################################################################
@implementation MTFileSearchController

//******************************************************************************
// 検索バー表示前
//******************************************************************************
- (void)viewWillAppear:(BOOL)animated
{
	UIViewController* pPresentingViewController = nil;
	
	[super viewWillAppear:animated];
	
	//検索バーが表示されるときナビゲーションのボタンを消す
	pPresentingViewController = [self presentingViewController];
	pPresentingViewController.navigationItem.rightBarButtonItem = nil;
}

//******************************************************************************
// 検索バー非表示前
//******************************************************************************
- (void)viewWillDisappear:(BOOL)animated
{
	UIViewController* pPresentingViewController = nil;
	
	[super viewWillDisappear:animated];
	
	//検索バーが消えるときナビゲーションのボタンを表示する
	pPresentingViewController = [self presentingViewController];
	pPresentingViewController.navigationItem.rightBarButtonItems = @[[pPresentingViewController editButtonItem]];
}

@end


//##############################################################################
// ファイルビュー制御クラス
//##############################################################################

//******************************************************************************
// プライベートメソッド定義
//******************************************************************************
@interface MTFileViewCtrl ()

//検索バー初期化
- (void)setupSearchBar;

//ファイル一覧生成
- (int)makeFileList;

//通知送信処理
- (int)postNotificationWithName:(NSString*)pName;

//テーブルセル作成：ファイル
- (UITableViewCell*)makeFileCellForIndexPath:(NSIndexPath*)indexPath;

//テーブルセル選択イベント：ファイル一覧
- (void)onSelectFileCellForIndexPath:(NSIndexPath*)indexPath;

//ファイル削除
- (int)removeFileWithPath:(NSString*)pPath;

//ファイルリネーム
- (int)renameFileWithPath:(NSString*)pSrcPath toPath:(NSString*)pDestPath;

//リフレッシュ
-(void)refreshTable:(id)sender;

@end


@implementation MTFileViewCtrl

//******************************************************************************
// 生成
//******************************************************************************
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil targetDirPath:(NSString *)pTargetDirPath
{
    NSString* pFileEditViewNibName = nil;
	NSString* pTitle = nil;
	NSArray* pPathList = nil;
	
	//対象ディレクトリパス
	if (pTargetDirPath == nil) {
		//対象ディレクトリ指定なし（ルートビュー）
		//Documentsディレクトリパスを取得
		pPathList = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
		m_pTargetDirPath = [pPathList objectAtIndex:0];
		pTitle = @"MIDI Files";
	}
	else {
		//対象ディレクトリ指定あり（子ビュー）
		m_pTargetDirPath = pTargetDirPath;
		pTitle = [m_pTargetDirPath lastPathComponent];
	}
	[m_pTargetDirPath retain];
	
	self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
		//ビュー設定
		self.title = pTitle;
		self.tabBarItem.image = [UIImage imageNamed:@"img/TabIcon"];
		
		//ファイル一覧生成
		m_pFileArray = nil;
		m_pFileAttributesDictionary = nil;
		[self makeFileList];
		
		//選択行番号
		m_SelectedFileIndex = 0;
		
		//ファイル編集ビュー制御の生成
		if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
			//iPhone / iPod touch
			pFileEditViewNibName = @"MTFileEditView_iPhone";
		}
		else {
			//iPad
			pFileEditViewNibName = @"MTFileEditView_iPad";
		}
		m_pFileEditViewCtrl = [[MTFileEditViewCtrl alloc] initWithNibName:pFileEditViewNibName bundle:nil];
		
		//ファイル選択ビュー制御の生成
		m_pDocumentPickerViewCtrl = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.midi-audio"]
																						   inMode:UIDocumentPickerModeImport];
		m_pDocumentPickerViewCtrl.delegate = self;
    }
	
	m_pChildFileViewCtrl = nil;
	
    return self;
}

//******************************************************************************
// ビュー登録完了
//******************************************************************************
- (void)viewDidLoad
{
	NSNotificationCenter* pCenter = nil;
	
    [super viewDidLoad];
	
	//追加ボタン作成
	m_pAddButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
																 target:self
																 action:@selector(onAddButton:)];
	
	//整理ボタン作成
	m_pOrganizeButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemOrganize
																	  target:self
																   action:@selector(onOrganizeButton:)];
	
	//ナビゲーションバー右側に編集ボタンと整理ボタンを登録
	self.navigationItem.rightBarButtonItems = @[[self editButtonItem], m_pOrganizeButton];
	
	//検索バー初期化
	[self setupSearchBar];
	
	//リフレッシュ制御生成生成
	m_pRefreshCtrl = [[UIRefreshControl alloc]init];
	[m_pRefreshCtrl addTarget:self action:@selector(refreshTable:) forControlEvents:UIControlEventValueChanged];
	m_pTableView.alwaysBounceVertical = YES;
	
	//テーブルビューにリフレッシュ制御を登録
    if (@available(iOS 10.0, *)) {
        m_pTableView.refreshControl = m_pRefreshCtrl;
    } else {
        [m_pTableView addSubview:m_pRefreshCtrl];
    }
	
	//通知先登録：ファイル名更新
	pCenter = [NSNotificationCenter defaultCenter];
	[pCenter addObserver:self
				selector:@selector(onEditFile:)
					name:@"MTFileViewCtrl_onEditFile"
				  object:nil];
	[m_pFileEditViewCtrl setNotificationNameForEditFile:@"MTFileViewCtrl_onEditFile"];
	
	//通知先登録：ディレクトリ作成
	[pCenter addObserver:self
				selector:@selector(onCreateDir:)
					name:@"MTFileViewCtrl_onCreateDir"
				  object:nil];
	[m_pFileEditViewCtrl setNotificationNameForCreateDir:@"MTFileViewCtrl_onCreateDir"];
	
	//通知先登録：検索結果でのファイル選択
	[pCenter addObserver:self
				selector:@selector(onSelectFileInSearchResults:)
					name:@"MTFileViewCtrl_onSelectFileInSearchResults"
				  object:nil];
	[m_pFileSearchResultsViewCtrl setNotificationNameForSelectFile:@"MTFileViewCtrl_onSelectFileInSearchResults"];
	
	return;
}

//******************************************************************************
// 検索バー初期化
//******************************************************************************
- (void)setupSearchBar
{
	//検索結果ビュー制御オブジェクトを生成
	m_pFileSearchResultsViewCtrl = [[MTFileSearchResultsViewCtrl alloc] initWithStyle:UITableViewStylePlain];
	
	//検索結果ビュー表示中にナビゲーションバーが消えないようにする
	self.definesPresentationContext = true;
	
	//検索制御オブジェクトを生成
	m_pSearchController = [[MTFileSearchController alloc] initWithSearchResultsController:m_pFileSearchResultsViewCtrl];
	
	//検索条件更新の通知先設定
	m_pSearchController.searchResultsUpdater = self;
	
	//検索バー操作時のナビゲーションバー：隠さない
	m_pSearchController.hidesNavigationBarDuringPresentation = false;
	
	//検索バーのスタイル：デフォルト
	m_pSearchController.searchBar.searchBarStyle = UISearchBarStyleDefault;
	
	//検索バーの登録
	[m_pSearchController.searchBar sizeToFit];
	if (@available(iOS 11.0, *)) {
		//iOS 11以降は検索バーをナビゲーションバーに登録
		self.navigationItem.searchController = m_pSearchController;
	}
	else {
		//検索バーをテーブルヘッダに登録
		m_pTableView.tableHeaderView = m_pSearchController.searchBar;
	}
	
	//初期表示は検索バーを隠す
	m_pTableView.contentOffset = CGPointMake(0, CGRectGetHeight(m_pSearchController.searchBar.frame));
	
	return;
}

//******************************************************************************
// インターフェース自動回転確認
//******************************************************************************
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
	return YES;
}

//******************************************************************************
// インターフェース自動回転確認（iOS6以降）
//******************************************************************************
- (BOOL)shouldAutorotate
{
	//回転を許可する
	return YES;
}

//******************************************************************************
// インターフェース自動回転確認：回転方向（iOS6以降）
//******************************************************************************
- (NSUInteger)supportedInterfaceOrientations
{
	//全方向に対応する
	return UIInterfaceOrientationMaskAll;
}

//******************************************************************************
// ビュー表示
//******************************************************************************
- (void)viewWillAppear:(BOOL)animated
{
	int result = 0;
	
	//NSLog(@"MTFileViewCtrl::viewWillAppear %@", self.title);
	
	[super viewWillAppear:animated];
	
	//子ビューが存在する場合は破棄
	[m_pChildFileViewCtrl release];
	m_pChildFileViewCtrl = nil;
	
	//ファイル一覧更新
	result = [self updateFileList];
	if (result != 0) goto EXIT;
	
EXIT:;
	if (result != 0) YN_SHOW_ERR();
	return;
}

//******************************************************************************
// ビュー非表示
//******************************************************************************
- (void)viewWillDisappear:(BOOL)animated
{
	//NSLog(@"MTFileViewCtrl::viewWillDisappear %@", self.title);
	
	[super viewWillDisappear:animated];
	
	return;
}

//******************************************************************************
// ファイル一覧生成
//******************************************************************************
- (int)makeFileList
{
	int result = 0;
	int i = 0;
	NSString* pPath = nil;
	NSString* pFile = nil;
	NSArray* pFileArrayTmp = nil;
	NSMutableArray* pFileArray = nil;
	BOOL isDir = NO;
	
	pFileArray = [[NSMutableArray alloc] init];
	
	//ファイル属性辞書の初期化
	[m_pFileAttributesDictionary release];
	m_pFileAttributesDictionary = [[NSMutableDictionary alloc] init];
	
	//対象ディレクトリ配下のファイル一覧を取得
	if ([[NSFileManager defaultManager] fileExistsAtPath:m_pTargetDirPath]) {
		pFileArrayTmp = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:m_pTargetDirPath error:nil];
	}
	else {
		//ディレクトリが存在しない場合はファイルなしとして処理を続行（File Appで突然削除される可能性を想定）
		pFileArrayTmp = [NSArray array];
	}
	
	//ファイル一覧を作成（画像ファイルとWavetableファイルは除外する）
	for (i = 0; i < [pFileArrayTmp count]; i++) {
		pFile = [pFileArrayTmp objectAtIndex:i];
		pPath = [m_pTargetDirPath stringByAppendingPathComponent:pFile];
		[[NSFileManager defaultManager] fileExistsAtPath:pPath isDirectory:&isDir];
		if (isDir) {
			//ディレクトリの場合
			if ([pFile isEqualToString:@"Inbox"]
				|| [pFile isEqualToString:@".Trash"]) {
				//Inboxディレクトリとゴミ箱ディレクトリは除外
				continue;
			}
			[pFileArray addObject:pFile];
			[m_pFileAttributesDictionary setObject:[NSNumber numberWithInteger:MT_FILE_ATTRIBUTE_DIRECTORY] forKey:pFile];
		}
		else {
			//ファイルの場合
            if (([[pPath pathExtension] caseInsensitiveCompare:@"jpg"] == NSOrderedSame) ||
                ([[pPath pathExtension] caseInsensitiveCompare:@"png"] == NSOrderedSame) ||
				([[pPath pathExtension] caseInsensitiveCompare:@"dls"] == NSOrderedSame) ||
				([[pPath pathExtension] caseInsensitiveCompare:@"sf2"] == NSOrderedSame)) {
                //画像ファイルとWavetableファイルは無視する
                //NSLog(@"%@", pFile);
            }
            else {
                [pFileArray addObject:pFile];
				[m_pFileAttributesDictionary setObject:[NSNumber numberWithInteger:MT_FILE_ATTRIBUTE_NORMAL] forKey:pFile];
            }
		}
	}
	
	//ファイル名ソート：大文字小文字を区別しない
	[m_pFileArray release];
	m_pFileArray = [pFileArray mutableCopy];
	[m_pFileArray sortUsingComparator:^(id str1, id str2) {
		return [((NSString*)str1) compare:((NSString*)str2) options:NSCaseInsensitiveSearch]; }];
	[m_pFileArray retain];
	
	//テスト：ファイルが存在しない場合
	//m_pFileArray = [[NSArray alloc] init];
	
	//ファイルが存在しない場合は選択不可とする
	if ([m_pFileArray count] == 0) {
		m_pTableView.allowsSelection = NO;
	}
	else {
		m_pTableView.allowsSelection = YES;
	}
	
	[pFileArray release];
	return result;
}

//******************************************************************************
// 通知送信処理
//******************************************************************************
- (int)postNotificationWithName:(NSString*)pName
{
	int result = 0;
	NSNotification* pNotification = nil;
	NSNotificationCenter* pCenter = nil;
	
	//通知オブジェクトを作成
    pNotification = [NSNotification notificationWithName:pName
												  object:self
												userInfo:nil];
	//通知する
	pCenter = [NSNotificationCenter defaultCenter];
	
	//通知に対応する処理を演奏スレッドで処理させる場合
	//[pCenter postNotification:pNotification];
	
	//通知に対応する処理をメインスレッドに処理させる場合
	[pCenter performSelectorOnMainThread:@selector(postNotification:)
							  withObject:pNotification
						   waitUntilDone:NO];
	
	return result;
}

//******************************************************************************
// セクション数
//******************************************************************************
-(NSInteger)numberOfSectionsInTableView:(UITableView*)tableView
{
	//セクション
	// 0. ファイル一覧
    return 1;
} 

//******************************************************************************
// セクションヘッダ
//******************************************************************************
- (NSString*)tableView:(UITableView*)tableView titleForHeaderInSection:(NSInteger)section
{
	NSString* pSectionHeader = nil;
	
	switch(section) {
		case 0:
			//ファイル一覧
			pSectionHeader = @"";
			break;
		default:
			break;
    }
	
    return pSectionHeader;
} 

//******************************************************************************
// セクションごとの項目数
//******************************************************************************
- (NSInteger)tableView:(UITableView *)tableView
 numberOfRowsInSection:(NSInteger)section
{
	NSInteger numOfRows = 0;
	
	//NSLog(@"section %d", section);
	
	switch (section) {
		case 0:
			//ファイル一覧の項目数
			numOfRows = [m_pFileArray count];
			if (numOfRows == 0) {
				//ファイルなしの場合はメッセージを表示
				numOfRows = 1;
			}
			break;
		default:
			break;
	}
	
	return numOfRows;
}

//******************************************************************************
// 項目表示内容
//******************************************************************************
- (UITableViewCell*)tableView:(UITableView*)tableView
		cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
	UITableViewCell* pCell = nil;
	
	switch (indexPath.section) {
		case 0:
			//ファイル一覧
			pCell = [self makeFileCellForIndexPath:indexPath];
			break;
		default:
			break;
	}
	
    return pCell;
}

//******************************************************************************
// テーブルセル作成：ファイル
//******************************************************************************
- (UITableViewCell*)makeFileCellForIndexPath:(NSIndexPath*)indexPath
{
    static NSString* pCellIdentifier = @"MTFileViewCtrl";
	UITableViewCell* pCell = nil;
	NSString* pFile = nil;
	
	//再利用可能セル生成
	pCell = [m_pTableView dequeueReusableCellWithIdentifier:pCellIdentifier];
	if (pCell == nil) {
		pCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
									   reuseIdentifier:pCellIdentifier];
	}
	
	//ラベル設定
	if ([m_pFileArray count] == 0) {
		//ファイルなしの場合はメッセージを表示
		pCell.textLabel.text = @"File not found.";
		pCell.detailTextLabel.text = @"You can import your MIDI files through iTunes File Sharing or Files App.";
		pCell.detailTextLabel.numberOfLines = 0;
		pCell.accessoryType = UITableViewCellAccessoryNone;
		pCell.editingAccessoryType = UITableViewCellAccessoryNone;
	}
	else {
		//ファイル名を表示
		pFile = [m_pFileArray objectAtIndex:indexPath.row];
		if ([[m_pFileAttributesDictionary objectForKey:pFile] intValue] == MT_FILE_ATTRIBUTE_DIRECTORY) {
			//ディレクトリの場合
			pCell.textLabel.text = pFile;
			pCell.detailTextLabel.text = @"";
			pCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; //階層マーク
			pCell.editingAccessoryType = UITableViewCellAccessoryDisclosureIndicator;
		}
		else {
			//標準ファイルの場合
			pCell.textLabel.text = pFile;
			pCell.detailTextLabel.text = @"";
			pCell.accessoryType = UITableViewCellAccessoryNone;
			pCell.editingAccessoryType = UITableViewCellAccessoryDisclosureIndicator;
		}
	}
	
	return pCell;
}

//******************************************************************************
// テーブルセル作成：列の高さ
//******************************************************************************
- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath
{
	CGFloat height = 0.0f;
	
	if ([m_pFileArray count] == 0) {
		//ファイルなしの場合はメッセージ表示のため高さを変更する
		height = 80.0f;
	}
	else {
		//デフォルトの高さを返す
		height = m_pTableView.rowHeight;
	}
	
	return height;
}

//******************************************************************************
// テーブルセル選択イベント
//******************************************************************************
- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
	//選択状態解除
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
	
	switch (indexPath.section) {
		case 0:
			//ファイル一覧
			[self onSelectFileCellForIndexPath:indexPath];
			break;
		default:
			break;
	}
	
	return;
}

//******************************************************************************
// テーブルセル選択イベント：ファイル一覧
//******************************************************************************
- (void)onSelectFileCellForIndexPath:(NSIndexPath*)indexPath
{
	int result = 0;
	NSString* pFile = nil;
	NSString* pNewTargetDirPath = nil;
	
	//NSLog(@"selected %d", indexPath.row);
	
	//ファイルなしの場合は何もしない
	if ([m_pFileArray count] == 0) goto EXIT;
	
	//選択行番号を保持
	m_SelectedFileIndex = indexPath.row;
	
	pFile = [m_pFileArray objectAtIndex:m_SelectedFileIndex];
	
	//ファイル選択処理
	if (super.editing) {
		//編集モードであればファイル編集ビューを表示
		[m_pFileEditViewCtrl setFilePathForEditing:[m_pTargetDirPath stringByAppendingPathComponent:pFile]];
		[self.navigationController pushViewController:m_pFileEditViewCtrl animated:YES];
	}
	else {
		//編集中でない場合
		if ([[m_pFileAttributesDictionary objectForKey:pFile] intValue] == MT_FILE_ATTRIBUTE_DIRECTORY) {
			//ディレクトリ選択時は子ビューを生成して遷移
			pNewTargetDirPath = [m_pTargetDirPath stringByAppendingPathComponent:pFile];
			[m_pChildFileViewCtrl release];
			m_pChildFileViewCtrl = [[MTFileViewCtrl alloc] initWithNibName:self.nibName bundle:nil targetDirPath:pNewTargetDirPath];
			[self.navigationController pushViewController:m_pChildFileViewCtrl animated:YES];
		}
		else {
			//ファイル選択時はファイル選択通知を発行
			[self postNotificationWithName:@"onSelectFile"];
		}
	}
	
EXIT:;
	if (result != 0) YN_SHOW_ERR();
	return;
}

//******************************************************************************
// 選択行ファイルパス取得
//******************************************************************************
- (NSString*)selectedFilePath
{
	NSString* pFilePath = nil;
	NSString* pFileName = nil;
	
	//子ビューが存在する場合は子ビューから選択ファイルパスを取得
	if (m_pChildFileViewCtrl != nil) {
		pFilePath = [m_pChildFileViewCtrl selectedFilePath];
		goto EXIT;
	}
	
	//選択行ファイル名
	if (m_pSearchController.active) {
		//検索中は検索結果ビュー制御からファイル名を取得
		pFileName = [m_pFileSearchResultsViewCtrl selectedFileName];
	}
	else {
		pFileName = [m_pFileArray objectAtIndex:m_SelectedFileIndex];
	}
	
	//選択行ファイルパス
	pFilePath = [m_pTargetDirPath stringByAppendingPathComponent:pFileName];
	
EXIT:;
	return pFilePath;
}

//******************************************************************************
// 編集開始終了通知
//******************************************************************************
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
	//編集開始終了処理
	[super setEditing:editing animated:animated];
	[m_pTableView setEditing:editing animated:animated];
	
	//編集開始で追加ボタンを表示
	if (editing) {
		self.navigationItem.rightBarButtonItems = @[[self editButtonItem], m_pAddButton];
	}
	//編集終了で追加ボタンを消去
	else {
		self.navigationItem.rightBarButtonItems = @[[self editButtonItem], m_pOrganizeButton];
	}
	
	return;
}

//******************************************************************************
// 行単位削除可否判定
//******************************************************************************
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
	BOOL isDeletable = YES;
	//NSString* pFile = nil;
	
	//ファイルが存在しない場合は削除不可
	if ([m_pFileArray count] == 0) {
		isDeletable = NO;
		goto EXIT;
	}
	
	//ディレクトリは削除不可
	//pFile = [m_pFileArray objectAtIndex:indexPath.row];
	//if ([[m_pFileAttributesDictionary objectForKey:pFile] intValue] == MT_FILE_ATTRIBUTE_DIRECTORY) {
	//	isDeletable = NO;
	//	goto EXIT;
	//}
	
EXIT:;
	return isDeletable;
}

//******************************************************************************
// 行削除イベント
//******************************************************************************
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
	int result = 0;
	NSString* pFilePath = nil;
	
	//ファイルなしの場合は何もしない
	if ([m_pFileArray count] == 0) goto EXIT;
	
	//選択行番号を保持
	m_SelectedFileIndex = indexPath.row;
	
	//選択行ファイルパス取得
	pFilePath = [self selectedFilePath];
	
	//ファイル削除
	result = [self removeFileWithPath:pFilePath];
	if (result != 0) goto EXIT;
	
	//ファイル一覧の該当データを削除
	[m_pFileArray removeObjectAtIndex:indexPath.row];
	
	//テーブル再読み込み
	[m_pTableView reloadData];
	
EXIT:;
	//if (result != 0) YN_SHOW_ERR();
	return;
}

//******************************************************************************
// ファイル削除
//******************************************************************************
- (int)removeFileWithPath:(NSString*)pPath
{
	int result = 0;
	NSError* pError = nil;
	NSURL* pPathURL = nil;
	BOOL isDeleted = NO;
	UIAlertController* pAlertController = nil;
	UIAlertAction* pAlertAction = nil;
	
	pPathURL = [NSURL fileURLWithPath:pPath];
	isDeleted = [[NSFileManager defaultManager] removeItemAtURL:pPathURL error:&pError];
	if (!isDeleted) {
		//ファイル削除失敗
		result = YN_SET_ERR(@"File deletion failed.", pError.code, 0);
		
		//アラート表示
		pAlertController = [UIAlertController alertControllerWithTitle:@"File deletion failed."
															   message:[pError localizedDescription]
														preferredStyle:UIAlertControllerStyleAlert];
		pAlertAction = [UIAlertAction actionWithTitle:@"OK"
												style:UIAlertActionStyleDefault
											  handler:nil];
		[pAlertController addAction:pAlertAction];
		[self presentViewController:pAlertController animated:YES completion:nil];
		
		goto EXIT;
	}
	
EXIT:;
	return result;
}

//******************************************************************************
// ファイル編集イベント
//******************************************************************************
- (void)onEditFile:(NSNotification*)pNotification
{
	int result = 0;
	NSString* pFileName = nil;
	NSString* pNewFileName = nil;
	NSString* pSrcPath = nil;
	NSString* pDestPath = nil;
	int fileAttribute = 0;
	
	//親ビューまたは子ビューでのファイル編集の場合は何もしない
	if (pNotification.object != m_pFileEditViewCtrl) {
		goto EXIT;
	}
	
	//変更前ファイルパス
	pSrcPath = [self selectedFilePath];
	pFileName = [pSrcPath lastPathComponent];
	
	//変更後ファイルパス
	pNewFileName = [m_pFileEditViewCtrl getNewFileName];
	pDestPath = [m_pFileEditViewCtrl getNewFilePath];
	
	//NSLog(@"SrcFilePath: %@", pSrcPath);
	//NSLog(@"DestFilePath: %@", pDestPath);
	
	//ファイルリネーム
	result = [self renameFileWithPath:pSrcPath toPath:pDestPath];
	if (result != 0) goto EXIT;
	
	//配置先の変更がない場合
	if ([[pDestPath stringByDeletingLastPathComponent] isEqualToString:m_pTargetDirPath]) {
		//ファイル一覧の該当データを更新
		[m_pFileArray replaceObjectAtIndex:m_SelectedFileIndex withObject:pNewFileName];
		
		//ファイル属性辞書を更新
		fileAttribute = [[m_pFileAttributesDictionary objectForKey:pFileName] intValue];
		[m_pFileAttributesDictionary removeObjectForKey:pFileName];
		[m_pFileAttributesDictionary setObject:[NSNumber numberWithInteger:fileAttribute] forKey:pNewFileName];
		
		//ファイル一覧ソート：大文字小文字を区別しない
		[m_pFileArray sortUsingComparator:^(id str1, id str2) {
			return [((NSString*)str1) compare:((NSString*)str2) options:NSCaseInsensitiveSearch]; }];
	}
	//配置先が変更された場合
	else {
		//ファイル一覧の該当データを削除
		[m_pFileArray removeObjectAtIndex:m_SelectedFileIndex];
		//ファイル属性辞書を更新
		[m_pFileAttributesDictionary removeObjectForKey:pFileName];
	}
	
	//テーブル再読み込み
	[m_pTableView reloadData];
	
EXIT:;
	//if (result != 0) YN_SHOW_ERR();
	return;
}

//******************************************************************************
// ファイルリネーム
//******************************************************************************
- (int)renameFileWithPath:(NSString*)pSrcPath toPath:(NSString*)pDestPath
{
	int result = 0;
	NSError* pError = nil;
	BOOL isMoved = NO;
	UIAlertController* pAlertController = nil;
	UIAlertAction* pAlertAction = nil;
	
	//リネーム実施
	isMoved = [[NSFileManager defaultManager] moveItemAtPath:pSrcPath toPath:pDestPath error:&pError];
	if (!isMoved) {
		//リネーム失敗
		result = YN_SET_ERR(@"File rename failed.", pError.code, 0);
		
		//アラート表示
		pAlertController = [UIAlertController alertControllerWithTitle:@"File rename failed."
															   message:[pError localizedDescription]
														preferredStyle:UIAlertControllerStyleAlert];
		pAlertAction = [UIAlertAction actionWithTitle:@"OK"
												style:UIAlertActionStyleDefault
											  handler:nil];
		[pAlertController addAction:pAlertAction];
		[self presentViewController:pAlertController animated:YES completion:nil];
		goto EXIT;
	}
	
EXIT:;
	return result;
}

//******************************************************************************
// ディレクトリ作成イベント
//******************************************************************************
- (void)onCreateDir:(NSNotification*)pNotification
{
	int result = 0;
	NSError* pError = nil;
	NSString* pNewDirPath = nil;
	BOOL isCreated = NO;
	UIAlertController* pAlertController = nil;
	UIAlertAction* pAlertAction = nil;
	
	//親ビューまたは子ビューでのファイル編集の場合は何もしない
	if (pNotification.object != m_pFileEditViewCtrl) {
		goto EXIT;
	}
	
	//ディレクトリ作成
	pNewDirPath = [m_pFileEditViewCtrl getNewFilePath];
	isCreated = [[NSFileManager defaultManager] createDirectoryAtPath:pNewDirPath
										  withIntermediateDirectories:NO
														   attributes:nil
																error:&pError];
	if (!isCreated) {
		//ディレクトリ作成失敗
		result = YN_SET_ERR(@"Folder creation failed.", pError.code, 0);
		
		//アラート表示
		pAlertController = [UIAlertController alertControllerWithTitle:@"Folder creation failed."
															   message:[pError localizedDescription]
														preferredStyle:UIAlertControllerStyleAlert];
		pAlertAction = [UIAlertAction actionWithTitle:@"OK"
												style:UIAlertActionStyleDefault
											  handler:nil];
		[pAlertController addAction:pAlertAction];
		[self presentViewController:pAlertController animated:YES completion:nil];
		goto EXIT;
	}
	
EXIT:;
	return;
}

//******************************************************************************
// 検索結果更新
//******************************************************************************
- (void)updateSearchResultsForSearchController:(UISearchController*)pSearchController
{
	int i = 0;
	NSMutableArray* pFilteredFileArray = nil;
	NSString* pFile = nil;
	NSString* pSearchStr = nil;
	
	//検索文字列
	//  1文字入力するたびに本メソッドが呼び出される
	//  ただし日本語変換中は呼び出されない
	pSearchStr = pSearchController.searchBar.text;
	NSLog(@"Search: %@", pSearchStr);
	
	//検索結果配列の準備
	pFilteredFileArray = [[NSMutableArray alloc] init];
	
	//検索：部分一致（ディレクトリも検索結果に含む）
	if ([pSearchStr length] > 0) {
		for (i = 0; i < [m_pFileArray count]; i++) {
			pFile = [m_pFileArray objectAtIndex:i];
			if ([pFile rangeOfString:pSearchStr options:NSCaseInsensitiveSearch].location != NSNotFound) {
				[pFilteredFileArray addObject:pFile];
			}
		}
	}
	
	//検索結果ビューに検索結果を登録
	[m_pFileSearchResultsViewCtrl setResults:pFilteredFileArray fileAttributesDictionary:m_pFileAttributesDictionary];
	
	return;
}

//******************************************************************************
// 検索結果でのファイル選択イベント
//******************************************************************************
- (void)onSelectFileInSearchResults:(NSNotification*)pNotification
{
	NSString* pFileName = nil;
	NSString* pNewTargetDirPath = nil;
	
	//親ビューまたは子ビューでのファイル編集の場合は何もしない
	if (pNotification.object != m_pFileSearchResultsViewCtrl) {
		goto EXIT;
	}
	
	//選択ファイル名
	pFileName = [m_pFileSearchResultsViewCtrl selectedFileName];
	
	if ([[m_pFileAttributesDictionary objectForKey:pFileName] intValue] == MT_FILE_ATTRIBUTE_DIRECTORY) {
		//ディレクトリ選択時は子ビューを生成して遷移
		pNewTargetDirPath = [m_pTargetDirPath stringByAppendingPathComponent:pFileName];
		[m_pChildFileViewCtrl release];
		m_pChildFileViewCtrl = [[MTFileViewCtrl alloc] initWithNibName:self.nibName bundle:nil targetDirPath:pNewTargetDirPath];
		[self.navigationController pushViewController:m_pChildFileViewCtrl animated:YES];
	}
	else {
		//ファイル選択処理
		[self postNotificationWithName:@"onSelectFile"];
	}
	
EXIT:;
	return;
}

//******************************************************************************
// ファイル一覧更新
//******************************************************************************
- (int)updateFileList
{
	int result = 0;
	
	//ファイル一覧生成
	result = [self makeFileList];
	if (result != 0) goto EXIT;
	
	//テーブル再読み込み
	[m_pTableView reloadData];
	
	//子ビュー側のファイル一覧更新
	if (m_pChildFileViewCtrl != nil) {
		result = [m_pChildFileViewCtrl updateFileList];
		if (result != 0) goto EXIT;
	}
	
EXIT:;
	return result;
}

//******************************************************************************
// 指定ファイルまでスクロール
//******************************************************************************
- (int)scroolToFilePath:(NSString*)pTargetFilePath
{
	int result = 0;
	NSInteger i = 0;
	NSString* pFile = nil;
	NSIndexPath* pTargetIndexPath= nil;
	NSString* pTargetDirPath = nil;
	NSString* pTargetFileName = nil;
	
	//子ビューが存在する場合は処理を任せて終了
	if (m_pChildFileViewCtrl != nil) {
		result = [m_pChildFileViewCtrl scroolToFilePath:pTargetFilePath];
		goto EXIT;
	}
	
	pTargetFileName = [pTargetFilePath lastPathComponent];
	pTargetDirPath = [pTargetFilePath stringByDeletingLastPathComponent];
	
	//対象ディレクトリが一致しない場合は終了
	if (![m_pTargetDirPath isEqualToString:pTargetDirPath]) {
		goto EXIT;
	}
	
	//指定ファイルを検索
	for (i = 0; i < [m_pFileArray count]; i++) {
		pFile = [m_pFileArray objectAtIndex:i];
		if ([pFile isEqualToString:pTargetFileName]) {
			pTargetIndexPath = [NSIndexPath indexPathForRow:i inSection:0];
		}
	}
	
	//指定ファイルをスクロールして選択状態にする
	if (pTargetIndexPath != nil) {
		dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
			//[m_pTableView scrollToRowAtIndexPath:pTargetIndexPath
			//					atScrollPosition:UITableViewScrollPositionTop
			//							animated:YES];
			[m_pTableView selectRowAtIndexPath:pTargetIndexPath
									  animated:YES
								scrollPosition:UITableViewScrollPositionTop];
		});
	}
	
EXIT:;
	return result;
}

//******************************************************************************
// 追加ボタン押下イベント
//******************************************************************************
-(void)onAddButton:(id)sender
{
	int result = 0;
	
	NSLog(@"Add button pressed.");
	
	//編集モードであればファイル編集ビューを表示
	[m_pFileEditViewCtrl setDirPathForCreatingDir:m_pTargetDirPath];
	[self.navigationController pushViewController:m_pFileEditViewCtrl animated:YES];
	
EXIT:;
	if (result != 0) YN_SHOW_ERR();
	return;
}

//******************************************************************************
// リフレッシュ
//******************************************************************************
-(void)refreshTable:(id)sender
{
	int result = 0;
	
	//ファイル一覧更新
	result = [self updateFileList];
	if (result != 0) goto EXIT;
	
	//リフレッシュ完了
	[m_pRefreshCtrl endRefreshing];
	
EXIT:;
	if (result != 0) YN_SHOW_ERR();
	return;
}

//******************************************************************************
// 破棄
//******************************************************************************
- (void)dealloc
{
	//NSLog(@"MTFileViewCtrl::dealloc %@", self.title);
	
	[m_pTargetDirPath release];
	[m_pFileArray release];
	[m_pFileAttributesDictionary release];
	[m_pFileEditViewCtrl release];
	[m_pSearchController release];
	[m_pFileSearchResultsViewCtrl release];
	[m_pRefreshCtrl release];
	[m_pChildFileViewCtrl release];
	[m_pAddButton release];
	
	m_pTargetDirPath = nil;
	m_pFileArray = nil;
	m_pFileAttributesDictionary = nil;
	m_pFileEditViewCtrl = nil;
	m_pSearchController = nil;
	m_pFileSearchResultsViewCtrl = nil;
	m_pRefreshCtrl = nil;
	m_pChildFileViewCtrl = nil;
	m_pAddButton = nil;
	
	[super dealloc];
	
	return;
}

//******************************************************************************
// 次ファイル検索
//******************************************************************************
- (int)findNextFileWithRepeat:(bool)isRepeat isExist:(bool*)pIsExist
{
	int result = 0;
	NSInteger index = 0;
	NSString* pFile = nil;
	
	*pIsExist = false;
	
	//子ビューが存在する場合は子ビュー側で検索
	if (m_pChildFileViewCtrl != nil) {
		result = [m_pChildFileViewCtrl findNextFileWithRepeat:isRepeat isExist:pIsExist];
		goto EXIT;
	}
	
	//ファイルなしの場合は何もしない
	if ([m_pFileArray count] == 0) goto EXIT;
	
	//次のファイルを検索
	for (index = (m_SelectedFileIndex + 1); index < [m_pFileArray count]; index++) {
		pFile = [m_pFileArray objectAtIndex:index];
		if ([[m_pFileAttributesDictionary objectForKey:pFile] intValue] == MT_FILE_ATTRIBUTE_DIRECTORY) {
			//ディレクトリは無視する
		}
		else {
			//次のファイルが見つかった
			*pIsExist = true;
			break;
		}
	}
	
	//次のファイルがなくリピート指定時は先頭のファイルを選択
	if (!(*pIsExist) && isRepeat) {
		//先頭のファイルを検索
		for (index = 0; index < [m_pFileArray count]; index++) {
			pFile = [m_pFileArray objectAtIndex:index];
			if ([[m_pFileAttributesDictionary objectForKey:pFile] intValue] == MT_FILE_ATTRIBUTE_DIRECTORY) {
				//ディレクトリは無視する
			}
			else {
				//次のファイルが見つかった
				*pIsExist = true;
				break;
			}
		}
	}
	
EXIT:;
	return result;
}

//******************************************************************************
// 次ファイル自動選択
//******************************************************************************
- (int)autoSelectNextFileWithRepeat:(bool)isRepeat
{
	int result = 0;
	NSInteger index = 0;
	NSString* pFile = nil;
	bool isFound = false;
	
	//子ビューが存在する場合は子ビュー側で選択
	if (m_pChildFileViewCtrl != nil) {
		result = [m_pChildFileViewCtrl autoSelectNextFileWithRepeat:isRepeat];
		goto EXIT;
	}
	
	//ファイルなしの場合は何もしない
	if ([m_pFileArray count] == 0) goto EXIT;
	
	//次のファイルを検索
	for (index = (m_SelectedFileIndex + 1); index < [m_pFileArray count]; index++) {
		pFile = [m_pFileArray objectAtIndex:index];
		if ([[m_pFileAttributesDictionary objectForKey:pFile] intValue] == MT_FILE_ATTRIBUTE_DIRECTORY) {
			//ディレクトリは無視する
		}
		else {
			//次のファイルが見つかったのでファイル選択通知を発行
			m_SelectedFileIndex = index;
			[self postNotificationWithName:@"onSelectFile"];
			isFound = true;
			break;
		}
	}
	
	//次のファイルがなくリピート指定時は先頭のファイルを選択
	if (!isFound && isRepeat) {
		//先頭のファイルを検索
		for (index = 0; index < [m_pFileArray count]; index++) {
			pFile = [m_pFileArray objectAtIndex:index];
			if ([[m_pFileAttributesDictionary objectForKey:pFile] intValue] == MT_FILE_ATTRIBUTE_DIRECTORY) {
				//ディレクトリは無視する
			}
			else {
				//次のファイルが見つかったのでファイル選択通知を発行
				m_SelectedFileIndex = index;
				[self postNotificationWithName:@"onSelectFile"];
				isFound = true;
				break;
			}
		}
	}
	
EXIT:;
	return result;
}

//******************************************************************************
// 整理ボタン押下イベント
//******************************************************************************
-(void)onOrganizeButton:(id)sender
{
	int result = 0;
	
	NSLog(@"Organize button pressed.");
	
	//ファイル選択ビューを表示
	[self.navigationController presentViewController:m_pDocumentPickerViewCtrl animated:YES completion:nil];
	
EXIT:;
	if (result != 0) YN_SHOW_ERR();
	return;
}

//******************************************************************************
// ファイル選択完了通知 iOS 11以降廃止
//******************************************************************************
- (void)documentPicker:(UIDocumentPickerViewController*)pController didPickDocumentAtURL:(NSURL*)pUrl
{
	int result = 0;
	MTURLAccessUtil* pUrlAccessUtil = nil;
	
	NSLog(@"documentPicker didPickDocumentAtURL");
	
	//指定URLのファイルを対象ディレクトリに取り込む
	pUrlAccessUtil = [[MTURLAccessUtil alloc] init];
	result = [pUrlAccessUtil importFileFromURL:pUrl destDirPath:m_pTargetDirPath];
	if (result != 0) goto EXIT;
	
	//ファイル一覧更新
	result = [self updateFileList];
	if (result != 0) goto EXIT;
	
	//ファイル一覧ビューで指定ファイルまでスクロール
	result = [self scroolToFilePath:[pUrlAccessUtil importedFilePath]];
	if (result != 0) goto EXIT;
	
EXIT:;
	[pUrlAccessUtil release];
	if (result != 0) YN_SHOW_ERR();
	return;
}

//******************************************************************************
// ファイル選択完了通知 iOS 11以降
//******************************************************************************
- (void)documentPicker:(UIDocumentPickerViewController*)pController didPickDocumentsAtURLs:(NSArray<NSURL*>*)pUrls
{
	[self documentPicker:pController didPickDocumentAtURL:[pUrls firstObject]];
}

//******************************************************************************
// ファイル選択キャンセル通知
//******************************************************************************
- (void)documentPickerWasCancelled:(UIDocumentPickerViewController*)pController
{
	NSLog(@"documentPickerWasCancelled");
}


@end

