//
//  TegakiScroll.m
//	手書き処理；スクロール処理対応
//  traceWrite
//
//  Created by 今井 彰彦 on 2011/12/11.
//  Copyright (c) 2011 AIG-Soft. All rights reserved.
//

#import "TegakiScroll.h"
#import "libs.h"
#import "GeneratePdf.h"
#import "SnapShot.h"
#import "FileControl2.h"
#import "main.h"

@implementation TegakiScrollView

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

// Tegakiのそれのオーバーライド
-(void)initTegaki:(id)delegate_ scrollView:(UIScrollView *)scrollView_ imageView:(UIImageView *)imageView_
{
	printSelf();
	//
	[super initTegaki:delegate_ scrollView:scrollView_ imageView:imageView_];
	//
	delegateScroll=delegate_;
	//
	[self load]; // ファイルから読み込み
	//
	fBegin		=BIT_NOBEGIN;
	_fEnableTouch=YES;
	multiTouch	=0;
	fScrollMode	=SCRL_NONE; // スクロールしてない
	[delegateScroll hiddenScrollSymbol:YES]; // スクロールシンボル消去
	savePoint	=-1;
	fsave		=NO; // save出来る
}

//-------------------------------------------------------------------
// 保存・読み出し
//-------------------------------------------------------------------

-(void)load
// ストロークデータをファイルから読み出す
{
	printSelf();
	
	// 手書きトレースデータ
	super.lineArray =[[NSMutableArray alloc]init];
	//
	// V2.0でのファイル名変更に対応
	NSString *path	  =makeFullPathForSaveData(TEGAKIFILE);		// 新ファイル名
	NSString *path_old=makeFullPathForSaveData(TEGAKIFILE_OLD); // 旧ファイル名
	nslog(@"手書きファイル=%@",path);
	NSFileManager *fp=[NSFileManager defaultManager];
	if ([fp fileExistsAtPath:path_old]) {
		// 旧ファイル名が存在する
		nslog(@"旧手書きファイル=%@",path_old);
		// 新ファイル名に変名する
		nslog(@"旧ファイル名->新ファイル名");
		NSError *error;	
		if (![fp moveItemAtPath:path_old toPath:path error:&error]) { // ファイル名変更
			// エラー発生
			nslog(@"error=%@",error);
#if 0
			// その時は元ファイルを消してしまう
			[fp removeItemAtPath:path_old error:nil];
#endif
		}
	}
	//
	NSFileManager *fileManager=[NSFileManager defaultManager];
	if ([fileManager fileExistsAtPath:path]) {
		nslog(@"手書きファイルあり");
		NSData *data=[NSData dataWithContentsOfFile:path]; // 全体を一括読み込み
		//
		LINES line1;
		NSRange range={0,SZ_LINES}; // 最初の取得位置
		NSInteger length=[data length];
	//	nslog(@"data=%@(%d)",data,length);
		drawStart=0;
		while (length>0) {
			[data getBytes:&line1 range:range];
			[self.lineArray addObject:[NSValue value:&line1 withObjCType:@encode(LINES)]];
			range.location+=SZ_LINES;
			length-=SZ_LINES;
			drawStart++;
		}
		nslog(@"データ数=%d",(int)drawStart);
		// drawStartから後がdrawRect対象となる(新規ストローク=imageViewに入ってない)
		if (drawStart==0) {	// データ数=0のときも手書きファイルなしと同様とする
			// 念のためファイルも削除しておく
			nslog(@"データ数=0:手書きファイルなしと同様とする");
			[[NSFileManager defaultManager]removeItemAtPath:path error:nil];
		} else {
			// ストロークデータをロードしたので、次回snapshot必要：ここでimageView確定
			fsnapShot=FSNAPSHOT_ALL;
		}
	} else {
		nslog(@"手書きファイルなし");
	}
	nslog(@"lineArray=%d",(int)[self.lineArray count]);
}

-(void)save
// ストロークデータをファイルに記録する
{
	printSelf();
	if (savePoint==[self.lineArray count]) {
		nslog(@"前回保存した時と同じなので回避");
		fsave=NO; // saveが呼び出された
		return;
	}
	if (self.lineArray!=nil) {
		nslog(@"lineArray=%d",(int)[self.lineArray count]);
		NSString *path=makeFullPathForSaveData(TEGAKIFILE);
		nslog(@"手書きファイル=%@",path);
		[[NSFileManager defaultManager]createFileAtPath:path contents:nil attributes:nil]; // ファイル新規作成(古いのは消す)
		id fp=[NSFileHandle fileHandleForWritingAtPath:path];
		nslog(@"fp=%@",fp);
		#ifdef DEBUG
		NSInteger i=0;
		#endif
		LINES line1;
		NSValue *val;
		NSEnumerator *emu=[self.lineArray objectEnumerator];
		while (val=[emu nextObject]) { // 一番最初はデータがないので描画されない
			// 1行ごと構造体に読みなおして書きだす
			[val getValue:&line1];
			NSData *data = [NSData dataWithBytes:&line1 length:SZ_LINES];
			[fp writeData:data];
			#ifdef DEBUG
			i++;
			#endif
		}
		nslog(@"データ数=%d",(int)i);
		[fp closeFile];
		savePoint=[self.lineArray count]; // save位置保存
		fsave=NO; // saveが呼び出された
	} // if (lineArray)
}

