//
//  WebHelp.m
//  X-BASIC'
//
//  Created by AIG-Soft(iMac) on 2012/09/27.
//  Copyright (c) 2012-15年 AIG-Soft. All rights reserved.
//

#import "WebHelp.h"
#import "FileControl2.h"
#import "libs.h"
#import "click.h"

@implementation WebHelp

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

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}

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

-(void)openWebHelp:(NSString *)helpFile fromView:(UIView *)fromView
// helpFileはローカライズされる
{
	// 初期設定
	search=nil;
	scrollView=self.scrollView; // scrollViewのみ抜き出しておく
	self.delegate=self; // UIWebViewのdelegate
	alertView.delegate=self; // 念のため
	url=nil;
	self.scrollView.scrollsToTop=YES;	// ステータスバーのタップで先頭にスクロール;スクロールさせたいもののみYESにし、他はNOにしなければならない;iOS7ではデフォルトがNOに変更されたので強制ON
	//
	floaded=NO;
	NSString *path=makeFullPathForResource(NSLocalStr(helpFile),@"html"); // ここはリソース内だけでOK
	NSURL *base=[NSURL fileURLWithPath:path]; // HTML内のリンクを解決するため、これが非常に重要
	nslog(@"base=%@",base);
	[self loadHTMLString:[NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL] baseURL:base];
	self.hidden=NO;
	self.alpha=0.0;
	[UIView transitionWithView:self // 最後に表示したいView
					  duration:0.5
					   options:UIViewAnimationOptionTransitionCurlUp
					animations:^{
						self.alpha=1.0;
						fromView.hidden=YES;
					}
					completion:^(BOOL fnished){
					}
	 ];
	DoAnimation();
	//
	alertView=[[UIAlertView alloc]initWithTitle:NSLocalStr(@"EXTLINK")
									message:@""
								   delegate:self
						  cancelButtonTitle:NSLocalStr(@"NO")
						  otherButtonTitles:NSLocalStr(@"YES"),nil];
	setAlertViewResize(alertView); // リサイズ設定
	//
	fopenAlert=NO; // アラートを表示していないフラグ
}

-(void)webViewDidFinishLoad:(UIWebView *)webView
{
	printSelf();
	floaded=YES;
}

-(void)closeWebHelp:(UIView *)toView
{
	[self eraseSearchBar]; // 検索中の時は先に検索を解除する(v2.8)
	[UIView transitionWithView:toView // 最後に表示したいView
					  duration:0.5
					   options:UIViewAnimationOptionTransitionCurlDown
					animations:^{
						self.alpha=0.0;
					}
					completion:^(BOOL fnished){
						// 元のモードに従って画面を戻す
						self.hidden=YES;
						self.alpha=1.0; // 戻しておく
						toView.hidden=NO;
					}
	 ];
	DoAnimation();
}

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

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
// webViewからのデリゲート
{
	// リンクはそのままではwebView内で開いてしまうので、ブラウザが開くように処理を差し替える
	nslog(@"request=%@",request);
	switch (navigationType) {
		case UIWebViewNavigationTypeLinkClicked: // リンクがクリックされたとき
			// リンクに飛ぶ前に確認する
			{
			NSURL *url0=[request URL];
			nslog(@"確認前url=%@\nscheme=%@",url0,[url0 scheme]);
			if ([[url0 scheme]hasPrefix:@"file"]) {
				break; // file:の時は内部なので、何もしないで開けば良い
			}
			url = [url0 copy]; // copyしないと消えてしまうので要注意
			}
			[alertView show]; // 表示したらすぐ終わる
			fopenAlert=YES; // アラートを表示しているフラグ
			nslog(@"alertView終了");
			return(FALSE);
		default:
			break;
	}
	return(TRUE);
}

