//
//  RootViewController.m
//  X-BASIC'
//
//  Created by AIG-Soft on 2012/8/13
//  Copyright 2012-2015 AIG-Soft. All rights reserved.
//

#import "AppDelegate.h"
#import "RootViewController.h"
#import "Help.h"
#import "SetupViewController.h"
#import "Setup.h"
#import "libs.h"
#import "click.h"
#import "main.h"
#import "BasicSelectWithTable2.h"

#import "mode.h"
#define MEMREPORT
#ifdef MEMREPORT
#import "mach/mach.h" // メモリーレポート用
#endif
#import "ZipArchive.h"
#import "GeneratePdf.h"
#import "ScreenCapture.h"

#include <string.h>
#import "malloc2.h"
#include "code2code.h"
#import "UIView+loadFromNib.h"
#import "UIActivityIndicatorView+show.h"

@interface RootViewController()
{
	AppDelegate *app;
	Setup		*setup;
	IBOutlet	__weak UIView *viewForEditor;
	UIActivityIndicatorView	*indicator;
}

@end

@implementation RootViewController

//--------------------------------------------------------

#pragma mark -

-(void)startIndicator
{
	printSelfs(@"cnt=%d",cntActivityIndicator);
	if (cntActivityIndicator++==0) {// 多重処理対応
		indicator=[UIActivityIndicatorView show:viewForEditor style:UIActivityIndicatorViewStyleWhiteLarge fbackground:YES];
	} // 多重処理対応
}

-(void)stopIndicator
{
	printSelfs(@"%d",cntActivityIndicator);
	if (cntActivityIndicator>0) {
		if (--cntActivityIndicator==0) {
			[indicator dismiss];
		} // 多重処理対応
	}
}

//----------------------------------------------
// view*
//----------------------------------------------

- (void)viewDidLoad
{
	printSelf();
	[super viewDidLoad];
	
	app=getAppDelegate();
	setup=app.setup;
	
	// 最初の1回だけでいい初期化処理
	// ボタン／ラベル名など表示(ローカライズ)
	self.title=NSLocalStr(@"PROGRAM_NAME"); // プログラム名

	self.editorView=[EditorView loadFromIdiomNib];
	CGRect frame=viewForEditor.frame; // サイズを合わせる
	frame.origin=CGPointZero; // 位置はviewForEditor相対なので(0,0)から
	self.editorView.frame=frame;
	[viewForEditor addSubview:self.editorView];
	
	// Naviにボタン追加
	btnEdit =[[UIBarButtonItem alloc]initWithTitle:NSLocalStr(@"EDIT") style:UIBarButtonItemStylePlain target:self action:@selector(naviButtonAction:)];
//	btnEdit =[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemEdit      target:self action:@selector(naviButtonAction:)]; // こちらで設定するとあとで.titleは変更できない
	btnEdit.tag=3;
	self.navigationItem.leftBarButtonItem=btnEdit;
	//
	btnBasic=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemBookmarks target:self action:@selector(toolButtonAction:)];
	btnBasic.tag=4;
	self.navigationItem.rightBarButtonItem=btnBasic;
	
	self.popover			=nil;
	fpopover				=POPOVER_NONE; // iPhoneの時はこれから変化しない
	// 読み込んでない/初回の印
	_setupViewController	=nil;
	_help					=nil;
	actionSheet				=nil;
	cntActivityIndicator	=0;
	opeMode					=MODE_NONE; // 最初は確実にモード設定させるため
	//
	fviewDidLoad			=YES;
}

//-------------------

- (void)viewWillAppear:(BOOL)animated
{
	printSelf();
	
    [super viewWillAppear:animated];
	//
	// 初期画面方向設定
	
	UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; // 起動時の画面方向
	[self willAnimateRotationToInterfaceOrientation:orientation duration:0];
	[_runView disableRotate:NO]; // 画面回転許可
	[self didRotateFromInterfaceOrientation:0]; // これをしないとvwBackが消えたままになる(方向は任意)
	
	// setupはここで読み込まれる
	// 本番では、前回から継続する
	// windowのIBによる設定背景色を保存（初回だけ）
	if (winColor==nil) {
		winColor=app.window.backgroundColor;
		//nslog(@"window=%@",_mainView.window);
		nslog(@"winColor=%@",winColor);
	} // 毎回やるとタイミングかなんかでclearColorになってしまうことがある
	// window背景色を消す
	app.window.backgroundColor=[UIColor clearColor];
	//
	
	// EditorViewに初期化データを渡す
	// 初期化自体はEditorViewが自身で行う
	[_editorView setEditorFont:setup.fontName pointSize:setup.fontSize]; // viewDidLoadではsetupが読み込まれてないのでここで

	// キーボード表示時に通知させる
	[_editorView keyboardNotification:YES];
	//
	if (fviewDidLoad) { // 起動直後の通過時のみ
		nslog(@"起動直後のみ:%@",setup.basicFile);
		fviewDidLoad=NO;
		// _runView読み込み
		self.runView=[[RunViewController alloc]init]; // _runViewを(releaseとペアで)2回以上読み込もうとするとなぜかエラーが出るので1回にする
		// 起動時ファイル読み込み
		[self loadBasic:setup.basicFile];
	}
	//
	printSelfs(@"%@ ", @"end");
}

-(void)viewDidAppear:(BOOL)animated
{
	printSelf();
	// ここはiPhoneではsetup/helpの後も呼び出されるので注意
	[super viewDidAppear:animated];
	//
	//	printFrame(@"root.navi",self.view.frame);
#if 1
	if (ffirst) {
		// 初回起動時（1回だけ）
		Alert1(@"FIRST_LAUNCH",@"FIRST_MESSAGE", nil);
		ffirst=NO;
	}
#endif
}

-(void)viewWillDisappear:(BOOL)animated
// 消える前
{
	printSelf();
	[super viewWillDisappear:animated];
	[self closePopover];
}

-(void)viewDidDisappear:(BOOL)animated
{
	printSelf();
	[super viewDidDisappear:animated];
	// キーボード通知の解除
	[_editorView keyboardNotification:NO];
}

//----------------------------------------------

// こちらは公開メソッド
-(void)setFontWithFile
{
	printSelf();
	// editor.text内はフォーマット済みの特殊文字列なので、これではうまくいかない
//	[_editorView setFont:editor.text];
	// 読み込みからやり直す必要がある
	[self loadBasic:setup.basicFile];
}

// 新規作成
-(NSString *)setNewFile
{
	[self setMode:MODE_EDIT]; // 新規作成は即編集
	[setup setup2XBoperationStatus]; // operationStatusの設定
	[_editorView displayBasic:NSLocalStr(@"NEWFILE")]; // 新規作成時の名前
	//
	operationStatus.fsjis=NO;	// 新規作成時はUTF8のみ
	[_editorView displayEncode];

	_editorView.fafterEdit=YES;	// 編集済の印
	
	return [NSString stringWithFormat:@"// %@\n",makeNowDateStr()]; // 作成日付のみ入れておく
}

