//
//  RotationViewController.m
//	表示用
//  ChariReco
//
//  Created by AIG-Soft 2011/06/22
//  Copyright 2011 AIG-Soft. All rights reserved.
//

#import "RotationViewController.h"
#import "click.h"
#import "libs.h"
#import "FileControl2.h"
#import "main.h"
#include <math.h>
#include "UIScreen+is568screen.h"
#import "HelpViewController.h"

@interface RotationViewController()
<HelpViewControllerDelegate>
{
	NSArray __strong	*btnXYZ;
}
@end

@implementation RotationViewController

//------------------------------------------------------------------------------
// View
//------------------------------------------------------------------------------

- (void)viewDidLoad
{
	printSelf();
	clickStop(); // 以下の要素操作でクリック音がならないようにするため
	
	[super viewDidLoad];

	// 軸設定
	[self setXGrid];
	graphViewAxisGrid = [self allocAndSetBasicsData:YES alpha:1.0 fpeek:NO ]; // 本来こちらは軸描画のためにあるので上記設定は本末転倒
	nslog(@"graphViewAxisGrid=%p",graphViewAxisGrid);
	
	// グラフ設定
	graphView		  = [self allocAndSetBasicsData:NO  alpha:0.8 fpeek:YES]; // 軸をわずかに透過する/peakを表示するのはグラフ側
	nslog(@"graphView=%p",graphView);
	
	[self setAxisGrid];
	
	// 表示要素はload後しか設定できない
	
	// 文字色を軸色と同じにする
	xLabel.textColor=colorByIndex(0); // copyされる
	[btnX setTitleColor:xLabel.textColor forState:UIControlStateNormal];
	
	yLabel.textColor=colorByIndex(1); // copyされる
	[btnY setTitleColor:yLabel.textColor forState:UIControlStateNormal];
	
	zLabel.textColor=colorByIndex(2); // copyされる
	[btnZ setTitleColor:zLabel.textColor forState:UIControlStateNormal];
	// 軸ボタン配列
	btnXYZ=@[btnX,btnY,btnZ];
	nslog(@"btnXYZ=%@",btnXYZ);
	//
	// しきい値覧表示の初期化
	[self setDispLblPeakThres:DISP_LblPeakThres_None];
	
	// ボタンなどのローカライズ
	[SegSelectData removeAllSegments];
	[SegSelectData insertSegmentWithTitle:NSLocalStr(@"DEGREE2"  ) atIndex:DATA_DEGREE   animated:NO];
	[SegSelectData insertSegmentWithTitle:NSLocalStr(@"VELOCITY2") atIndex:DATA_VELOCITY animated:NO];
	[SegSelectData insertSegmentWithTitle:NSLocalStr(@"ROTATION2") atIndex:DATA_ROTATION animated:NO];
	SegSelectData.selectedSegmentIndex=_rotationControl.dno;
	[self setDataName:SegSelectData.selectedSegmentIndex];
	[btnALL		 setTitle:NSLocalizedString(@"BTN_ALL"	,@"全て")	forState:UIControlStateNormal];
	[btnSet		 setTitle:NSLocalizedString(@"BTN_SET"	,@"設定")	forState:UIControlStateNormal];
	[btnInit	 setTitle:NSLocalizedString(@"BTN_INIT"	,@"初期化")	forState:UIControlStateNormal];
	LblSelectData.text	 =NSLocalizedString(@"DATASOUCE",@"データ源");
	LblSwPause.text		 =NSLocalizedString(@"PAUSE"	,@"一時停止");
	swPause.on=NO;
	
	// アラームシンボルの設定；imgAlarmの表示要素のため、それが確定した後に設定すること
	alarmSymbol =[[LimitedSymbol alloc]initWithImageView:imgAlarm];
	nslog(@"alarmSymbol=%@",alarmSymbol);
	
	// 初期化用アクションシートを初期化しておく
	asheet=[[UIActionSheet alloc]
			initWithTitle:NSLocalStr(@"PEAKINIT")
			delegate:self
			cancelButtonTitle:NSLocalStr(@"CANCEL")	// ボタン番号=cancelButtonIndex
	  destructiveButtonTitle:nil
			otherButtonTitles:NSLocalizedString(@"GOINIT",@"初期化実行"),	// ボタン番号=firstOtherButtonIndex
			nil
			];
	setActionSheetResize(asheet); // リサイズ指定
	//
	//clickSound(); // ボタン押下時に鳴っているのでここでは不要
	clickResume();
}