-(void)closeAlertView
// アラートの強制閉じ
{
	printSelf();
	// アラート中は他のすべてのキー入力は禁止されているので、此処に来る可能性があるのは画面回転時のみ
	// (バックグラウンド時はアラートも消す必要がない)
	if (fopenAlert) {
		// キャンセル相当にする
		if (url!=nil) {
			url=nil;
		}
		[alertView dismissWithClickedButtonIndex:0 animated:NO];
		fopenAlert=NO; // アラートを表示してないフラグ
	}
}

-(void)alertView:(UIAlertView *)alertView_ clickedButtonAtIndex:(NSInteger)buttonIndex
// アラートビューでボタンがクリックされた時に呼び出されるデリゲート
{
	printSelfs(@"button=%d",(int)buttonIndex);
	if (buttonIndex!=alertView.cancelButtonIndex) {	// 「はい」のとき
		nslog(@"直前url=%@",url);
		nslog(@"はい");
		// リンクへ飛ぶ
		[[UIApplication sharedApplication] openURL:url]; // httpがあるので自動的にブラウザが立ち上がる
	}
}

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

-(void)scrollToEndOfHelp
{
	CGSize  size=scrollView.contentSize;
	CGPoint ofst={-scrollView.contentInset.left,size.height-self.frame.size.height*3};
	if (ofst.y<0) ofst.y=0;
	scrollView.contentOffset=ofst; // 3画面前まで一気に飛ばす
	// 最後の2画面だけアニメーション;途中も全部スクロールするの画面が瞬くようになるので
	ofst.y=size.height-self.frame.size.height;
	if (ofst.y<0) ofst.y=0;
	// アニメーションしながらスクロール
	[UIView animateWithDuration:1.0
					 animations:^{ // アニメーション処理
						 scrollView.contentOffset=ofst;
					 }
					 completion:^(BOOL finished){ // 終了時処理
						 nslog(@"webhelp.アニメーション終了:%d",finished);
					 }
	 ];
	DoAnimation();
}

//----------------------------------------------
// 検索
//----------------------------------------------

-(void)searchString
{
	nslog(@"WebView内文字列検索");
	if (search==nil) {
		// HTMLの読み込み終了を待つ(念のため)
		while (!floaded) {
			EnterRunLoop(0.2);
		}
		nslog(@"helpは読み込み済み");
		// EditorView.mのsearchとの違い
		// EditorViewではedtorViewの上にeditorとsearchが存在している
		// =frameはEditorViewを基準として付けられる。
		// これに対し、WebHelpはself=UIWebViewであり、この上にsearchが配置される
		// =frameはself基準であり、それを移動すればsearchも同時に移動してしまう
		// WebHelpをEditorViewと同じ構造にすれば解決できるが、それは大作業であり、
		// 今回は重なることで諦める
		// searchのorigin.yを-SEARCH_BAR_HEIGHT_IPADにすれば表示上解決できるが、
		// 今度はCancelボタンが効かないという問題が発生する。
		// 負数座標領域内にあるボタンなどは使えない仕様である。
		CGRect frame={{0,0},{self.frame.size.width,SEARCH_BAR_HEIGHT_IPAD}};
		search=[[UISearchBar alloc]initWithFrame:frame];
		printFrame(@"search", search.frame);

		search.autocapitalizationType=UITextAutocapitalizationTypeNone;
		search.showsCancelButton=YES;
		search.autocorrectionType=YES;
		search.barStyle=UIBarStyleDefault;
		search.translucent=YES;
		search.keyboardType=UIKeyboardTypeDefault;
		search.placeholder=NSLocalStr(@"SEARCH");
		search.delegate=self;
		//
		[self addSubview:search];
		[self keyboardNotification:YES]; // 通知を有効にする
		//
		[self searchBarWithScreen:1.0]; // 検索バー分、webViewを下げる(相当)
	} // すでに検索バーを表示中の時は、キーボードを戻すだけ
	// キーボードを表示
	[search becomeFirstResponder];
}