// ソース読み込み処理
-(void)loadBasic:(NSString *)basicFile
{
	printSelfs(@"%@",basicFile);
	nslog(@"loadBasic=%@",basicFile);

	// basicFileはフルパスで入ってくる
	// なぜならプログラムは内蔵分はリソース内、ユーザー作成分はDocumentパスに存在するから。
#if 1	// デバッグ処理
	// iOS8ではなぜかリソースパスが変化することがあるのでここで動的に差し替える
	// リソースないならリソースへ、ユーザー領域ならそれへ
	nslog(@"basicFile=%@",basicFile);
	nslog(@"setup.basicFile=%@",setup.basicFile);
	nslog(@"setup.basicFileOnly=%@",setup.basicFileOnly);
	basicFile=autoReplaceDocumentOrResourceDirectory(basicFile);
	nslog(@"newPath=%@",basicFile);
	
	setup.basicFile=basicFile;
#endif
	//
	[self startIndicator];
	[_editorView errorViewHidden:YES];
	[_editorView eraseSearchBar];
	//
	_editorView.fafterEdit=NO;	// 未編集の印

	// 読み出し＆表示
	[_editorView colorEncode:[UIColor blackColor]];
	NSString *text;
	if ([basicFile isEqualToString:PATH_NEWFILE]) {
		nslog(@"新規作成");
		text=[self setNewFile];
	} else {
		nslog(@"ファイル読み込み=%@",basicFile);
		[self setMode:MODE_LIST]; // 読み込んだ後は編集可能（強制SJISでは不可にする)!!
		[setup setup2XBoperationStatus]; // operationStatusの設定
		[_editorView displayBasic:setup.basicFileOnly];
		
		switch (readBasicFile(basicFile,&startupSize,&startupLines)) {
			case RET_readBasicFile_memory_error:
				nslog(@"メモリー不足");
				[self stopIndicator];
				[self noMemory];
				[self waitAlertEnd];
				exit(1);
				
			case RET_readBasicFile_file_not_found:
				nslog(@"読めないときは新規作成にする:%@",basicFile);
				// 編集中のプログラムを削除したあとの後の起動時に発生する
				// 前回起動時から今回起動の間にiTunes側を削除した場合も
				text=[self setNewFile];
				nslog(@"text=%@",text);
				break;
				
			default: // 正常に読み込めた
				xb_fileload(nsStringTocString(setup.basicFileOnly)); // ファイル名の記録のみ
				[_editorView displayEncode];
				
				// sourceTop:ここに入るのはUTF8、または強制SHIFT-JISモードの時はSHIFT-JISのまま
				// ゆえに、表示用にUTF8に変換した分も作らなければならない
				if (operationStatus.fsjis) { // SJIS→UTF8変換して入れる
					nslog(@"SJIS→UTF8変換");
					UByte *bp;
					bp=(UByte *)malloc2(strlen((const char*)sourceTop)*2);
					if (bp==NULL) {
						nslog(@"メモリー不足");
						[self stopIndicator];
						[self noMemory];
						[self waitAlertEnd];
						exit(1);
					}
					nslog(@"変換前source\n%@",@((char *)sourceTop+startupSize));
					sjisToUtf8S(bp,sourceTop+startupSize);
					nslog(@"変換後source\n%@",@((char *)bp));
					// SHIFT-JISは表示用テキストを別に作るので、そのままでもstartupは表示されない
					text=@((char *)bp);
					// ↑ C文字列をNSString化して入れる:UTF8を指定していると内部では何も変換していないみたい。故に内容がSHIFT-JISならそのまま渡る
					free2(bp);
					[_editorView colorEncode:[UIColor redColor]];
				} else { // UTF8/ASCIIの時はそのまま表示
					nslog(@"UTF8/ASCIIの時はそのまま表示");
					// startup.bas部分は除く
					text=@((char *)sourceTop+startupSize); // C文字列をNSString化して入れる
				}
				break;
		} // switch
	} // if (newfile)
	// 表示フォント設定
	nslog(@"テキスト設定:text=%@",text);
	_editorView.fontName=setup.fontName;
	_editorView.fontSize=setup.fontSize;
	_editorView.text=text;
	//
	[setup saveSetup];

	[self stopIndicator];
}

//-----------------------------------------

// UTI経由のファイルインポート
// リターン値 : YES=pathからファイルを読み込めた , NO=読み込めない
// V2.9でインポート機能は削除されたのでここは未使用
-(BOOL)importFromUTI:(NSURL *)url
{
	printSelfs(@"%@",url); 		// 受信ファイルURL
	NSString *path=[url relativePath]; 		// 受信ファイルフルパス名
	nslog(@"path=%@",path);
	NSString *fname=[url lastPathComponent];// 受信ファイル名＋拡張子
	nslog(@"fname=%@",fname);
	NSString *ext=[[path pathExtension]lowercaseString]; // 受信ファイル拡張子(小文字)
	nslog(@"ext=%@",ext);
	//
#ifdef ENABLE_ZIP_IMPORT
	if ([ext caseInsensitiveCompare:@"zip"]==NSOrderedSame) {
		nslog(@"ZIPファイル→解凍して格納");
		// MacOS標準上でフォルダを圧縮すると
		// __MACOSX\フォルダ名\._ファイル群.ext		(サイズから見て)実体ではない
		// フォルダ名\ファイル群.ext				ファイル実体
		// という構成で圧縮されてしまう。
		// （muCommanderやWindows上の圧縮ではこのようにはならない。）
		// __MACOSX内は.から始まるので隠しファイルとなり表示されないが、残ってしまい無駄になる
		// また、展開時にフォルダ名\.DS_Storeというファイルも作られてしまう(__MACOSX内にリンクがあるからだと思う)
		// しかし、フォルダ名を特定できない(するのが面倒な)ので、このファイルを消すことはできない
		ZipArchive *zip = [[ZipArchive alloc] init];
		if ([zip UnzipOpenFile:path]) {
			NSString *extendPath=getDocumentsPath();
			nslog(@"解凍フォルダ=%@",extendPath);
			BOOL ret;
#if 1
			// 実展開前に、アーカイブの中に展開対象外ファイルが含まれるかどうか確認する。
			ret = [zip checkInZipFile:extendPath exceptExt:EXT_BASIC_REGEXP];
			if (ret==NO) {
				// 展開できないファイルが含まれている
				Alert1(@"ZIPERR_TITLE",@"ZIPERR2_MESSAGE", nil);
				return NO;
			}
#endif
			ret = [zip UnzipFileTo:extendPath overWrite:YES exceptExt:EXT_BASIC_REGEXP]; // 解凍;.bas（に相当するもの）は除く
			if (NO == ret) {
				// エラー処理
				Alert1(@"ZIPERR_TITLE",@"ZIPERR_MESSAGE", nil);
				return NO;
			}
			[zip UnzipCloseFile];
		}
		// __MACOSX\を削除する
		// 存在しないこともあるので、エラーは無視する
		[[NSFileManager defaultManager]removeItemAtPath:makeFullPathForSaveData(@"__MACOSX") error:NULL];
		// zipの時はその中のどれを起動すれば良いのかわからない(.basがないこともあり得る)ので自動表示しない
	} else
#endif
	{
		// 単独ファイル
		nslog(@"単独ファイル:ext=%@",ext);
		// 単独ファイルは、iTunes\Inbox\という場所にコピーされて呼び出される(メイル以外では別ディレクトリかもしれない)
		// files()は下位ディレクトリまで検索するのでそのままでよい
		// ここには来ないはずだけど、念のためエラーにしておく
		Alert1(@"IMPORT_ERR_TITLE",[NSString stringWithFormat:NSLocalStr(@"IMPORT_ERR_MESSAGE"),fname], nil);
		return NO;
	}
	Alert1(@"IMPORT_TITLE",[NSString stringWithFormat:NSLocalStr(@"IMPORT_MESSAGE"),fname], nil);
#if 1	// v2.7
	// インポートしたzipファイルを消す
	// zipファイル中に残っているとか言われないために
	nslog(@"インポートしたzipファイルを消す:%@",path);
	[[NSFileManager defaultManager]removeItemAtPath:path error:NULL];
#endif
	return YES;
}