-(void)viewWillAppear:(BOOL)animated
{
	printSelf();
	[super viewWillAppear:animated];
	self.navigationController.navigationBarHidden=YES; // ここは画面が足りないのでNaviを消す

	// 軸表示
	[forGraph addSubview:graphViewAxisGrid];
	// グラフ表示(後のほうが上に表示される)
	[forGraph addSubview:graphView];
	
	// 実際に表示されるのはサンプリングごとの処理時
	// サンプリング開始
	nslog(@"サンプリング開始？=%@",_rotationControl.opQueueMotion);
	if (_rotationControl.opQueueMotion==nil) {
		nslog(@"サンプリング開始!!");
		[_rotationControl startSampling]; // 初回だけ
	}
}

-(void)viewDidDisappear:(BOOL)animated
{
	printSelf();
	[super viewDidDisappear:animated];
	// データ保存
	// 今はここに入れておく
	[_rotationControl saveSettings:GRAPHFILE];
	
	// ヘルプ表示前も呼び出される
	// HOMEボタン押下時には呼び出されない
}

//-------------------------------------------------------------------
// 設定処理内でのしきい値超時の処理
//-------------------------------------------------------------------

-(void)alarm3DdetectionEnd:(id)sender
// アラームシンボル表示終了
{
	nslog(@"アラームシンボル表示終了");
}

-(void)alarm3Ddetection:(NSNotification *)notification
// アラーム発報シンボル表示
// ここは設定中の表示だけなので、Edge/Levelは関係ない
{
	nslog(@"しきい値超え");
	// アラームシンボルを表示
	[alarmSymbol display:TM_ALARM_DISPLAY target:self selector:@selector(alarm3DdetectionEnd:)];
	nslog(@"alarmSymbol表示完了");
}

//-------------------------------------------------------------------
// 初期化処理
//-------------------------------------------------------------------

// 初期化
-(id)initWithSampling:(NSUInteger)sampling selectData:(NSUInteger)selectData rotationControl:(RotationControl *)rotationControl
{
	printSelfs(@"sampling=%d",(int)sampling);
	self=[super init];
	if (self!=nil) {
		nslog(@"rotationControl=%@",rotationControl);
		self.rotationControl=rotationControl;
		[_rotationControl initialize:sampling];
				// しきい値は初期化される
				// dataSourceは_rotationControlに初期設定される
		_rotationControl.dataSource=self; // ので、ここに設定
		// 
		[self graphAllOnOff:YES]; // グラフはすべて表示
		
		// 初期化
		_rotationControl.dno=selectData;	// 初期表示データ
		_rotationControl.gno=GRAPH_ALL;		// 全軸表示
		[self resetThreshold];
		[_rotationControl readSettings:GRAPHFILE];	// ファイルから設定済みしきい値設定を読み込む
		[_rotationControl resetPeakHold];			// Peakは毎回初期化

		// アラーム発報通知先を設定
		[_rotationControl setAlarm3DNortification:self selector:@selector(alarm3Ddetection:)];
	}
	return(self);
}


-(void)close
{
	if ([self.delegate respondsToSelector:@selector(AtRotationViewControllerClose:)]) {
		[self.delegate performSelector:@selector(AtRotationViewControllerClose:) withObject:self];
	}
	clickSound(); // クリック音
	self.navigationController.navigationBarHidden=NO; // Naviを戻す
	[self.navigationController popViewControllerAnimated:YES];
}

// 全軸グラフ描画のon/off
-(BOOL)graphAllOnOff:(BOOL)onoff
{
	BOOL f=NO;
	for (NSUInteger i=GRAPH_X;i<=GRAPH_Z;i++) {
		if (onoff==YES) { // 全ONにするとき
			if (fGraph[i]==NO) f=YES; // OFF→ONの変更があった
		}
		fGraph[i]=onoff;
	}
	// OFF→ONの変更があったかどうか
	return (f);
}

//-------------------------------------------------------------------
// 再初期化処理
//-------------------------------------------------------------------

// しきい値の初期化
-(void)resetThreshold
{
	[_rotationControl resetThreshold]; // 値の初期化
	[alarmSymbol erase:self]; // しきい値が変わるのでアラーム表示も消す（しきい値を超えているかどうかわからなくなるため）
}

//-------------------------------------------------------------------
// データ表示制御
//-------------------------------------------------------------------

// Peak/Threshold表示領域への表示制御
-(void)dispLblPeakThres:(NSString *)numstr gno:(NSUInteger)no result:(NSUInteger)result
{
	switch (fdispLblPeakThres) {
		default: // 警告回避のため
		case DISP_LblPeakThres_Axis: // 軸図表示
		case DISP_LblPeakThres_None: // 表示されてないとき
			// 何もしない
			break;
		case DISP_LblPeakThres_Threshold: // しきい値表示
			// しきい値は、設定時の１値表示か、表示切替時の全値表示である
		case DISP_LblPeakThres_Peak: // Peak値
			// Peak値は基本リアルタイムの１要素表示である
			switch (result) {
			//	case THRES1:
				case CHANGE_MAX:// 最大値(Peak)/しきい値1
					switch (no) {
						case GRAPH_X:LblPeakThresX1.text=numstr; break;
						case GRAPH_Y:LblPeakThresY1.text=numstr; break;
						case GRAPH_Z:LblPeakThresZ1.text=numstr; break;
					}
					break;
			//	case THRES2:
				case CHANGE_MIN:// 最小値(Peak)/しきい値2
					switch (no) {
						case GRAPH_X:LblPeakThresX2.text=numstr; break;
						case GRAPH_Y:LblPeakThresY2.text=numstr; break;
						case GRAPH_Z:LblPeakThresZ2.text=numstr; break;
					}
					break;
			}
			break;
	}
}