#if 0
-(void)saveOnce
{
	if (!fsave) {
		fsave=YES; // 以下NOになるまで=save終了まで、saveは回避
		// 一定時間後に自動保存
		[self performSelector:@selector(save) withObject:nil afterDelay:10.0];
	}
}
#endif

//-------------------------------------------------------------------
// タッチ処理
//-------------------------------------------------------------------
// マルチタッチの処理
//	(1)正確に同時にタッチしないと[touches count]>=2にはならない
//	(2)多くの場合、Beginが[touches count]=1で連続で発生する。Begin->普通処理,Begin->シングル連続となる
//  (3)count=1*複数回の場合、moveしたときにも、その座標が連続で返ってくる(指の特定はできない)
//  (4)count>=2の場合も返ってくる座標は複数で、どの指の座標かは特定できない

// Tegakiのそれのオーバーライド
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
	printSelf();
	nslog(@"(Scroll):multiTouch=%d/count=%d",(int)multiTouch,(int)[touches count]);

	if (!_fEnableTouch) {
		nslog(@"Begin禁止");
		return;
	}
	
	NSInteger cnt=[touches count];
	if (cnt>=2) { // ダブル(以上)タッチ
		nslog(@"スクロールモード開始(ダブルタッチ)");
		// ここでは座標の保存は必要ない
		multiTouch=1; // 2にすると、指を一度に離したときに残ってしまうのでダメ
		goto TM2;
	}

	// 以下はシングルタッチ
	if (++multiTouch>=2) {
		// Beginが連続(>=2)発生
		nslog(@"スクロールモード開始(シングル連続):multiTouch=%d",(int)multiTouch);
	TM2:;
		if (fScrollMode==SCRL_NONE) { // 前回スクロール直後でないとき
			// 画面取得
			[super performSelectorInBackground:@selector(imageSnapShot) withObject:nil];
			// ↑snapShotを並行動作処理；操作上劇的に高速化される
		}
		self.hidden=YES; // UIViewを消す
		fScrollMode=SCRL_NOW; // スクロールモード開始
		[delegateScroll hiddenScrollSymbol:NO]; // スクロールシンボルの表示
		return;
	}

	fScrollMode=SCRL_NONE;

	CGPoint point=[super getTouchPoint:touches]; // タッチ座標の取得
	if ([delegateScroll checkScrollArea:point fscroll:NO]) {
		// スクロールエリア内では描画しない
		// マルチタッチ判定の１つ目がスクロールエリア内
		nslog(@"Begin skip");
		return;
	}
	//
	// それ以外の時の処理はオリジナルに任せる
	fBegin=BIT_BEGIN;
	[super touchesBegan:touches withEvent:event];
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
//	printSelf();

	if (!_fEnableTouch) {
		nslog(@"Moved禁止");
		return;
	}
	if (fScrollMode!=SCRL_NONE) {
		nslog(@"スクロールモード中");
		if (fScrollMode==SCRL_DONE) {
			// スクロールシンボルの表示;ダブルタッチで手を離した後シンボルが消えてしまうので、まだスクロールモードが継続しているときはここで再起動する
			nslog(@"スクロールモード復活");
			[delegateScroll hiddenScrollSymbol:NO];
			self.hidden=YES; // UIViewを消す
		}
		NSArray *touchesArray=[touches allObjects]; // 返ってきている全座標を得る
		CGFloat dx=0,dy=0;	 // 実差分(符号付き)
		for (NSInteger i=0;i<[touchesArray count];i++) {
			// 座標差分は表示でも内部でも同じなので変換しない
			UITouch *touch=touchesArray[i];
			CGPoint p1=[touch previousLocationInView:self]; // 直前座標
			CGPoint p2=[touch locationInView:self]; // 現在座標
			CGFloat dx0=(p1.x-p2.x); // 距離差x1
			CGFloat dy0=(p1.y-p2.y); // 距離差y1
			if (fabs(dx0)>fabs(dx)) dx=dx0;
			if (fabs(dy0)>fabs(dy)) dy=dy0;
		}
		[delegateScroll scrollMove:dx dy:dy];
		multiTouch=0;
		return;
	}
	// ↑ここまではBeginから共通状態

	if (fBegin==BIT_NOBEGIN) {
		// Beginしていないでここに来た時＝Beginがスクロールエリア内だった/描画エリア外だった時は、最初のMovedをBeginとみなす
		nslog(@"Move->Begin");
		[self touchesBegan:touches withEvent:event];
		return;
	}

	// ここで消してしまうとcnt=1でここに来た後にダブルになる状況が判定できない