//-------------------------------------------------------------------
// ソース保存処理
//-------------------------------------------------------------------

// BASICプログラムの保存
-(void)saveBasic
{
	printSelf();
	nslog(@"saveBasic=%@",setup.basicFile); // フルパス名で入ってきている。故に、内蔵サンプルに同名のものがあっても名称は一致しない
	
	if ([setup.basicFile isEqualToString:PATH_NEWFILE]) {
		// 新規作成の時
		setup.basicFile=makeFullPathForSaveData(NSLocalStr(@"NEWFILE")); // 保存はiTunes側のみ
	}
	nslog(@"save path=%@",setup.basicFile);
	//
	[self startIndicator];
	NSError *err;
	err=[[NSError alloc]init];
	if (![_editorView.editor.text writeToFile:setup.basicFile atomically:YES encoding:NSUTF8StringEncoding error:&err]) { // 常にUTF8で保存
		nslog(@"error=%@",err);
	}
	
	// setupも保存
	[setup saveSetup];
	
	// 保存したら編集した印を消す
	_editorView.fafterEdit=NO;
	
	[self stopIndicator];
}

// _editorView.editor.text内のUTF8テキストをchar *でsourecTopからに格納する
// 新規作成時もここを通る
-(void)editorToSource
{
	printSelf();
	if (!operationStatus.fsjis) {
		nslog(@"fsjisではない");
		if (_editorView.fafterEdit) { // 編集されている時のみ
			// 中間ファイルに保存する
			NSString *tmpPath=makeFullPathForSaveData(TEMP_BASIC); // 保存はiTunes側
			nslog(@"tmpPath=%@",tmpPath);
			[self startIndicator];
			NSError *err;
			err=[[NSError alloc]init];
			if (![_editorView.editor.text writeToFile:tmpPath atomically:YES encoding:NSUTF8StringEncoding error:&err]) { // 常にUTF8で保存
				nslog(@"error=%@",err);
			}
#if 1
			// 再読み込みすることでstartupを入れ込む
			// ファイルが見つからないことはないはず
			if (readBasicFile(tmpPath,&startupSize,&startupLines)==RET_readBasicFile_memory_error) {
				nslog(@"メモリー不足");
				[self stopIndicator];
				[self noMemory];
				[self waitAlertEnd];
				exit(1);
			}
			[self stopIndicator];
#else
			nslog(@"編集されている");
			char *src=nsStringTocString(_editorView.editor.text);
			int len=strlen(src);
			nslog(@"len=%dバイト",len);
			if (sourceTop!=NULL) {
				free2(sourceTop);
			}
			len++; // 後ろにもう1つEOSを入れるから
			sourceTop=malloc2(len+1);
			if (sourceTop==NULL) {
				nslog(@"メモリー不足");
				[self stopIndicator];
				[self noMemory];
				[self waitAlertEnd];
				exit(1);
			}
			memcpy(sourceTop,src,len);
			sourceTop[len-1]=EOS;
			//
			sourceEnd=sourceTop+len;
			nslog(@"source=%p～%p(size=%d)",sourceTop,sourceEnd,sourceEnd-sourceTop+1);
#endif
		}
	} // SJISモードの時は編集不可なので戻しも不要
}

// ソースが編集されているときは、先に保存確認
-(void)editSave
{
	if (_editorView.fafterEdit) {
		nslog(@"ソースが編集されているときは、先に保存確認");
		[self saveSourceAlert];
		[self waitAlertEnd];
		if (fAlert==ALERT_SAVEAS) {
			nslog(@"名前を付けて保存");
			[self saveAsSourceAlert]; // ファイル名入力
			[self waitAlertEnd];
			// .bas自動付加
			NSString *fname=[alertViewField textFieldAtIndex:0].text;
			nslog(@"fname=%@",fname);
			if ([fname length]>0) {
				setup.basicFile=makeFullPathForSaveData(replaceExt(fname,EXT_BASIC)); // 拡張子を付ける(変更する)
				[_editorView displayBasic:setup.basicFileOnly];
				[self saveBasic];
			}
#ifdef DEBUG
			else {
				// 名前の実指定がないとき
				nslog(@"名前の実指定がないのでキャンセル");
			}
#endif
		}
		nslog(@"保存終了");
	}
}

// AlertViewの終了待ち
// これを入れないと勝手に画面が進んでしまうから
-(void)waitAlertEnd
{
	NSUInteger f=fAlert;
	printSelfs(@"fAlert=%d",(int)f);
	//
	while (fAlert==f) {
		EnterRunLoop(0.5); // これがチェック間隔となる(秒)
		// EnterRunLoopは、指定された時間までの間「ループ」を実行する
		// モードが変更されたら終了
	}
	nslog(@"待ち終了:fAlert=%d",(int)fAlert);
}

// 名前を付けて保存用 アラート
-(void)saveAsSourceAlert
{
	printSelf();
    alertViewField = [[UIAlertView alloc] initWithTitle:NSLocalStr(@"SAVEAS")
											    message:nil
											   delegate:self
									  cancelButtonTitle:NSLocalStr(@"CANCEL")
									  otherButtonTitles:NSLocalStr(@"SAVE"),
									 nil
					];
	alertViewField.alertViewStyle=UIAlertViewStylePlainTextInput; // A single text field at index 0.
	
	// 元のファイル名を入れておく;ディレクトリ情報は消す
	// 元がユーザープログラムの場合元のディレクトリに戻したいが、内蔵→編集→ユーザー領域の場合に区別処理が必要になるので、今回は実装しない
//	nslog(@"basicFile=%@",_mainView.setup.basicFile);
//	nslog(@"basicFileOnly=%@",_mainView.setup.basicFileOnly);
	
	// v3.20 debug
	NSString *fname=setup.basicFileOnly;
	if ([setup.basicFileOnly isEqualToString:PATH_NEWFILE]) {
		fname=@"";
	}
	[alertViewField textFieldAtIndex:0].text=fname;
	
	// 表示
	clickSound();
	[alertViewField show];
}

