//----------------------------------------------------------------------------------------------
//
//	Console+animation.m : 描画用コンソールのアニメーション拡張部分
//  X-BASIC'
//
//  Created by AIG-Soft(iMac) on 2013/05/21.
//  Copyright (c) 2013年 AIG-Soft. All rights reserved.
//

#import "Console+animation.h"

@implementation Console (animation)

//----------------------------------------------------------------------------------------------
// レイヤーアニメーション(V2.1)
//----------------------------------------------------------------------------------------------

-(void)animeMainThread
// アニメ用スレッド(メインスレッド)
// fanime
{
	@autoreleasepool { // 別スレッドのお約束
	nslog(@"animeMainThread:%d",fanime_);
	[self animation:fanime_];
	}
}

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

#if nslog == NSLog
void print3D(CATransform3D d3)
{
	//	struct CATransform3D
	//	{
	//		CGFloat m11, m12, m13, m14;
	//		CGFloat m21, m22, m23, m24;
	//		CGFloat m31, m32, m33, m34;
	//		CGFloat m41, m42, m43, m44;
	//	};
	nslog(@"%f,%f,%f,%f",d3.m11,d3.m12,d3.m13,d3.m14);
	nslog(@"%f,%f,%f,%f",d3.m21,d3.m22,d3.m23,d3.m24);
	nslog(@"%f,%f,%f,%f",d3.m31,d3.m32,d3.m33,d3.m34);
	nslog(@"%f,%f,%f,%f",d3.m41,d3.m42,d3.m43,d3.m44);
}
#else
#define	print3D(d3)
#endif

#if nslog==NSLog
void printTransform(CGAffineTransform tr)
{
	//	struct CGAffineTransform
	//	{
	//		CGFloat  a, b
	//		CGFloat  c, d
	//		CGFloat tx,ty
	//	};
	nslog(@"%f,%f",tr.a ,tr.b );
	nslog(@"%f,%f",tr.c ,tr.d );
	nslog(@"%f,%f",tr.tx,tr.ty);
}
#else
#define	printTransform(tr)
#endif

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

-(void)setAnimeParameter1:(CFTimeInterval)duration_ repeatCount:(float)repeatCount_ autoreverses:(BOOL)autoreverses_ animationCurve:(int)animationCurve_
// アニメーション用共通情報設定
// アニメーションはKVOで起動するため、直接パラメーターが渡せないので
{
	nslog(@"setAnimeParameter1:%f,%f,%d,%d",duration_,repeatCount_,autoreverses_,animationCurve_);
	duration		=duration_;
	repeatCount		=repeatCount_;
	autoreverses	=autoreverses_;
	animationCurve	=animationCurve_;
}

-(void)setAnimeParameter2:(CGFloat)tx ty:(CGFloat)ty scaleX:(CGFloat)scaleX_ scaleY:(CGFloat)scaleY_ angle:(CGFloat)angle_ axis:(int)axis_
// 水平移動、拡大縮小、軸回転
{
	//												pi
	//	ベース		TRANSLATION		SCALE			ROTATION-X	  ROTATION-Y	ROTATION-Z
	//	1, 0,0,0	 1, 0,0,0		0.5,   0,0,0	1, 0,  0,0	*-1, 0,  0,0	*-1, 0,0,0
	//	0,-1,0,0	 0,-1,0,0		  0,-0.5,0,0	0,-1,  0,0	  0,*1,  0,0	  0,-1,0,0
	//	0, 0,1,0	 0, 0,1,0		  0,   0,1,0	0, 0,*-1,0	  0, 0,*-1,0	  0, 0,1,0
	//	0, 0,0,1	tx,ty,0,1		  0,   0,0,1	0, 0,  0,1	  0, 0,  0,1	  0, 0,0,1
	//
	//												1,   0,   0,0	cos,0,-sin,0	 cos,sin,0,0
	//												0, cos, sin,0	  0,1,   0,0	-sin,cos,0,0
	//												0,-sin, cos,0	sin,0, cos,0	   0,  0,1,0
	//												0,   0,   0,1	  0,0,   0,1	   0,  0,0,1
	printSelf();
	matrix=CATransform3DMakeAffineTransform(baseAffineWithTrans);			// まずは現在の変形を元にする
	matrix.m41=tx;			// 水平移動
	matrix.m42=ty;
	matrix.m11*=scaleX_;	// 倍率
	matrix.m22*=scaleY_;
	switch (axis_) {		// 軸回転
		case AXIS_X:
			matrix.m22*= cos(angle_);
			matrix.m23 = sin(angle_);
			matrix.m32 =-sin(angle_);
			matrix.m33 = cos(angle_);
			break;
		case AXIS_Y:
			matrix.m11*= cos(angle_);
			matrix.m13 =-sin(angle_);
			matrix.m31 = sin(angle_);
			matrix.m33 = cos(angle_);
			break;
		case AXIS_Z:
			matrix.m11*= cos(angle_);
			matrix.m12 = sin(angle_);
			matrix.m21 =-sin(angle_);
			matrix.m22*= cos(angle_);
		case AXIS_NONE:
			break;
	}
	print3D(matrix);
}

-(void)setAnimeParameter3:(CATransform3D)matrix_
// 変形情報(総合)
{
	printSelf();
	matrix=matrix_;
	// 鏡像変換対応のため
	matrix.m21=-matrix.m21;
	matrix.m22=-matrix.m22;
	matrix.m23=-matrix.m23;
	print3D(matrix);
}

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

-(void)transformCancel
{
	printSelf();
	// 変形をキャンセル
	baseAffineWithTrans=baseAffine;
	[self.layer setAffineTransform:baseAffine];
	
	// 再表示(これがないと、即時表示反映されない)
	[self update];
}