-(void)setDispLblPeakThres
// Peak/Threshold表示領域への表示制御:切り替えに伴う初期表示
{
	printSelfs(@"%d",(int)fdispLblPeakThres);
	
	// switch内で宣言できないので
	NSUInteger no;
	NSString *numstr;
	GRAPH_SPECIFICATIONS *spc;
	// 軸別色設定
	LblPeakThresX.textColor	=
	LblPeakThresX1.textColor=
	LblPeakThresX2.textColor=colorByIndex(GRAPH_X);
	LblPeakThresY.textColor	=
	LblPeakThresY1.textColor=
	LblPeakThresY2.textColor=colorByIndex(GRAPH_Y);
	LblPeakThresZ.textColor	=
	LblPeakThresZ1.textColor=
	LblPeakThresZ2.textColor=colorByIndex(GRAPH_Z);
	//
	switch (fdispLblPeakThres) {
		default: // 警告回避のため
		case DISP_LblPeakThres_Axis: // 軸図表示
			nslog(@"DISP_LblPeakThres_Axis");
			imgAxis.hidden=NO;
			forPeakThres.hidden=YES;
			return;
		case DISP_LblPeakThres_None: // 表示されない
			nslog(@"DISP_LblPeakThres_None");
			imgAxis.hidden=YES;
			forPeakThres.hidden=YES; // 全ての表示を消す
			return;
		//
		case DISP_LblPeakThres_Threshold: // しきい値表示
			nslog(@"DISP_LblPeakThres_Threshold");
			LblPeakThresName.text=NSLocalizedString(@"THRESHOLD",@"しきい値"); // タイトル
			for (no=GRAPH_X;no<=GRAPH_Z;no++) {
				spc=[_rotationControl specDnoGno:no];
				if (spc->fthreshold1) {
					numstr=[_rotationControl float2String:spc->threshold1];
				} else {
					numstr=NSLocalStr(@"NONE");
				}
				[self dispLblPeakThres:numstr gno:no result:THRES1];
				//
				if (spc->fthreshold2) {
					numstr=[_rotationControl float2String:spc->threshold2];
				} else {
					numstr=NSLocalStr(@"NONE");
				}
				[self dispLblPeakThres:numstr gno:no result:THRES2];
			}
			break;
		case DISP_LblPeakThres_Peak: // Peak値
			nslog(@"DISP_LblPeakThres_Peak");
			LblPeakThresName.text=NSLocalizedString(@"PEAK",@"生Peak値"); // タイトル	
			for (no=GRAPH_X;no<=GRAPH_Z;no++) {
				spc=[_rotationControl specDnoGno:no];
				if (spc->truePeakMax==DEF_TRUE_PEAK_MAX) {
					// 未設定時
					numstr=NSLocalStr(@"NONE");
				} else {
					numstr=[_rotationControl float2String:spc->truePeakMax];
				}
				[self dispLblPeakThres:numstr gno:no result:CHANGE_MAX];
				//
				if (spc->truePeakMin==DEF_TRUE_PEAK_MIN) {
					// 未設定時
					numstr=NSLocalStr(@"NONE");
				} else {
					numstr=[_rotationControl float2String:spc->truePeakMin];
				}
				[self dispLblPeakThres:numstr gno:no result:CHANGE_MIN];
			}
			break;
	}
	imgAxis.hidden=YES;
	forPeakThres.hidden=NO; // 表示
}

-(void)setDispLblPeakThres:(NSUInteger)fdispLblPeakThres_
{
	fdispLblPeakThres=fdispLblPeakThres_;
	[self setDispLblPeakThres];
}

//-------------------------------------------------------------------
// データ制御:RotationControlのdelegate
//-------------------------------------------------------------------

// １軸データの表示&Peak判定
-(BOOL)storeData1:(float)f gno:(NSUInteger)no label:(UILabel *)label
{
	NSUInteger result;
	BOOL falarm=[_rotationControl checkData1:&f gno:no checkResult:&result];
	NSString *numstr=[_rotationControl float2String:f];
//	nslog(@"storeData1:f=%f(%@)",f,numstr);
	if (fdispLblPeakThres==DISP_LblPeakThres_Peak) {
		[self dispLblPeakThres:numstr gno:no result:result];
	}
	label.text=numstr;
	return (falarm);
}