// 保存用アラート
-(void)saveSourceAlert
{
	printSelf();
	fAlert=ALERT_SAVE;
	// 表示
	enum {
		PROGRAM_USER=0,	// ユーザープログラム
		PROGRAM_NEW,	// 新規作成
		PROGRAM_SAMPLE,	// 内蔵サンプル
	};
	NSString *lastPath=[setup.basicFile lastPathComponent];
	nslog(@"setup.basicFile=%@/last=%@",setup.basicFile,lastPath);
	int fprogram=PROGRAM_SAMPLE;
	if ([lastPath isEqualToString:PATH_NEWFILE]) {
		nslog(@"新規作成で作ってた時");
		fprogram=PROGRAM_NEW;
	} else {
		// 新規作成ではない時
		// 既存のファイルを編集している
		NSString *basepath=getDocumentsPath();
		size_t len=[basepath length];
		nslog(@"iTunesディレクトリ(%zd)=%@",len,basepath);
		if ([setup.basicFile length]>len) {
			NSString *path=[setup.basicFile substringToIndex:len]; // このパスにサロゲートペアはありえないのでこれでよい
			nslog(@"プログラムファイルのディレクトリ名=%@",path);
			if ([basepath isEqualToString:path]) fprogram=PROGRAM_USER;
		} // 現在のプログラムのパス名がiTunesディレクトリの名前長より以下の時は、当然そこではない
	}
	// V3.00
	// ファイル名のみを比較し、一致する場合は
	// 内蔵：ユーザー＝内蔵を隠蔽し、ユーザーのみを表示
	// ユーザー：ユーザー＝置換
	switch (fprogram) {
		case PROGRAM_NEW:
			nslog(@"新規作成時");
		case PROGRAM_SAMPLE:
			nslog(@"内蔵サンプル時");
			// 新規作成/内蔵サンプル編集時は上書き保存なし
			alertView = [[UIAlertView alloc]  initWithTitle:NSLocalStr(@"SAVEQESTION")
													message:nil
												   delegate:self
										  cancelButtonTitle:NSLocalStr(@"NOSAVE2")		// 横2ボタンになり表示幅が狭いので
										  otherButtonTitles:NSLocalStr(@"SAVEAS"),		// 名前を付けて保存
						 nil
						 ];
			// 名前を付けて保存のボタン番号
			noSAVEAS=alertView.firstOtherButtonIndex;
			break;
		case PROGRAM_USER:
			// 新規作成ではないとき
			alertView = [[UIAlertView alloc]  initWithTitle:NSLocalStr(@"SAVEQESTION")
													message:nil
												   delegate:self
										  cancelButtonTitle:NSLocalStr(@"NOSAVE")
										  otherButtonTitles:NSLocalStr(@"OVERWRITE"),	// 上書き保存：ボタン番号=firstOtherButtonIndex
															NSLocalStr(@"SAVEAS"),		// 名前を付けて保存
						 nil
						 ];
			// 名前を付けて保存のボタン番号
			noSAVEAS=alertView.firstOtherButtonIndex+1;
			break;
	}
	clickSound();
	[alertView show];
}

// 編集できないアラート
-(void)cantEditAlert
{
	printSelf();
	fAlert=ALERT_CANTEDIT;
	// 表示
	alertView = [[UIAlertView alloc]  initWithTitle:NSLocalStr(@"CONFIRMATION")
											message:NSLocalStr(@"CANTEDIT")
										   delegate:self
								  cancelButtonTitle:nil
								  otherButtonTitles:NSLocalStr(@"OK"),
				 nil
				 ];
	// 名前を付けて保存のボタン番号
	clickSound();
	[alertView show];
}

//-------------------------------------------------------------------

// メモリ不足エラー
-(void)noMemory
{
	printSelf();
	fAlert=ALERT_NOMEMORY;
	// 表示
	alertView = [[UIAlertView alloc]  initWithTitle:NSLocalStr(@"NOMEMORY")
											message:NSLocalStr(@"MES_NOMEMORY")
										   delegate:self
								  cancelButtonTitle:nil
								  otherButtonTitles:NSLocalStr(@"EXIT"),
				 nil
				 ];
	// 名前を付けて保存のボタン番号
	clickSound();
	[alertView show];
}

//-------------------------------------------------------------------

// alertViewのボタンが押された
// fAlert : alertView/alertViewFieldの両方からくる
-(void)alertView:(UIAlertView *)alertView_ clickedButtonAtIndex:(NSInteger)buttonIndex
{
	nslog(@"alertView:ボタン=%d/noSAVEAS=%d",(int)buttonIndex,(int)noSAVEAS);
///	clickSound();
	if (buttonIndex==alertView_.cancelButtonIndex) { // キャンセル
		// alertView自体が画面外タップなどでキャンセルされた時もここに来る
		nslog(@"キャンセル");
		fAlert=ALERT_NONE;
		// _editorView.fafterEditはそのまま保持
	} else {
		switch (fAlert) {
			case ALERT_CANTEDIT:
				// 編集できない確認アラートの時
				fAlert=ALERT_NONE;
				break;
			//
			case ALERT_SAVEAS:
				fAlert=ALERT_NONE;
				break;
			case ALERT_SAVE:
				if (buttonIndex==noSAVEAS) {
					nslog(@"名前を付けて保存へつなげる");
					fAlert=ALERT_SAVEAS;
				} else {
					nslog(@"上書き保存");
					[self saveBasic];
					fAlert=ALERT_NONE;
				}
				break;
			case ALERT_NOMEMORY:
				//!!これで正しいかどうかわからないけどとりあえず
				exit(1);
		}
	}
}

//-------------------------------------------------------------------
// 印刷処理
//-------------------------------------------------------------------

-(void)printClose
{
	printSelf();
	[airPrint close];
//	fpopover=POPOVER_NONE;
}

#ifdef DEBUG
// 印刷設定画面が表示された後に呼び出される
- (void)printInteractionControllerDidPresentPrinterOptions:(UIPrintInteractionController *)printInteractionController
{
	printSelf();
}
#endif

// 印刷設定画面が、印刷開始で消えるときに呼び出される
// closeでは呼び出されないので注意
- (void)printInteractionControllerDidDismissPrinterOptions:(UIPrintInteractionController *)printInteractionController
{
	printSelf();
//	fpopover=POPOVER_NONE; // もう閉じたの印;他の画面は開いてないはず
}

// 印刷開始時に呼び出される
- (void)printInteractionControllerWillStartJob:(UIPrintInteractionController *)printInteractionController
{
	printSelf();
	// 設定画面はこの時点で自動的に閉じるので、通常閉じ処理は必要ない
//	fpopover=POPOVER_NONE; // もう閉じたの印;他の画面は開いてないはず
}

// 印刷終了時に呼び出される
// プリンタースプーラーに処理が渡ればすぐに呼び出される（＝実印刷終了を待つわけではない）
// 印刷設定画面がcloseで消された時も呼び出される(重要）
- (void)printInteractionControllerDidFinishJob:(UIPrintInteractionController *)printInteractionController
{
	printSelf();
	/* 重要な注意
	 印刷設定が表示されているときに_helpを押すと、
	 airPrint:close
	 _help表示
	 ここ
	 の順に呼び出される。したがって、ここでfpopoverをいじってはいけない
	 */
}

-(void)printList
{
	printSelf();
#if 0
	if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
		// iPad時のみpoppver判定が必要
		nslog(@"print:iPad");
//		fpopover=POPOVER_PRINTER;
	}