-(void)transform:(CGFloat)tx ty:(CGFloat)ty scaleX:(CGFloat)scaleX_ scaleY:(CGFloat)scaleY_ angle:(CGFloat)angle_
{
	nslog(@"gTransform:tx=%f,ty=%f,scaleX=%f,scaleY=%f,angle=%f",tx,ty,scaleX_,scaleY_,angle_);
	// 変形設定：アニメーション時はこれが基準となる
	// CGAffineTransform
	// a ,b ,0	x'=ax   ,y'=dy			拡大縮小
	// c ,d ,0	x'=ax+cy,y'=bx+dy		回転		a=cos,b=sin,c=-sin,d=cos
	// tx,ty,1	x'= x+tx,y'= y+ty		平行移動
	//			x'=-x					鏡像
	//			x'=-(ax+cy),y'=bx+dy	回転＋鏡像変換	(a*=-1,c*=-1)	←これがベース
//	CGAffineTransform m={-1*cos(M_PI),sin(M_PI),-1*-sin(M_PI),cos(M_PI),0,0};
//						{-1*-1,0,-1*0,-1,0,0}; // sin/cosを計算するとこうなる
//						{1,0,0,-1,0,0}
	// 変形上の注意
	// layerの変形は画面全体の変形である。
	// 拡大縮小時は全体が拡大すると同時に、実表示画面が拡大した仮想画面の中央になるよう設定される。
	// したがって、平行移動をかけないと見かけ上のホーム座標もずれる
	// 回転時も同様。
	// 回転方向は反時計回り(通常の角度計測と同じ)
	
	CGAffineTransform m;
	// 基本回転
	// 通常回転は+x軸を中心に反時計回りに行われるが、X-BASIC上では鏡像変換がなされているため、
	// -x軸から時計回りに行われる。ゆえに変換を行う
	angle_=-angle_;
	m.a= cos(angle_);
	m.b= sin(angle_);
	m.c=-sin(angle_);
	m.d= cos(angle_);
	// 鏡像変換
	m.c=-m.c;
	m.d=-m.d;
	//
	m.a*=scaleX_;
	m.d*=scaleY_;
	m.tx=tx;
	m.ty=ty;
	printTransform(m);
	
	baseAffineWithTrans=m;
	[self.layer setAffineTransform:baseAffineWithTrans];
	
	// 再表示(これがないと、即時表示反映されない)
	[self update];
}

-(void)transformReset
// baseAffineWithTransで再設定
{
	[self.layer setAffineTransform:baseAffineWithTrans];
	
	// 再表示(これがないと、即時表示反映されない)
	[self update];
}

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

-(void)animation:(int)mode
{
	nslog(@"animation:%d",mode);
	//
	UIViewAnimationTransition transition;
	switch (mode) {
		// UIViewアニメーション
		case ANIMATION_FLIPFROMLEFT:
			nslog(@"ANIMATION_FLIPFROMLEFT");
			transition=UIViewAnimationTransitionFlipFromLeft;
			goto ANIMATION_UI;
		case ANIMATION_FLIPFROMRIGHT:
			nslog(@"ANIMATION_FLIPFROMRIGHT");
			transition=UIViewAnimationTransitionFlipFromRight;
			goto ANIMATION_UI;
		case ANIMATION_CURLUP:
			nslog(@"ANIMATION_CURLUP");
			transition=	UIViewAnimationTransitionCurlUp;
			goto ANIMATION_UI;
		case ANIMATION_CURLDOWN:
			transition=UIViewAnimationTransitionCurlDown;
			nslog(@"ANIMATION_CURLDOWN");
		ANIMATION_UI:
			// UIViewアニメーションの設定開始
			[UIView beginAnimations:@"transition" context:context];
			[UIView setAnimationRepeatCount:repeatCount];
			[UIView setAnimationRepeatAutoreverses:autoreverses];
			[UIView setAnimationDuration:duration];
			[UIView setAnimationCurve:animationCurve];

			// トランジションアニメーションの設定
			[UIView setAnimationTransition:transition forView:self cache:YES];
			
			// ビューの変更
			// UIViewの終了処理をここに書くのが普通
			
			// UIViewアニメーションの実行
			[UIView commitAnimations];
			break;
		
		// layerアニメーション
		case ANIMATION_STOP:// animation stop
			nslog(@"ANIMATION_STOP");
			// レイヤーレイヤーアニメーションの全削除
			[self.layer removeAllAnimations];
			return;
			
		case ANIMATION_LAYER:
		{
			// アニメーションの設定
			CABasicAnimation *anime=[CABasicAnimation animationWithKeyPath:@"transform"]; // ここのkey名は変更してはいけない
			// animationWithKeyPath:はCAPropertyAnimationのメソッド
			anime.duration		= duration;		// 変化時間
			anime.repeatCount	= repeatCount;	// 繰り返し回数
			anime.autoreverses	= autoreverses;	// リバース
			
			// consoleの鏡像回転を考慮した上での基準指定
			// consoleにはstartで鏡像変換がかけられているので、それに追加されることを考慮しなければならない
			anime.fromValue	= [NSValue valueWithCATransform3D:CATransform3DMakeAffineTransform(baseAffineWithTrans)];
			//
			// 終点指定
			anime.toValue   = [NSValue valueWithCATransform3D:matrix];
			
			// レイヤーアニメーションの追加＝実行
			[self.layer addAnimation:anime forKey:@"animation"]; // keyを変えても重複設定はできない
		}
			break;
	}
	// アニメーションによるレイヤーの変形は、アニメーション終了時に自動的に解除される。
	// toValueが変形結果で、fromValueが基本形
	
	// ここは[self update]は不要。というか付けるとうまくいかない。
}

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

@end