// データ表示＆格納
-(void)rotationControlStoreData:(CMRotationRate *)xyz
{
//	printSelf();
	// データの表示&Peak判定
	// ここは表示なので３軸とも常に必要
	BOOL falarm =[self storeData1:xyz->x gno:GRAPH_X label:xData];
		 falarm|=[self storeData1:xyz->y gno:GRAPH_Y label:yData];
		 falarm|=[self storeData1:xyz->z gno:GRAPH_Z label:zData];
	[_rotationControl triggerAlarm3D:falarm];
	// グラフデータ追加
	if ([_rotationControl addData:(CMRotationRate *)xyz]) {
		[graphView setNeedsDisplay]; // 再描画指示(グラフのみ)
#if 0	// ここでこの処理をすると描画前にデータが消えてしまう。そのため描画終了時処理に回す
		[_rotationControl eraseData];
#endif
	}
	// samples>datasPerSecの間＝グラフ描画終了までに来たデータは破棄する
}

//-------------------------------------------------------------------
// set*
//-------------------------------------------------------------------

-(void)setDataName:(NSUInteger)no
{
	switch (no) {
		case DATA_DEGREE:
			lblName.text=NSLocalStr(@"DEGREE");
			break;
		case DATA_VELOCITY:
			lblName.text=NSLocalStr(@"VELOCITY");
			break;
		case DATA_ROTATION:
			lblName.text=NSLocalStr(@"ROTATION");
		default:
			break;
	}
}

// グラフのx軸の数値設定
// グラフのx軸は単なる時間なので全ての軸／データ源で共通
-(void)setXGrid
{
	printSelf();
	gxArray = [[NSMutableArray alloc] init];
	for ( NSUInteger i = 0 ; i < _rotationControl.datasPerSec ; i ++ ) {
		[gxArray addObject:@(i)];
	}
}

// 軸の描画
-(void)setAxisGrid
{
	graphViewAxisGrid.ycount=[_rotationControl getYcount];
	float max=[_rotationControl getMaxY];
	float min=[_rotationControl getMinY];
	[graphViewAxisGrid calcAxisGrid:min maxYValue:max];
	[graphView		   calcAxisGrid:min maxYValue:max];
	[graphViewAxisGrid setNeedsDisplay];
	//これを入れると軸切替時にグラフが欠けてしまう
//	[graphView		   setNeedsDisplay];
}

// 基本データ設定
-(S7GraphView *)allocAndSetBasicsData:(BOOL)fAxis alpha:(CGFloat)alpha fpeek:(BOOL)fpeek
{
	printSelf();
	nslog(@"forGraph.frame=%f,%f〜%f,%f",forGraph.frame.origin.x,forGraph.frame.origin.y,forGraph.frame.size.width,forGraph.frame.size.height);
	CGRect frameForGraph=forGraph.frame; // 表示後しか取得できない
	///
	if ([UIScreen is568screen]) {
		nslog(@"568画面でグラフを広げる");
		CGRect frame=frameForGraph;
		frame.size.height*=(568.0/480.0);
		frameForGraph=frame;
	}

	// originは親ビュー内でのforGraphの開始位置を持っているが、グラフに対してはこれを視点とする
	frameForGraph.origin.x=0.0;
	frameForGraph.origin.y=0.0;
	
	S7GraphView *graph = [[S7GraphView alloc] initWithFrame:frameForGraph];
	graph.dataSource = self;
	graph.backgroundColor = [UIColor clearColor/*whiteColor*/];
	graph.drawAxisX =			// 軸
	graph.drawAxisY = 
	graph.drawGridX =			// 格子
	graph.drawGridY = fAxis;
	graph.alpha		= alpha;	// 透過率
	graph.fpeak		= fpeek;	// peakを表示するのはグラフ側（念のため）
	
	return (graph);
}

//-------------------------------------------------------------------
// ActionSheet（確認用）
//-------------------------------------------------------------------

// アクションシートのボタンが押された
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
	// 押されたボタンの保存
	if (buttonIndex==actionSheet.cancelButtonIndex) {
		nslog(@"キャンセル");
		// キャンセル時は音は出さない
	} else {
		nslog(@"初期化実行");
		[_rotationControl resetPeakHold];	// PeakHoldも初期化
		[self resetThreshold];	// しきい値も初期化
		[self setDispLblPeakThres:DISP_LblPeakThres_None]; // Peak/しきい値表示も消す
		clickSound();
	}
}

// 初期化をアクションで確認する
-(void)checkInit
{
	[asheet showInView:self.view];
}