#endif
	airPrint=[[AirPrint alloc]init];
	[airPrint initPrintInView:self.view]; // 渡しているのは、プリンターコントロールを表示するビュー（位置）のみ
	airPrint.delegate=self;
	
	// テキストデータからPDFを作る
	GeneratePdf *pdf=[[GeneratePdf alloc]init];
	NSString *tmpPath=makeFullPathForSaveData(TEMP_PDF); // 保存はiTunes側
	nslog(@"tmpPath=%@",tmpPath);
	[pdf savePDFFileWithText:_editorView.editor.text fname:tmpPath]; // 一旦中間ファイルに書き出す
	// PDFをNSDataに入れる
	NSData *data=[[NSData alloc]initWithContentsOfFile:tmpPath];
	//
	[airPrint setItem:(id)data jobName:getAppDelegate().setup.basicFileOnly];
	// setItemは画面表示するとすぐに戻ってきてここに来るので、ここではprintCloseで画面を閉じてはいけない
}

// 画面のハードコピー
// _runView.capturedImageViewにキー画面をキャプチャーした状態で呼び出すこと
-(void)printScreen
{
	printSelf();
#if 0
	if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
		// iPad時のみpoppver判定が必要
		nslog(@"print:iPad");
//		fpopover=POPOVER_PRINTER;
	}
#endif
	airPrint=[[AirPrint alloc]init];
	[airPrint initPrintInView:self.view]; // 渡しているのは、プリンターコントロールを表示するビュー（位置）のみ
	airPrint.delegate=self;
	
	// 印刷準備
	_runView.capturedImageView.hidden=NO;  // キャプチャーのためキー画面を表示
	UIImage *image=viewCapture(_runView.captureView,YES); // 印刷するためには背景を黒にしておく必要がある
	_runView.capturedImageView.hidden=YES; // キー画面を消去
#if 0 // def DEBUG
	{
		static int cnt=0;
		NSData *imgdata;
		imgdata=UIImageJPEGRepresentation(image,1.0);
		[imgdata writeToFile:[NSString stringWithFormat:TestFile(@"_runView%02d.jpg"),cnt] atomically:YES];
		cnt++;
	}
#endif
	
	// 印刷
	[airPrint setItem:(id)image jobName:getAppDelegate().setup.basicFileOnly];
	// setItemは画面表示するとすぐに戻ってきてここに来るので、ここではprintCloseで画面を閉じてはいけない
}

// デバッグ画面のハードコピー
-(void)printDebug
{
	printSelf();
	airPrint=[[AirPrint alloc]init];
	[airPrint initPrintInView:self.view]; // 渡しているのは、プリンターコントロールを表示するビュー（位置）のみ
	airPrint.delegate=self;
	
	// テキストデータからPDFを作る
	GeneratePdf *pdf=[[GeneratePdf alloc]init];
	NSString *tmpPath=makeFullPathForSaveData(TEMP_PDF); // 保存はiTunes側
	nslog(@"tmpPath=%@",tmpPath);
	[pdf savePDFFileWithText:_runView.debugText fname:tmpPath]; // 一旦中間ファイルに書き出す
	// PDFをNSDataに入れる
	NSData *data=[[NSData alloc]initWithContentsOfFile:tmpPath];
	//
	[airPrint setItem:(id)data jobName:getAppDelegate().setup.basicFileOnly];
	// setItemは画面表示するとすぐに戻ってきてここに来るので、ここではprintCloseで画面を閉じてはいけない
}

//----------------------------------------------
// ActionSheet
//----------------------------------------------

// アクションシートのボタンが押された
-(void)actionSheet:(UIActionSheet *)actionSheet_ clickedButtonAtIndex:(NSInteger)buttonIndex
{
	printSelfs(@"buttonIndex=%d",(int)buttonIndex);
	if (buttonIndex==actionSheet_.cancelButtonIndex) {
		// ActionSheet自体が画面外タップなどでキャンセルされた時もここに来る
		nslog(@"キャンセル");
		return;
	}
	//
	switch (buttonIndex) {
		case 0:
			if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && !webHelp.hidden) {
				// iPadのみ
				nslog(@"HELP最終行へ");
				[webHelp scrollToEndOfHelp];
			} else {
				// 検索結果は消さない
				nslog(@"ソース最終行へ");
				[_editorView scrollToEndOfSource];
			}
			break;
		case 1: {
			nslog(@"実行画面表示");
			[self presentViewController:self.runView animated:YES completion:^{
				[self.runView displayRun];
			}];
			break;
		}
		case 2: {
			nslog(@"変数ダンプ画面表示");
			[self presentViewController:self.runView animated:YES completion:^{
				[self.runView displayDebug:MODE_DEBUG_ACTIONSHEET];
			}];
			break;
		}
		case 3:
			nslog(@"プログラム印刷");
			[self printList];
			break;
		case 4:
			nslog(@"デバッグ画面印刷");
			[self printDebug];
			break;
		case 5: // 一度もRUNしてないときは選択されて来ない
			nslog(@"実行画面印刷");
			[self printScreen];
			break;
	}
	clickSound();
}