//	multiTouch=0;

	CGPoint point=[super getTouchPoint:touches]; // タッチ座標の取得
	if ([delegateScroll checkScrollArea:point fscroll:NO]) {
		// スクロールエリア内では描画しない
		nslog(@"Move skip");
		return;
	}
	
	// それ以外の時の処理はオリジナルに任せる
	fBegin|=BIT_MOVED;
	[super touchesMoved:touches withEvent:event];
}

-(void)endOfScrollMode
{
	printSelfs(@"multiTouch=%d",(int)multiTouch);
	fScrollMode=SCRL_DONE;  // スクロール終了直後
	[self setNeedsDisplay]; // 現在エリア画面を再表示
	self.hidden=NO; // UIViewを表示
	[delegateScroll hiddenScrollSymbol:YES]; // スクロールシンボルの消去
}

// Tegakiのそれのオーバーライド
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
	printSelf();

	multiTouch=0;

	if (!_fEnableTouch) {
		nslog(@"Ended禁止");
		return;
	}
	if (fScrollMode!=SCRL_NONE) {
		nslog(@"スクロールモード終了(Ended)");
		[self endOfScrollMode];
		return;
	}
	// ↑ここまではBeginから共通状態

	// スクロールエリア内で実際にスクロールするのはEndedのみ
	CGPoint point=[super getTouchPoint:touches]; // タッチ座標の取得
	if ([delegateScroll checkScrollArea:point fscroll:YES]) {
		// スクロールするとき
		if (fBegin&BIT_MOVED) {
			// begin->moved->の後ここに来た
			[super touchesLatestEnd]; // 先の最終データ(moved)をendedに書き換える
		}
		else
		if (fBegin&BIT_BEGIN) {
			// begin->endedのときは全部消してしまう
			[super undo:nil]; // beginまで消す
		}
		fBegin=BIT_NOBEGIN;
		return;
	}
	// BeginもMovedもskipしてここに来ることもある
	if (fBegin==BIT_NOBEGIN) return; // その時は座標を記録せず終了

	// それ以外の時の処理はオリジナルに任せる
	self.hidden=NO; // UIViewを表示
	fBegin=BIT_NOBEGIN;
	[super touchesEnded:touches withEvent:event];
#if 0	// これを入れると、その処理中の手書きが抜けるので中止
	// 一定時間後に画面取得
	[super performSelector:@selector(imageSnapShot) withObject:nil afterDelay:3.0];
#endif
//	[self saveOnce]; // 一定時間後に自動保存
}

// Tegakiのそれのオーバーライド
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
	printSelf();

	// マルチタッチの途中でなぜかCancelが発生するので、ここでマルチタッチ判定をここで終了してはいけない
	// しかし、Cancel発生後はタッチそのものが発生しなくなるのでマルチタッチは継続できない
	
	// タッチ後にzoom動作に移行するとBegin→(Moved→)Cancelとなる
	if (!_fEnableTouch) {
		nslog(@"Cancel禁止");
		return;
	}
	if (fScrollMode!=SCRL_NONE) {
		nslog(@"スクロールモード終了(Cancel)");
		[self endOfScrollMode];
		return;
	}
	// ↑ここまではBeginから共通状態
	fBegin=BIT_NOBEGIN;
	[super touchesCancelled:touches withEvent:event]; // beginまで消す
}

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

// Tegakiのそれのオーバーライド
-(void)undo:(id)sender
{
	printSelf();
	[super undo:sender]; // ストロークから全再描画
	savePoint=-1; // undo後は常に保存
#ifdef UNDO_SCROLL
	// 最後のみスクロール対象とする(高速化のため)
	[delegateScroll checkLineArea:lines.point];
#endif
//	[self saveOnce]; // 一定時間後に自動保存
}

// Tegakiのそれのオーバーライド
-(void)clearPage1
{
	printSelf();
	NSString *path=makeFullPathForSaveData(TEGAKIFILE);
	nslog(@"手書きファイル=%@",path);
	[[NSFileManager defaultManager]removeItemAtPath:path error:nil]; // ファイル削除
	[super clearPage1];
}

@end