-(void)searchBarWithScreen:(CGFloat)direc
// 検索バーの表示に従ってwebView位置を調整する
// direc : 1.0=下げる , -1.0=上げる
{
	nslog(@"検索バー分、webViewを%@(相当)",direc<0? @"上げる":@"下げる");
	//
	UIScrollView *webScroll=self.scrollView;
	CGPoint ofst=webScroll.contentOffset;
	printOffset(@"元WebScroll.contentOffset",ofst);
	if (ofst.y>=search.frame.size.height) {
		CGFloat h=search.frame.size.height*direc;
		// WebViewを見た目下げるにはoffsetを-する
		// 見た目上げるにはoffsetを+する
		ofst.y-=h;
		printOffset(@"新WebScroll.contentOffset",ofst);
		webScroll.contentOffset=ofst;
	}
	// 残念ながらcontentOffsetは負数にしても0に補正されるので、searchBarの高さ未満の領域が先頭であるときには検索バーが重なって表示される
	// これは現在の実装上致し方無い
#if 0
	CGRect frame=self.frame;
	printFrame(@"webView", frame);
	frame.origin.y   +=h;
//	frame.size.height-=h;	// これをするとなぜか高さがh*2減ってしまうので削除(V2.8)
	self.frame=frame;
	printFrame(@"webView", frame);
#endif
}

-(void)eraseSearchBar
{
	printSelf();
	if (search==nil) {
		nslog(@"すでに消えているので何もしない");
		return;
	}
	clickSound();
//	[self keyboardNotification:NO];
	
	// iOS8で外部キーボードのときはkeyboardDidHideが呼び出されないので
	[self eraseSearchBarMain];
	
	[search resignFirstResponder];  // キーボードを消す→keyboardDidHide→eraseSearchBarMainが呼び出される
//	[search removeFromSuperview];
//	[self searchBarWithScreen:-1.0]; // 検索バー分、editorを上げる(相当)
//	[self keyboardDidHide:nil]; // WebViewを元に戻す
//	search=nil;
}

-(void)eraseSearchBarMain
{
	printSelf();
	[self keyboardNotification:NO];
	[search removeFromSuperview];
	[self searchBarWithScreen:-1.0]; // 検索バー分、editorを上げる(相当)
	[self keyboardDidHide:nil]; // WebViewを元に戻す
	search=nil;
}

- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
	printSelf();
	[self removeAllHighlights]; // 検索結果をすべて消す
	[self eraseSearchBar];
	// iOS6までは検索欄に何か入力しないとCancelボタンは押せるようにならない。iOS7では問題ない。
}

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
	printSelf();
	[self removeAllHighlights]; // 前の検索結果をすべて消す
#ifdef DEBUG
	NSInteger len=
#endif
	[search.text length];
#ifdef DEBUG
	nslog(@"検索文字列(len=%d)=%@",(int)len,search.text);
#endif
	// 実検索処理
	NSInteger cnt=[self highlightAllOccurencesOfString:search.text];
	nslog(@"発見個数=%d",(int)cnt);
	if (cnt==0) {
		// 見つからない
		[self displaySearchEnd];
	}
	[self eraseSearchBar]; // 検索バーを消す
}

-(void)displaySearchEnd
// 「検索終了」としばらく表示して消す
{
	printSelf();
	alertView = [[UIAlertView alloc]  initWithTitle:NSLocalStr(@"SEARCHEND")
											message:NSLocalStr(@"AUTOERASE")
										   delegate:self
								  cancelButtonTitle:nil
								  otherButtonTitles:NSLocalStr(@"OK"),nil
				 ];
	[alertView show];
	// 一定時間後に消去
	[self performSelector:@selector(eraseSearchEnd:) withObject:self afterDelay:2.0];
}

-(void)eraseSearchEnd:(id)sender
{
	printSelf();
	[alertView dismissWithClickedButtonIndex:0 animated:YES]; // ボタン番号は適当
	alertView=nil; // 開放した印
}

//----------------------------------------------
// キーボード表示/消去通知
//----------------------------------------------