-(IBAction)actionButton:(UIBarButtonItem *)btn
{
	printSelf();
	[_editorView eraseSearchBar]; // 検索が出てたら消す
	if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
		// アクションシートを表示する前にpopoverを閉じる(Appleからの指摘)
		[self closePopover];
	}
	// UIActionSheetは毎回alloc&initしないと二回目以降化けてしまう
	NSString *menuStr=NSLocalStr(@"ENDOFSOURCE");
	if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
		if (!webHelp.hidden) menuStr=NSLocalStr(@"ENDOFHELP");
	} // iPhoneではwebViewは表示されないので、それの中の検索もない
	NSString *mesPrintScreen=nil;
	if (_runView.runCount>0) mesPrintScreen=NSLocalStr(@"PRINTSCREEN"); // 一度もRUNしてないときは表示しない
	// デバッグ画面はRUN前にも有効なことがあるので常に出す
	
	if (getSystemVersion()>=8.0) {
		// iOS8のiPadでActionSheetを使うと、その中からAirPrintのダイアログが開けない
		fpopover=POPOVER_ACTION;
		alertController = [UIAlertController alertControllerWithTitle:NSLocalStr(@"ACTION")
																				 message:@""
																		  preferredStyle:UIAlertControllerStyleActionSheet];
		[alertController addAction:[UIAlertAction actionWithTitle:menuStr
															style:UIAlertActionStyleDefault
														  handler:^(UIAlertAction *action) {
															  if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && !webHelp.hidden) {
																  // iPadのみ
																  nslog(@"HELP最終行へ");
																  [webHelp scrollToEndOfHelp];
															  } else {
																  // 検索結果は消さない
																  nslog(@"ソース最終行へ");
																  [_editorView scrollToEndOfSource];
															  }
															  clickSound();
														  }]];
		[alertController addAction:[UIAlertAction actionWithTitle:NSLocalStr(@"RUNSCREEN")
															style:UIAlertActionStyleDefault
														  handler:^(UIAlertAction *action) {
															  nslog(@"実行画面表示");
															  clickSound();
															  [self presentViewController:self.runView animated:YES completion:^{
																  [self.runView displayRun];
															  }];
														  }]];
		// v3.20
		[alertController addAction:[UIAlertAction actionWithTitle:NSLocalStr(@"DEBUGSCREEN")
															style:UIAlertActionStyleDefault
														  handler:^(UIAlertAction *action) {
															  nslog(@"デバッグ画面表示");
															  clickSound();
															  [self presentViewController:self.runView animated:YES completion:^{
																  [self.runView displayDebug:MODE_DEBUG_ACTIONSHEET];
															  }];
														  }]];
		//
		
		if ([UIPrintInteractionController isPrintingAvailable]) { // 印刷が使えるとき
			[alertController addAction:[UIAlertAction actionWithTitle:NSLocalStr(@"PRINTLIST")
																style:UIAlertActionStyleDefault
															  handler:^(UIAlertAction *action) {
																  nslog(@"プログラム印刷");
																  [self printList];
																  clickSound();
															  }]];
			// v3.20
			[alertController addAction:[UIAlertAction actionWithTitle:NSLocalStr(@"PRINTDEBUG")
																style:UIAlertActionStyleDefault
															  handler:^(UIAlertAction *action) {
																  nslog(@"デバッグ画面印刷");
																  [self printDebug];
																  clickSound();
															  }]];
			if (mesPrintScreen!=nil) {
				[alertController addAction:[UIAlertAction actionWithTitle:mesPrintScreen
																	style:UIAlertActionStyleDefault
																  handler:^(UIAlertAction *action) {
																	  nslog(@"実行画面印刷");
																	  [self printScreen];
																	  clickSound();
																  }]];
			}
		}
		[alertController addAction:[UIAlertAction actionWithTitle:NSLocalStr(@"CANCEL")
															style:UIAlertActionStyleDefault
														  handler:^(UIAlertAction *action) {
															  nslog(@"キャンセルが押された");
														  }]];
		if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
			// iPadのときは以下の設定によりpopover形式にしなければならない
			alertController.popoverPresentationController.sourceView=self.view;
			alertController.popoverPresentationController.barButtonItem=btn;
		}
		// 表示
		clickSound();
		[self presentViewController:alertController animated:YES completion:nil];
	} else {
		// iOS7ではActionSheetが使える
		actionSheet = [[UIActionSheet alloc]
					 initWithTitle:NSLocalStr(@"ACTION")
						  delegate:self
				 cancelButtonTitle:NSLocalStr(@"CANCEL")	// ボタン番号=cancelButtonIndex
			destructiveButtonTitle:nil
					   otherButtonTitles:menuStr, 			// ボタン番号=firstOtherButtonIndex=0
									NSLocalStr(@"RUNSCREEN"),	// 1
								 	NSLocalStr(@"DEBUGSCREEN"),	// 2	// v3.20
								 	NSLocalStr(@"PRINTLIST"),	// 3
									NSLocalStr(@"PRINTDEBUG"),	// 4	// v3.20
								 	mesPrintScreen,				// 5
								 	nil
				  ];
		setActionSheetResize(actionSheet); // リサイズ指定
		// 表示
		clickSound();
		[actionSheet showInView:self.view];
	}
}

// iOS8
-(void)closeActionSheet
{
	printSelf();
	[alertController dismissViewControllerAnimated:NO completion:nil];
}

//----------------------------------------------
// popover表示処理(iPad)
//----------------------------------------------

// popoverが開いているときは強制的に閉じる
/* popoverがpopoverControllerDidDismissPopoverで消えるときは、
 popoverControllerDidDismissPopover→MailMessgaeCtrl:viewWillDisapearの順で呼び出されてしまう
 閉じるべきビューの処理のほうが後に来るので要注意。
 */
-(void)closePopover
{
	printSelf();
	nslog(@"fpopover=%d",(int)fpopover);
	switch (fpopover) {
		case POPOVER_ACTION: // iOS8
			nslog(@"ActionSheetが開いている");
			[self closeActionSheet];
			break;
		case POPOVER_HELP:
			// ヘルプは構造が変わったのでfpopoverを変更してはいけない
			return;
		case POPOVER_BASIC:
			clickStop();
			// ソース読み込みはなく閉じるだけ
			[self basicCancelButton:self];
			break;
		case POPOVER_SETUP:
			clickStop();
			[self setupSaveButton:self]; // ここでsetupの設定がボタンに反映される
		default: // POPOVER_NONE:iPhoneの時は常にここ
			nslog(@"default fpopover=%d",(int)fpopover);
			break;
	}
	clickResume();
	fpopover=POPOVER_NONE;
}

//------------

// popoverが消えた後に呼び出される
// dismissPopoverAnimatedでは来ないのは仕様
// 此処に来るときはPopoverは確実に開かれているし、dissmissも自動的に行われる
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController_
{
	printSelf();
	// 閉じる処理
	// setupではサブ画面中の時もあるが、全てsetupVireControllerを開放すれば一緒に解放されるので問題ない
	//	pickerView
	// →popoverControllerShouldDismissPopoverをNOにしたので、setupからはここに来ることはない
	[self closePopover];
}

// 閉じて良いかどうかの確認
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController_
{
	printSelf();
	switch (fpopover) {
		case POPOVER_BASIC:
			return YES;
		case POPOVER_HELP: // ヘルプは構造が変わったので、勝手に閉じてはいけない
		case POPOVER_SETUP:
		default:
			break;
	}
	// 途中では閉じさせない（途中閉じを許すと処理が大変面倒なので）
	return NO;
}

//----------------------------------------------
// ツールバーボタン押下時処理
//----------------------------------------------

// モード設定
// mode=MODE_*
-(void)setMode:(NSUInteger)mode
{
	printSelfs(@"mode=%d",(int)mode);
	//
	[self startIndicator];
	[self closePopover];			// popoverが出ていたら消す
	[_editorView eraseSearchBar]; 	// 検索が出てたら消す
	[_editorView.editor resignFirstResponder]; // キーボードを消す
	/* 可能状態遷移		現在状態と表示ボタン
	 LIST→EDIT			LIST	EDIT
	 EDIT→LIST			EDIT	LIST
	 */
	if (opeMode==mode) {
		// 同じモードの遷移指定なのでキャンセル
		nslog(@"同じモードの遷移指定なのでキャンセル");
	} else {
		nslog(@"異なるモード");
		NSInteger oldMode=opeMode;
		_editorView.opeMode=	// エディターにも(先に)通知
					opeMode=mode;
		
		CGPoint ofst=_editorView.editor.contentOffset; // モード変更時にスクロール位置が変わらないように
		switch (mode) { // 今度設定するモード
			case MODE_LIST:
				nslog(@"LISTにする");
				//consoleBackGround.hidden=YES; // コンソールを非表示
				btnEdit.title=NSLocalStr(@"EDIT");
				[_editorView lineNoHidden:NO];	// 行番号を表示
				_editorView.editor.editable=NO;  // 編集不可
				if (oldMode==MODE_EDIT) { // EDIT<→LIST切替時はアニメーションさせない
					_editorView.hidden=NO; // エディターを表示する
					btnActionSheet.enabled=YES;
				} else {
					[UIView transitionWithView:_editorView // 最後に表示したいView
									  duration:0.3
									   options:UIViewAnimationOptionTransitionFlipFromLeft
									animations:^{
										_editorView.hidden=NO;
									}
									completion:^(BOOL fnished){
										btnActionSheet.enabled=YES;
									}
					];
					//btnActionSheet.enabled=YES;
				}
				// 行番号表示位置はwebViewDidFinishLoadにて合わせる(合わせなければならない)
				break;
			case MODE_EDIT:
				nslog(@"EDITにする");
				btnEdit.title=NSLocalStr(@"LIST");
				[_editorView lineNoHidden:YES];		// 編集中は行番号を消す
				_editorView.editor.editable=YES; 	// 編集可=キーボードが表示される可能性あり
				_editorView.hidden=NO;				// エディターを表示する
				btnActionSheet.enabled=YES;
				break;
		}
		// iOS7 UITextViewのスクロール領域がおかしくなるバグ回避のため
		_editorView.editor.contentOffset=ofst; // スクロール位置を戻す
	}
	[self stopIndicator];
	nslog(@"setMode end");
}