//-------------------------------------------------------------------
// HELP操作用
//-------------------------------------------------------------------

-(void)AtHelpViewClose:(id)sender
{
	printSelf();
	clickSound(); // クリック音
	// 一時停止状態を戻す
	swPause.on=_rotationControl.fpause;
}

//-------------------------------------------------------------------
// 操作イベント
//-------------------------------------------------------------------

// 一時停止
-(IBAction)updateSwitch:(UISwitch *)sw
{
	printSelfs(@".on=%d",sw.on);
	clickSound();
	// 今は一時停止のみ(swPause)
	if (sw.on) {
		// 一時停止
		SegSelectData.enabled=NO;	// データ源選択を禁止する
		// 軸選択時のグラフ再描画ため、データを1回前の描画分に戻しておく
		[_rotationControl eraseData]; // 一旦消す
		[_rotationControl copyBackupData]; // 内容のコピー
	} else {
		SegSelectData.enabled=YES; // 許可
	}
	_rotationControl.fpause=sw.on;
}

// データ源切り替え
-(IBAction)updateSegment:(UISegmentedControl *)seg
{
	printSelf();
	_rotationControl.dno=seg.selectedSegmentIndex;
	[self setDataName:seg.selectedSegmentIndex];
	// サンプリングやり直し(データが変わるから)
	[_rotationControl eraseData];
	[self setAxisGrid];
	// データ元が変わるので、アラーム判定も変わるのでシンボルも消す
	[alarmSymbol erase:self];
	// 再表示
	[self setDispLblPeakThres];
	//
	clickSound();
}

-(IBAction)updateButton:(UIButton *)btn
{
	printSelfs(@"tag=%d",(int)btn.tag);
	switch (btn.tag) {
		case BTN_SET:
			nslog(@"設定");
			clickStop(); // 設定中は止める
			_rotationControl.fpause=swPause.on;
			clickResume();
			[self close];
			return;
		//
		case BTN_RESET:
			clickStop(); // 設定中は止める
			_rotationControl.fpause=swPause.on;
			nslog(@"Peak/しきい値初期化");
			clickResume();
			clickSound(); // クリック音
			[self checkInit];
			return;
		//
		case BTN_HELP:
		{
			nslog(@"ヘルプ表示");
			clickStop();
			_rotationControl.fpause=swPause.on;
			swPause.on=YES; // サンプリングは一時停止する;ここでクリック音がなってしまうので、Stop〜Resumeしてる
			HelpViewController *helpViewController=[[HelpViewController alloc]init];
			[helpViewController open:@"HELP3D" title:@"HELP3DTITLE"];
			helpViewController.delegate=self;
			clickResume();
			clickSound(); // クリック音
			self.navigationController.navigationBarHidden=NO; // naviを表示
			[self.navigationController pushViewController:helpViewController animated:YES];
		}
			return;
		//
		case GRAPH_X:
		case GRAPH_Y:
		case GRAPH_Z:
			_rotationControl.gno=btn.tag; // グラフ番号
			nslog(@"軸選択=%d",(int)btn.tag);
			// 指定された軸以外はOFFにする
			[self graphAllOnOff:NO];
			fGraph[btn.tag]=YES;
			[self selectedButton:btn.tag];
			// 個別グラフの時はしきい値を表示する
			[self setDispLblPeakThres:DISP_LblPeakThres_Threshold];
			clickSound(); // クリック音
			break;
		case GRAPH_ALL:
			_rotationControl.gno=btn.tag; // グラフ番号
			nslog(@"全軸選択");
			if ([self graphAllOnOff:YES]==NO) { // fGraph[]設定
				// グラフの表示OFF→ON変化がないとき
				// 軸表示→しきい値表示→Peak表示→OFF
				if (++fdispLblPeakThres>DISP_LblPeakThres_Peak) fdispLblPeakThres=DISP_LblPeakThres_None;
				[self setDispLblPeakThres];
			} else {
				// 全グラフ表示に変更
				for (NSUInteger i=GRAPH_X;i<=GRAPH_Z;i++) {
					fGraph[i]=YES;
				}
			}
			[self selectedButton:btn.tag];
			clickSound(); // クリック音
			break;
	}
	// GRAPH系の共通後処理
	[self setAxisGrid];
	[self reDispThresholdLine];
	xData.hidden=xLabel.hidden=(!fGraph[GRAPH_X]);
	yData.hidden=yLabel.hidden=(!fGraph[GRAPH_Y]);
	zData.hidden=zLabel.hidden=(!fGraph[GRAPH_Z]);
	if (swPause.on) {
		// 一時停止中なら、対象軸だけの表示にするため、グラフを再描画する
		nslog(@"一時停止中グラフ再描画");
		[graphView setNeedsDisplay];
	}
}