-(void)keyboardNotification:(BOOL)onoff
// キーボード表示通知の設定
{
	if (onoff) { // ON
		nslog(@"keyboardNotification on");
		// キーボード表示時に通知させる
		[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
		// キーボード消去時に通知させる
		[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:)  name:UIKeyboardDidHideNotification  object:nil];
		//
	} else { // OFF
		nslog(@"keyboardNotification off");
		// キーボード通知の解除
		[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
		// キーボード消去時に通知させる
		[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification  object:nil];
	}
}

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

-(void)keyboardWillShow:(NSNotification *)notification
{
	nslog(@"keyboardWillShow=%@",notification);
	if (keyboardFrameEnd.size.height!=0) {
		nslog(@"すでに表示中なので何もしない");
		// なぜかキーボードがすでに表示されているにもかかわらず再度通知がかかることがあるので
		return;
	}
	
	// キーボードの表示開始時の場所と大きさを取得
	//	keyboardFrameBegin = [[notification.userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
	//	printFrame(@"キーボード表示開始時サイズ", keyboardFrameBegin);
	
	// キーボードの表示完了時の場所と大きさを取得
	keyboardFrameEnd = [(notification.userInfo)[UIKeyboardFrameEndUserInfoKey] CGRectValue];
	printFrame(@"キーボード表示終了時サイズ", keyboardFrameEnd); // {origin.x,y},{size.width,height}}
	// iOSバグ：横画面において、キーボードwidthとheightが逆になってる(iPadで確認、iPhoneは不明)
#if 0
	//UIDeviceOrientation deviceOrientation=[UIDevice currentDevice].orientation; <- これではシミュレーター上では方向が得られない
	switch (deviceOrientation) {
		case UIDeviceOrientationLandscapeLeft:
		case UIDeviceOrientationLandscapeRight:
		{ // なので入れ替える
			nslog(@"横画面なのでwidth←→heightを入れ替える");
			CGFloat w=keyboardFrameEnd.size.width;
			keyboardFrameEnd.size.width=keyboardFrameEnd.size.height;
			keyboardFrameEnd.size.height=w;
			printFrame(@"修正キーボード表示終了時サイズ", keyboardFrameEnd); // {origin.x,y},{size.width,height}}
		}
		default:
			nslog(@"他方向:%d",deviceOrientation);
			break;
	}
#else
	// deviceOrientationではシミュレーター上では方向が得られないので、簡易的に幅の大小で判定している
	CGFloat w=keyboardFrameEnd.size.width;
	if (w<keyboardFrameEnd.size.height) {
		nslog(@"横画面なのでwidth←→heightを入れ替える");
		keyboardFrameEnd.size.width=keyboardFrameEnd.size.height;
		keyboardFrameEnd.size.height=w;
		printFrame(@"修正キーボード表示終了時サイズ", keyboardFrameEnd); // {origin.x,y},{size.width,height}}
	}
#endif
	//
	// webHelpの表示サイズとスクロールバーを変更
	// origin=始点(固定) , size=表示サイズ
	CGRect frame=self.frame;
	printFrame(@"キーボード前webView", frame);
	frame.size.height-=keyboardFrameEnd.size.height;
	printFrame(@"キーボード付きwebView", frame);
	self.frame=frame;
}

-(void)keyboardDidHide:(NSNotification *)notification
{
	nslog(@"keyboardDidHide=%@",notification);
	// サイズを戻す
	CGRect frame=self.frame;
	frame.size.height+=keyboardFrameEnd.size.height; // keyboardWillShowで得ていた値
	printFrame(@"キーボードなしwebView", frame);
	self.frame=frame;
	// キーボードを消した印
	keyboardFrameEnd.size.height=0;
	if (notification!=nil) {
		// 検索そのものも解除してしまう
		[self eraseSearchBarMain];
	} // eraseSearchBarから呼び出したときはnotification=nil
}

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

-(void)dealloc
{
	printSelf();
	self.delegate=nil; // なんか必要なのだそうな
}

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


@end