-(void)displayError
{
	if (errorCnt>0) {	// エラーがあるのでエラー処理
		nslog(@"コンパイルエラーまたは実行時エラー → LIST");
		[self setMode:MODE_LIST];
		[_editorView errorJump];
	}
}

// Naviのボタン用
// RUN/Break
-(IBAction)naviButtonAction:(id)sender
{
	UIBarButtonItem *btn=(UIBarButtonItem *)sender;
	printSelfs(@"UIBarButtonItem=%d",(int)btn.tag);
	switch (btn.tag) {
		case BUTTON_SEARCH:
			clickSound();
			if (fpopover==POPOVER_HELP) {
				[webHelp searchString];
			} else {
				[_editorView searchString];
			}
			break;
		
		case BUTTON_RUN:
			// ソース画面(EDIT/LIST)から来る
			nslog(@"ButtonRun:%s",sourceTop);
			[self webHelpClose];
			// editorの中にあるソースをsourceに戻す;保存しない時も実行のために必要
			[self editorToSource]; // editSaveするとfafterEditフラグがNOになるのでその前に処理する
			[_editorView errorViewHidden:YES]; // エラーも一旦消す
			[_editorView remakeLineNoAll]; // 検索結果を消すのと行番号側への反映
			[self editSave]; // ソースが編集されているときは、先に保存確認
			
			// コンパイル処理
			[self startIndicator];
			nslog(@"コンパイル開始:%@",@(__FILE__));
			[_editorView compilePrepare];
			{
			NSString *str=[NSString stringWithFormat:@"%@ : %@\n",NSLocalStr(@"COMPILE"),setup.basicFileOnly];
			nslog(@"メッセージ=%@",str);
			operationStatus.programName=nsStringTocString(str);
			}
			xb_setStartupLines(startupLines);
			// ↓ここで_Finitの実行がかかるので注意
			XB_ERRORNO ret=xb_compile(); // retで返ってくるのはメモリ不足のみ。他はret=ERR_NONEでerrorCnt>0でlastErrNo参照
			nslog(@"コンパイル終了:%@",@(__FILE__));
			[self stopIndicator];
			if (ret==ERR_NO_WORKAREA) {
				nslog(@"メモリ不足");
				[self noMemory];
				[self waitAlertEnd]; // 終了待ち
				exit(1);
			}
			nslog(@"エラーがなければモードを変更し実行:errCnt=%d/ret=%d/lastErrNo=%d",errorCnt,ret,lastErrNo);
			if (errorCnt==0) {
				[self presentViewController:_runView animated:YES completion:^{ // RUN画面表示
					nslog(@"プログラム実行");
					_runView.rootView=self;
					[_runView run];
				}];
				// この後のタスクの切り替えでroot viewDidDisapperarを通る
			} else {
				nslog(@"コンパイルエラーあり時");
				[self startIndicator];
				xb_end(YES); // 終了処理
				[self stopIndicator];
			}
			// コンパイルエラーがあれば表示する
			[self displayError];
			break;
		
		case BUTTON_EDIT: // EDIT/LIST
			nslog(@"ButtonEdit");
			[self webHelpClose]; // webHelpが開いていたら閉じる
			switch (opeMode) { // 現在のモード
				case MODE_EDIT: // EDIT→LIST
					nslog(@"EDIT→LIST");
					[self startIndicator];
					[self editorToSource]; // editorの中にあるソースをsourceに戻す

					[_editorView remakeLineNoAll]; // 検索結果を消すのと行番号側への反映

					[self editSave]; // ソースが編集されているときは、先に保存確認
					[self setMode:MODE_LIST];
					[self stopIndicator];
					break;
				case MODE_LIST: // LIST→EDIT
					nslog(@"LIST→EDIT");
					if (operationStatus.fsjis) {
						// 強制SJISでは編集不可
						[self cantEditAlert];
					} else {
						[self setMode:MODE_EDIT];
					}
					break;
			}
			break;
	}
}

// ツールバーのボタン用
-(IBAction)toolButtonAction:(id)sender
{
	UIBarButtonItem *btn=(UIBarButtonItem *)sender;
	printSelfs(@"UIBarButtonItem=%d",(int)btn.tag);
	
	// エディタのキーボードが出ているときは消す
	if ([_editorView.editor isFirstResponder]) {
		[_editorView.editor resignFirstResponder];
	}
	
	// window背景色を復帰
	app.window.backgroundColor=winColor;

	// 前回分のpopOver内ビューコントローラー解放処理
	switch (btn.tag) {
		case BUTTON_HELP:
			nslog(@"BUTTON_HELP");
			// ここでは検索結果は残しておく
			switch (fpopover) {
				case POPOVER_HELP:
					// 同じボタンが二度押しされたときは閉じる(iPad;iPod touchではそもそも押せない)
					nslog(@"二度押し");
					[self webHelpClose];
					break;
				case POPOVER_SETUP:
					nslog(@"setupを開いているときは他は受け付けない");
					break;
				default:
					// iPhoneの時は常にfpopover==POPOVER_NONE
					if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
						[_editorView keyboardNotification:NO]; // editorへのキー通知を解除
						[webHelp openWebHelp:@"XBASIC_iOS" fromView:_editorView];
						fpopover=POPOVER_HELP;
					} else {
						self.help=[[Help alloc]init];
						[_help open:self selector:@selector(helpCloseButton:)];
						[self anyOpen:_help btn:btnHelp popover:POPOVER_HELP ];
					}
					break;
			} // switch (fpopover)
			break;
		
		case BUTTON_BASIC:
			nslog(@"BUTTON_BASIC");
			[self editorToSource]; // editorの中にあるソースをsourceに戻す
			[_editorView remakeLineNoAll]; // 検索結果を消すのと行番号側への反映
			[self editSave]; // ソースが編集されているときは、先に保存確認
			switch (fpopover) {
				case POPOVER_BASIC:
					// 同じボタンが二度押しされたときは何もしない
					nslog(@"二度押し");
					break;
				case POPOVER_HELP:
					// HELPを開いているときにBASICを押した時
					[self webHelpClose];
				default:
					// iPhoneの時は常にfpopover==POPOVER_NONE
					
					// 先にズームを解除してかないと動作不良になるので(V3.00)
					[_editorView resetZoomWithAnimation];
				{
					// 全く原因不明だが、[BasicFiles alloc]initWithNibNameで_mainView.setup.basicFileの内容が破壊されてしまうことがあるので、先に別変数にコピーしておく(setup.basicFileをcopy属性にしても変わらない)
					NSString *bas=[setup.basicFile copy];
					self.basicSelect =[[BasicSelectWithTable2 alloc]init];
					[self.basicSelect open:self retSelector:@selector(basicCloseButton:) basicPath:bas calcelSelector:@selector(basicCancelButton:)];
					self.basicSelect.nowFile=setup.basicFileOnly;	// ファイル名のみ	v3.20で未使用になったが念のため
					self.basicSelect.nowPath=setup.basicFile;		// フルパス名	v3.20
					[self anyOpen:self.basicSelect btn:sender popover:POPOVER_BASIC ]; // BASICプログラムの選択
				}
					break;
			} // switch (fpopover)
			break;
		
		case BUTTON_SETTING:
			nslog(@"BUTTON_SETTING");
			[self editorToSource]; // editorの中にあるソースをsourceに戻す
			[_editorView remakeLineNoAll]; // 検索結果を消すのと行番号側への反映
			[self editSave]; // ソースが編集されているときは、先に保存確認
			switch (fpopover) {
				case POPOVER_SETUP:
					// 同じボタンが二度押しされたときは何もしない
					nslog(@"二度押し");
					break;
				default:
					// 設定が終わるまで、他のボタンは無効化する
					_editorView.btnLineNo.enabled=
					btnSearch.enabled=
					btnActionSheet.enabled=
					btnHelp.enabled=
					btnRun.enabled=
					btnEdit.enabled=
					btnBasic.enabled=NO;
					// iPhoneの時は常にfpopover==POPOVER_NONE
					self.setupViewController =[[SetupViewController alloc]init];
					[_setupViewController open:self retSelector:@selector(setupSaveButton:)];
					[self anyOpen:_setupViewController btn:sender popover:POPOVER_SETUP];
					break;
			} // switch (fpopover)
			break;
	}
}