// 選択されているボタンに枠を描く
// tag=全ボタンの時は全てから消える
-(void)selectedButton:(NSInteger)tag
{
	for (NSUInteger i=GRAPH_X;i<=GRAPH_Z;i++) {
		CALayer *layer=((UIButton *)(btnXYZ[i])).layer;
		layer.borderColor=[UIColor redColor].CGColor;
		if (i==tag) {
			layer.borderWidth=1;
		} else {
			layer.borderWidth=0; // 消す
		}
	}
}

//-------------------------------------------------------------------
// 表示制御
//-------------------------------------------------------------------

-(void)reDispThresholdLine
// しきい値軸のみ再表示
{
	printSelf();
	nslog(@"[%d][%d]",(int)_rotationControl.dno,(int)_rotationControl.gno);
	
	// しきい値ビューの表示制御
	BOOL fthres1Hidden,fthres2Hidden; // .hiddenのフラグ
	UIColor	*col;
	float thres1=0.0,thres2=0.0; // 0.0は警告回避のため
	if (_rotationControl.gno==GRAPH_ALL) {
		fthres1Hidden=fthres2Hidden=YES;
		// 念のため個別もOFF
		nslog(@"全グラフ時は表示しない");
		col=[UIColor clearColor]; // 念のため
	} else {
		// 各軸のとき
		GRAPH_SPECIFICATIONS *spc=[_rotationControl specDnoGno];
		fthres1Hidden=(!spc->fthreshold1);
		fthres2Hidden=(!spc->fthreshold2);
		thres1=spc->threshold1;
		thres2=spc->threshold2;
		col=colorByIndex(_rotationControl.gno);
	}
	// 各軸表示の時
	[graphViewAxisGrid setThreshold:thres1
							 value2:thres2
					  fValue1Hidden:fthres1Hidden
					  fValue2Hidden:fthres2Hidden
							  color:col
	 ];
	[graphViewAxisGrid setNeedsDisplay];
}

//-------------------------------------------------------------------
// 画面タッチイベント
//-------------------------------------------------------------------

-(CGPoint)checkTouchPoint:(NSSet *)touches
// タッチ座標からグラフ上座標を返す
{
	CGPoint point=[[touches anyObject]locationInView:self.view];
	return [graphViewAxisGrid checkPoint:point frame:forGraph.frame];
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
// 画面タッチ開始
{
	printSelfs(@"gno=%d",(int)_rotationControl.gno);
	fmoveThreshold=MOVE_THRESHOLD_NONE;
	if (_rotationControl.gno==GRAPH_ALL) {
		// 軸別表示でないときは操作できない
		nslog(@"軸別表示でない");
		return;
	}
	startPoint=[self checkTouchPoint:touches];
	if (startPoint.x<0.0) {
		// 画面外なので何もしない
		nslog(@"画面外");
		return;
	}
	// この近辺に閾値線があるときはそれを操作対象とする
	fmoveThreshold=MOVE_THRESHOLD_SET; // 設定開始
	float f=[graphViewAxisGrid calcPoint2Yvalue:startPoint frame:forGraph.frame];
	//nslog(@"値=%f",f);
	// 既存のどちらのしきい値線範囲にあるか
	BOOL fv1=NO,fv2=NO;
	GRAPH_SPECIFICATIONS *spc=[_rotationControl specDnoGno];
	if (spc->fthreshold1) { // (1)側が表示されているとき
		fv1=[graphViewAxisGrid checkThresholdArea:spc->threshold1 value:f];
	}
	if (spc->fthreshold2) { // (2)側が表示されているとき
		fv2=[graphViewAxisGrid checkThresholdArea:spc->threshold2 value:f];
	}
	// 
	if (fv1) { // (1)側を移動する
		printf("しきい値1移動開始");
		if (!fv2) {
			printf("((1)側範囲のみ)");
		} else {
			// (2)側も範囲に入っているとき
			// より近い方を操作する
			if (abs(spc->threshold1-f)>abs(spc->threshold2-f)) { // (2)側のほうがより近い
				printf("→しきい値2移動に変更\n");
				fmoveThreshold=MOVE_THRESHOLD2;
				return;
			}
			// (1)側のほうがより近い
			printf("((1)側のほうが近い)");
		}
		printf("\n");
		fmoveThreshold=MOVE_THRESHOLD1;
		return;
	}
	if (fv2) {
		printf("しきい値2移動開始");
		if (!fv1) {
			printf("((2)側範囲のみ)");
		} else {
			// (1)側も範囲に入っているとき
			// より近い方を操作する
			if (abs(spc->threshold2-f)>abs(spc->threshold1-f)) { // (1)側のほうがより近い
				printf("→しきい値1移動に変更\n");
				fmoveThreshold=MOVE_THRESHOLD1;
				return;
			}
			// (2)側のほうがより近い
			printf("((2)側のほうが近い)");
		}
		printf("\n");
		fmoveThreshold=MOVE_THRESHOLD2;
	}
	// 既存しきい値移動でないときはtouchesEndedで
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
// 画面タッチ終了
{
	printSelf();
	if (fmoveThreshold==MOVE_THRESHOLD_NONE) {
		nslog(@"画面外か複数軸表示");
		// 画面外か複数軸表示の時
		return;
	}
	// 此処に来るときは各軸表示である:gno=GRAPH_X〜Z
	clickSound();
	CGPoint point=[self checkTouchPoint:touches];
	GRAPH_SPECIFICATIONS *spc=[_rotationControl specDnoGno];
	if (point.x<0.0) {
		// グラフ範囲を越えるとき
		switch (fmoveThreshold) { // どこが動いているかはタッチ開始時に判定されている
			case MOVE_THRESHOLD1:
				// 既存のしきい値1を画面外にドラッグしたとき＝削除
				nslog(@"既存のしきい値1を画面外にドラッグした");
				spc->fthreshold1=NO; 
				break;
			case MOVE_THRESHOLD2:
				// 既存のしきい値2を画面外にドラッグしたとき＝削除
				nslog(@"既存のしきい値2を画面外にドラッグした");
				spc->fthreshold2=NO; 
				break;
			default:
				// 設定開始だったときは何もしない
				nslog(@"設定開始キャンセル");
				return;
		}
	} else {
		// 画面内移動または設定
		float f=[graphViewAxisGrid calcPoint2Yvalue:point frame:forGraph.frame]; // y数値にする
		//
		switch (fmoveThreshold) { // どこが動いているかはタッチ開始時に判定されている
			default:
				nslog(@"新規設定");
				if (spc->fthreshold1==NO) {
					// (1)側が空いているとき
					nslog(@"しきい値1に設定");
					spc->fthreshold1=YES;
					goto Value1Set;
				}
				if (spc->fthreshold2==NO) {
					// (2)側が空いているとき
					nslog(@"しきい値2に設定");
					spc->fthreshold2=YES;
					goto Value2Set;
				}
				nslog(@"(1)/(2)とも空いてない");
				if (abs(spc->threshold1-f)>abs(spc->threshold2-f)) { // (2)側のほうがより近い
					nslog(@"しきい値2のほうが近いので変更");
					goto Value2Set;
				}
				// (1)側のほうがより近い
				nslog(@"しきい値1のほうが近いので変更");
				goto Value1Set;
			case MOVE_THRESHOLD1:
				nslog(@"既存のしきい値1を変更");
			Value1Set:;
				spc->threshold1=f;
				// 再表示はreDispThresholdLineで行われる
				break;
			case MOVE_THRESHOLD2:
				nslog(@"既存のしきい値2を変更");
			Value2Set:;
				spc->threshold2=f;
				// 再表示はreDispThresholdLineで行われる
				break;
		}
	}
	// thresholdは軸側に描画する
	[self reDispThresholdLine];
	// 数値表示
	[self setDispLblPeakThres:DISP_LblPeakThres_Threshold];
}

#ifdef DEBUG
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
	nslog(@"画面タッチ中止");
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
// ドラッグ
{
	nslog(@"画面ドラッグ中");
//	CGPoint point=[self checkTouchPoint:touches];
	// 処理の都合上、ドラッグ中のしきい値線は描画できない
}
#endif

//-------------------------------------------------------------------
// 以下はS7GraphViewのデリゲート
//-------------------------------------------------------------------

#pragma mark -
#pragma mark S7GraphViewDataSource

- (NSUInteger)graphViewNumberOfPlots:(S7GraphView *)graphView_
// グラフ数
{	
	return (MAX_GRAPH);
}

- (NSMutableArray *)graphViewXValues:(S7GraphView *)graphView_
// x軸値
{
//	nslog(@"x軸数=%d",[gxArray count]);
	return gxArray;	
}

- (float)graphView:(S7GraphView *)graphView yValuesForPlot:(NSUInteger)plotIndex index:(NSUInteger)index;
{
	return [_rotationControl getDarray:index gno:plotIndex];
}

- (NSUInteger)graphView:(S7GraphView *)graphView yValuesCount:(NSUInteger)plotIndex;
// y軸値数
{
//	nslog(@"yValuesCount[%d]=%d",plotIndex,[_rotationControl getDarrayCount]);
	return [_rotationControl getDarrayCount]; // 今回は3軸同時なのですべて同数
}

-(void)graphViewEndOfPlots:(S7GraphView *)graphView_
// グラフ描画終了時処理
{
	// 一時停止中でない時にグラフ描画が終わったら、前のデータを消す
	if (graphView_==graphView) {
		if (!swPause.on) {
			[_rotationControl copyData]; // 描画したデータを保存しておく
			[_rotationControl eraseData];
		} // 一時停止中は再描画なのでデータを消してはいけない
	}
	// 軸の時は何もしない
}

-(BOOL)graphViewOnOff:(S7GraphView *)graphView_ gno:(NSUInteger)plotIndex
// 一時的なグラフ描画のON/OFF
{
	return (fGraph[plotIndex]);
}

- (float)graphViewPeakMax:(S7GraphView *)graphView gno:(NSUInteger)plotIndex
// max peak値を返す:データ別
{
	GRAPH_SPECIFICATIONS *spc=[_rotationControl specDnoGno:plotIndex];
	return (spc->peakMax);
}

- (float)graphViewPeakMin:(S7GraphView *)graphView gno:(NSUInteger)plotIndex;
// min peak値を返す:データ別
{
	GRAPH_SPECIFICATIONS *spc=[_rotationControl specDnoGno:plotIndex];
	return (spc->peakMin);
}

-(NSString *)graphViewYFormatter:(S7GraphView *)graphView_ cnt:(NSUInteger)cnt step:(float)step offset:(float)offset
// グラフの縦軸数値表示用文字列を返す
{
	NSArray *piArray;
	// offsetXの幅に収まるようにすること
	switch (_rotationControl.dno) {
		case DATA_DEGREE: // 0〜+-90
			return [NSString stringWithFormat:@"%+3d",(int)(-90+(180/[_rotationControl getYcount])*cnt)];
		case DATA_VELOCITY:
			// 本来ycountに依存するので、固定するのは良くないが、面倒なので。
			piArray=@[@"-2π",@"-3π/2",@"-π",@"-π/2",@"0",@"+π/2",@"+π",@"+3π/2",@"+2π"];
			return [NSString stringWithFormat:@"%5@",piArray[cnt]];
		case DATA_ROTATION:
			// 本来ycountに依存するので、固定するのは良くないが、面倒なので。
			switch (_rotationControl.gno) {
				case GRAPH_ALL:
				case GRAPH_X:
				case GRAPH_Y:
#ifndef USE_HOUI
				case GRAPH_Z: // 方位
#endif
				//	piArray=@[@"-π",@"-3π/4",@"-π/2",@"-π/4",@"0",@"+π/4",@"+π/2",@"+3π/4",@"+π"];
				//	return [NSString stringWithFormat:@"%5@",piArray[cnt]];
					return [NSString stringWithFormat:@"%+4d",(int)(-180+(360/[_rotationControl getYcount])*cnt)];
#ifdef USE_HOUI
				case GRAPH_Z: // 方位
					piArray=@[
							 NSLocalizedString(@"NORTH2",@"(北)"	),
							 NSLocalizedString(@"SE"	,@"南東"	),
							 NSLocalizedString(@"EAST"	,@"東"	),
							 NSLocalizedString(@"NE"	,@"北東"	),
							 NSLocalizedString(@"NORTH"	,@"北"	),
							 NSLocalizedString(@"NW"	,@"北西"	),
							 NSLocalizedString(@"WEST"	,@"西"	),
							 NSLocalizedString(@"SW"	,@"南西"	),
							 NSLocalizedString(@"SOUTH"	,@"南"	),
							];
					return [NSString stringWithFormat:@"%5@",piArray[cnt]];
#endif
			}
	}
	// 念のため
	return @"---";
}

//----------------------------------------------
// 画面を回転して良いかどうか
//----------------------------------------------
// iOS6.0

//- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
//{
//	// 画面回転は上下のみ有効
//	switch (interfaceOrientation) {
//		default: // 警告回避のため
//		case UIInterfaceOrientationPortrait:
//		case UIInterfaceOrientationPortraitUpsideDown:
//			break;
//		case UIInterfaceOrientationLandscapeLeft:
//		case UIInterfaceOrientationLandscapeRight:
//			// 横は不可
//			return NO;
//	}
//	return YES;
//}

-(BOOL)shouldAutorotate
{
	return shouldAutorotateByMain();
}

- (NSUInteger)supportedInterfaceOrientations
{
	return (supportedInterfaceOrientationsByMain());
}


- (void)didReceiveMemoryWarning
{
	printSelf();
    [super didReceiveMemoryWarning];
}


- (void)dealloc
{
	printSelf();
	//nslog(@"_rotationControl=%@",_rotationControl);
	[_rotationControl stopRotationControl]; // 停止だけ(確保は外部で行っているのでreleaseはしない)
	//
	nslog(@"alarmSymbol release=%@",alarmSymbol);
	[alarmSymbol waitErase]; // eraseが呼び出されるのを待つ;これをしないとalarmSymbolのrelaseが実行されない上、RotationViewControllerはreleaseされてしまい、erase中でエラーが発生する
}

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


@end