//-------------------------------------------------------------------

-(void)anyOpen:(UIViewController *)viewCtrl btn:(id)btn popover:(NSInteger)popover
{
	nslog(@"anyOpen:%@ btn:%@ poppver:%d ",viewCtrl,btn,(int)popover);
	
	clickSound(); // クリック音
	[_editorView eraseSearchBar]; // 検索が出てたら消す
	if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
		nslog(@"anyOpen:iPad");
		[self closePopover]; // 他のを閉じる

		UINavigationController *navi=[[UINavigationController alloc]initWithRootViewController:viewCtrl];
		self.popover=[[UIPopoverController alloc]initWithContentViewController:navi];
		self.popover.popoverContentSize=viewCtrl.view.frame.size;	// popoverのサイズを設定
		self.popover.delegate=self;
		[self.popover presentPopoverFromBarButtonItem:btn permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
		fpopover=popover;
	} else { // iPod touch/iPhone
		nslog(@"anyOpen:iPod Touch/iPhone");
		[self.navigationController pushViewController:viewCtrl animated:YES];
	}
}

-(void)anyClose
// これが呼び出されるときは、必ず対象が開いている
{
	printSelf();
	//
	clickSound(); // クリック音
	if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { // iPad
		// popoverを消す
		[self.popover dismissPopoverAnimated:YES];	// popoverは指示を出してから実際に閉じるまでに時間がある
		fpopover=POPOVER_NONE;
	} else { // iPhone
		[self.navigationController popViewControllerAnimated:YES];
	}
	//
	nslog(@"anyClose:終了");
}

// 以下target:selectorで飛んでくる

// これが呼び出されるときは、必ずHelpが開いている
-(void)helpCloseButton:(id)sender
{
	printSelfs(@"%@",sender);
	[self anyClose];
}

// これが呼び出されるときは、必ずBasicFilesが開いている
-(void)basicCloseButton:(NSString *)path
{
	printSelfs(@"%@",path);
	// 閉じる
	[self anyClose];
	// ソースを変更
	[self loadBasic:path];	// setup.への保存はここ
}

-(void)basicCancelButton:(id)sender
{
	printSelfs(@"%@",sender);
	// 消すだけ
	[self anyClose];
}

// 保存して閉じる
// これが呼び出されるときは、必ずSetup系が開いている
-(void)setupSaveButton:(id)sender
{
	printSelfs(@"sender=%@",sender);
	
	// 設定値保存
	[setup saveSetup];
	[self anyClose];

	nslog(@"setupSaveButton.setFontWithFile");
	[self setFontWithFile];

	// 設定をXBへ渡す
	[setup setup2XBoperationStatus];
	//
	_editorView.btnLineNo.enabled=
	btnSearch.enabled=
	btnActionSheet.enabled=
	btnHelp.enabled=
	btnRun.enabled=
	btnEdit.enabled=
	btnBasic.enabled=YES;
	//
	nslog(@"setupSaveButton:終了");
}

-(void)webHelpClose
{
	printSelf();
	if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
		if (fpopover==POPOVER_HELP) {
			UIView *toView=_editorView; // 警告回避のため
			switch (opeMode) { // 元のモード
				case MODE_EDIT:
				case MODE_LIST:
					nslog(@"EDIT/LIST");
					toView=_editorView;
					break;
			}
			clickSound();
			[webHelp closeWebHelp:toView];
			[_editorView keyboardNotification:YES]; // キー通知をeditorに戻す
			fpopover=POPOVER_NONE;
		}
	}
}

//----------------------------------------------
// 画面回転
//----------------------------------------------

// 回転検出：回転前
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
	printSelfs(@"Orientation=%d",(int)interfaceOrientation);
	understandOrientation(interfaceOrientation); // 画面方向を記録
	// interfaceOrientationは新しい方向
	switch (interfaceOrientation) {
		default:
		case UIInterfaceOrientationPortrait:
		case UIInterfaceOrientationPortraitUpsideDown:
			nslog(@"縦方向");
			break;
		case UIInterfaceOrientationLandscapeLeft:
		case UIInterfaceOrientationLandscapeRight:
			nslog(@"横方向");
			break;
	}
	[_editorView changeEditorView:_editorView.frame];
}

// 回転検出：回転後
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
	printSelf();
	nslog(@"%d",(int)fromInterfaceOrientation); /* 現在の方向 */
	[_editorView changeEditorViewEnd];
}


// 画面を回転して良いかどうか
-(BOOL)shouldAutorotate
{
	printSelf();
	return shouldAutorotateByMain();
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
	printSelf();
	return (supportedInterfaceOrientationsByMain());
}

//----------------------------------------------
// 終了・異常時処理
//----------------------------------------------

- (void)didReceiveMemoryWarning
{
	printSelf();
    [super didReceiveMemoryWarning];
	[self noMemory];
	[self waitAlertEnd]; // 終了待ち
	exit(1);
}

#ifdef MEMREPORT
-(void) report_memory
{
    struct task_basic_info info;
    mach_msg_type_number_t size = sizeof(info);
    kern_return_t kerr = task_info(mach_task_self(),
                                   TASK_BASIC_INFO,
                                   (task_info_t)&info,
                                   &size);
    if( kerr == KERN_SUCCESS ) {
        nslog(@"Memory in use (in bytes): %u", (int)info.resident_size);
    } else {
        nslog(@"Error with task_info(): %s", mach_error_string(kerr));
    }
}
#endif

@end
