//
//  libs.m
//  汎用関数
//
//  Created by 今井 彰彦 on 10/12/21.
//  Copyright 2010 AIG-Soft. All rights reserved.
//

#import "libs.h"
#import "NSString+sizeWithFont.h"

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

NSString *strInterfaceOrientation(UIInterfaceOrientation Orientation)
// UIInterfaceOrientationで回転方向を文字列で返す
// 固定アドレスを返すだけなのでrelease不要
{
	// nslog(@"strOrientation回転方向=%d",Orientation);
	switch (Orientation) {
		case UIInterfaceOrientationPortrait:
			return(@"縦");
		case UIInterfaceOrientationPortraitUpsideDown:
			return(@"縦；上下逆");
		case UIInterfaceOrientationLandscapeLeft:
			// UIDeviceOrientationLandscapeLeftとは逆になるので注意
			return(@"横右");
		case UIInterfaceOrientationLandscapeRight:
			// UIDeviceOrientationLandscapeRightとは逆になるので注意
			return(@"横左");
		default: // 警告回避のため
			break;
	}
	nslog(@"未定義=%d",(int)Orientation);
	return(@"未定義");
}

NSString *strDeviceOrientation(UIDeviceOrientation Orientation)
// UIDeviceOrientationで回転方向を文字列で返す
// 固定アドレスを返すだけなのでrelease不要
{
	// nslog(@"strOrientation回転方向=%d",Orientation);
	switch (Orientation) {
		case UIDeviceOrientationUnknown:
			return(@"不明");
		case UIDeviceOrientationPortrait:
			return(@"縦");
		case UIDeviceOrientationPortraitUpsideDown:
			return(@"縦；上下逆");
		case UIDeviceOrientationLandscapeLeft:
			return(@"横左");
		case UIDeviceOrientationLandscapeRight:
			return(@"横右");
		case UIDeviceOrientationFaceUp:
			return(@"上面");
		case UIDeviceOrientationFaceDown:
			return(@"下面");
	}
	nslog(@"未定義=%d",(int)Orientation);
	return(@"未定義");
}

BOOL checkDeviceOrientation(UIDeviceOrientation *deviceOrientation)
// デバイスの方向の取得と、それが縦横であるかどうか
// YES=縦横 , NO=それ以外
{
	//	nslog(@"UIDevice=%@",[UIDevice currentDevice]);
	*deviceOrientation = [UIDevice currentDevice].orientation;
	switch (*deviceOrientation) {
		case UIDeviceOrientationUnknown:
			nslog(@"方向不明");
			// 回転は加速度計を使って取得しているため、傾き途中にも通知が入り、その時この状態になる。
			// なので、回避が必要。
			return (NO);
		case UIDeviceOrientationFaceUp:
		case UIDeviceOrientationFaceDown:
			// この方向も無視する必要がある
			nslog(@"上下向き");
			return (NO);
		default: // 警告排除のため(実際には来ない)
			break;
	}
	// 縦横方向；問題なし
	return(YES);
}

BOOL checkDeviceOrientationOK(void)
// デバイスの方向が縦横であるかどうか
// YES=縦横 , NO=それ以外
{
	UIDeviceOrientation deviceOrientation;
	return (checkDeviceOrientation(&deviceOrientation));
}

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

static UIInterfaceOrientation _devOrientation_=UIInterfaceOrientationPortrait;

void understandOrientation(UIInterfaceOrientation Orientation)
{
	// すべてのshouldAutorotateToInterfaceOrientation:に入れ、回転を記録しておく
	_devOrientation_=Orientation;
}

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

DEVICE_TYPE getDeviceType(void)
// 実行中のデバイス種別を返す
{
	NSString *modelname=[[UIDevice currentDevice]model];
	nslog(@"model=%@",modelname);
	if ([modelname isEqualToString:@"iPad"]) return(DEVICE_IPAD);
	if ([modelname isEqualToString:@"iPhone"]) return(DEVICE_IPHONE);
	if ([modelname isEqualToString:@"iPod touch"]) return(DEVICE_IPODTOUCH);
	if ([modelname isEqualToString:@"iPhone Simulator"]) return(DEVIDE_IPHONE_SIMURATOR);
	return(DEVICE_IPAD_SIMULATOR);
}

BOOL isDeviceIpad(DEVICE_TYPE devtype)
// iPadかどうか（シミュレーターを含む）
{
	switch (devtype) {
		case DEVICE_IPAD:
		case DEVICE_IPAD_SIMULATOR:
			nslog(@"This is iPad=%d",devtype);
			return (YES);
		default: // 警告回避のため
			break;
	}
	return(NO);
}

BOOL isDeviceIpadAndPortrait(DEVICE_TYPE devtype)
// iPadの縦画面かどうか
{
	printFunc();
	if (isDeviceIpad(devtype)) { // iPad
		//UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
		//↑これでは、一度も回転していないときにUIDeviceOrientationUnknownが返ってくるので使っていない(iOSのバグ？)
		//nslog(@"deviceOrientation=%d",deviceOrientation);
		
		nslog(@"UIInterfaceOrientation=%d",(int)_devOrientation_);
		switch (_devOrientation_) {
			case UIDeviceOrientationPortrait:
			case UIDeviceOrientationPortraitUpsideDown:
				nslog(@"iPad縦画面");
				return (YES);
			default:
				// 他の方向の時
				break;
		}
	} // iPhone/iPod touch
	return(NO);
}

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

void SetViewBelowStatusBar(UIView *view)
// 何故かIB上ではどう設定してもステータスバー分のずらしがなされないため、手動で行う
{
	// サイズはもともとステータスバー文を引いたサイズが入っている
	//nslog(@"frame=%@",aViewController.view);
	CGRect frame,bounds;
	bounds=[[UIScreen mainScreen]bounds]; // 全画面サイズ
	//	nslog(@"bounds=%f,%f,%f,%f",bounds.origin.x,bounds.origin.y,bounds.size.width,bounds.size.height);
	frame=view.frame;
	frame.origin.y+=(bounds.size.height-frame.size.height); // statusバーの分を下げる
	view.frame=frame;
}

void SetViewSize(UIView *view,CGFloat wx,CGFloat wy)
// UIViewの幅を設定する
// IBでは設定ができないので
// 数値のチェックはしてない
// wx,wy<0のときは、画面幅の1/(-wx),1/(-wy)にする
{
	CGRect frame;
	nslog(@"元size=%f,%f",wx,wy);
	if (wx<0||wy<0) {
		CGRect bounds;
		bounds=[[UIScreen mainScreen]bounds]; // 全画面サイズ
		nslog(@"bounds=%f,%f,%f,%f",bounds.origin.x,bounds.origin.y,bounds.size.width,bounds.size.height);
		if (wx<0) {
			wx=-wx;
			wx=bounds.size.width/wx;
		}
		if (wy<0) {
			wy=-wy;
			wy=bounds.size.height/wy;
		}
	}
	nslog(@"size=%f,%f",wx,wy);
	frame=view.frame;
	frame.size.width =wx;
	frame.size.height=wy;
	view.frame=frame;
}

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

NSString *mesONOFF(BOOL onoff)
// switch状態表示文字列を返す
// 固定アドレスを返すだけなのでrelease不要
{
	if (onoff) {
		return NSLocalizedString(@"ON",@"オン");
	}
	return NSLocalizedString(@"OFF",@"オフ");
}

NSString *mesONOFF2(BOOL onoff,NSString *onmes,NSString *offmes)
// switch状態表示文字列を指定文字列で返す
// 固定アドレスを返すだけなのでrelease不要
{
	if (onoff) {
		return NSLocalStr(onmes);
	}
	return NSLocalStr(offmes);
}

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

NSUInteger getHourMinSec(NSDate *date,NSUInteger *hour,NSUInteger *sec)
// dateから時分秒を数値で返す
// リターン値は分
{
	nslog(@"NSDate=%@",date); // GMT+0000で表示される
	// 分だけ取り出す
	// NSDateから直接取り出す方法がないので非常に面倒な方法をとっている
	NSDateFormatter *formatter=[[NSDateFormatter alloc]init]; // initはiOS4.0で廃止されている
	[formatter setLocale:[NSLocale currentLocale]]; // Localeの設定(重要)
	[formatter setDateFormat:@"m"]; // 分だけ取り出す
	NSString *dtstr;
	dtstr=[formatter stringFromDate:date]; // 一旦インスタンスに入れないとメモリリークを起こす
	NSInteger minute=[dtstr intValue]; // 整数化
//	nslog(@"minute=%d",minute);
	if (hour!=NULL) {
		[formatter setDateFormat:@"H"]; // 時だけ取り出す
		dtstr=[formatter stringFromDate:date]; // 一旦インスタンスに入れないとメモリリークを起こす
		*hour=[dtstr intValue]; // 整数化
//		nslog(@"hour=%d",*hour);
	}
	if (sec!=NULL) {
		[formatter setDateFormat:@"s"]; // 秒だけ取り出す
		dtstr=[formatter stringFromDate:date]; // 一旦インスタンスに入れないとメモリリークを起こす
		*sec=[dtstr intValue]; // 整数化
//		nslog(@"sec=%d",*sec);
	}
	return (minute);
}

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

void centeringActivityIndicator(UIActivityIndicatorView *indicator,UIView *view)
// ActivityIndicatorを画面ど真ん中に表示する
{
	CGRect frame;
	frame.origin=CGPointZero;
	frame.size.width=37;
	frame.size.height=37; // インジケーターのサイズ
	indicator.frame=frame;
	indicator.center=view.center; // viewのど真ん中に出す
	[view addSubview:indicator]; // 少なくともここで初期表示が出るはず
	[indicator startAnimating];
	EnterRunLoop(0.0); // UIActivityIndicatorViewはRunLoopに戻らないと表示されないので、一瞬戻す
}

UIActivityIndicatorView *displayActivityIndicator(UIView *view,UIActivityIndicatorViewStyle style)
// ActivityIndicatorを表示する
{
	UIActivityIndicatorView *indicator=[[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:style];
#ifdef DEBUG
	if (indicator==nil) {
		nslog(@"indicator確保できず");
	}
#endif
	centeringActivityIndicator(indicator,view);
	// インジケーターは画面ど真ん中に出す
	
	return(indicator);
}

void changeActivityIndicator(UIActivityIndicatorView *indicator,UIView *view)
// ActivityIndicator位置を変更する
// 回転に対応させるときは、回転後のviewControllerを与える必要がある
{
	// 一旦インジケーターを止める
	[indicator stopAnimating];
	[indicator removeFromSuperview]; // 外す
	// 再度画面ど真ん中に出す
	centeringActivityIndicator(indicator,view);
}

void eraseActivityIndicator(UIActivityIndicatorView *indicator)
// ActivityIndicatorを消す
{
	[indicator stopAnimating];
	[indicator removeFromSuperview]; // 外す
}

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

#ifdef DEBUG
void printFrame(NSString *mes,CGRect frame)
{
	nslog(@"%@=%f,%f,%f,%f",mes,frame.origin.x,frame.origin.y,frame.size.width,frame.size.height);
}

void printInset(NSString *mes,UIEdgeInsets inset)
{
	nslog(@"%@=%f,%f〜%f,%f",mes,inset.top,inset.left,inset.bottom,inset.right);
}

void printSize(NSString *mes,CGSize size)
{
	nslog(@"%@=%f,%f",mes,size.width,size.height);
}

void printOffset(NSString *mes,CGPoint point)
{
	nslog(@"%@=%f,%f",mes,point.x,point.y);
}
#endif

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

void setActionSheetResize(UIActionSheet *asheet)
// ActionSheetの回転時のリサイズ指定
// IBが使えないので
{
	asheet.autoresizesSubviews=YES;
	asheet.autoresizingMask=	UIViewAutoresizingFlexibleWidth |
								UIViewAutoresizingFlexibleHeight |
								UIViewAutoresizingFlexibleTopMargin |
								UIViewAutoresizingFlexibleBottomMargin |
								UIViewAutoresizingFlexibleLeftMargin |
								UIViewAutoresizingFlexibleRightMargin;
}


void setAlertViewResize(UIAlertView *aview)
// AlertView の回転時のリサイズ指定
// IBが使えないので
{
	aview.autoresizesSubviews=YES;
	aview.autoresizingMask=	UIViewAutoresizingFlexibleWidth |
							UIViewAutoresizingFlexibleHeight |
							UIViewAutoresizingFlexibleTopMargin |
							UIViewAutoresizingFlexibleBottomMargin |
							UIViewAutoresizingFlexibleLeftMargin |
							UIViewAutoresizingFlexibleRightMargin;
}

void Alert1(NSString *title,NSString *message,id delegate)
// アラートの表示
{
	nslog(@"Alert1:%@",NSLocalStr(title));
	UIAlertView *aview=[[UIAlertView alloc]initWithTitle:NSLocalStr(title)
												 message:NSLocalStr(message)
												delegate:delegate
									   cancelButtonTitle:NSLocalStr(@"CLOSE")
									   otherButtonTitles:nil,nil];
	setAlertViewResize(aview); // リサイズ設定
	[aview show]; // 表示したらすぐ帰ってくる
}

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

NSString *dateStringWithoutGMT(NSDate *date)
// NSDate descriptionは〜±hhmmなので、この最後のGMT表記を消した文字列を返す
// 長期保存にはretain/copyすること
// Localizable.stringsに"DATE"の設定が必要なので要確認
{
	NSDateFormatter *formatter=[[NSDateFormatter alloc]init]; // initはiOS4.0で廃止されている
	[formatter setLocale:[NSLocale currentLocale]]; // Localeの設定(重要)
	[formatter setDateFormat:NSLocalStr(@"DATE")];
	NSString *str=[formatter stringFromDate:date];
	nslog(@"dateStringWithoutGMT=%@",str);
	//	return (str); // アドレス返しだけではダメ
	return [NSString stringWithString:str]; // ローカルスタック上に実体を生成してからリターンする
}


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

NSString *dateFormatJtoE(NSString *date)
// 日時文字列の日英を、現在のローカライズに合わせて変換する
// 長期保存にはretain/copyすること
{
	if (date==nil) {
		return [NSString stringWithString:NSLocalStr(@"NODATE")];
	}
	// 途中で日英を切り替えると、前の日時並びのまま表示されてしまう
	// 本来途中での切り替えはないはずだが、一応対策しておく
	// 0123
	// MM/DD/YYYY と YYYY/MM/DDが混在するため、[2]が/かどうかで判定する
	NSString *datefmt=NSLocalStr(@"DATE"); // 現在のローカライズにおける日付フォーマット
	unichar c =[datefmt characterAtIndex:2]; // UTF16
	unichar c2=[date    characterAtIndex:2]; // UTF16
	nslog(@"date=%@ [2]=%c($%04x) : fmt=%@ [2]=%c($%04x)",date,c2,c2,datefmt,c,c);
	// 文字コードはUTF-16
	if (c=='/') { // 現在は英語モード
		if (c2!='/') {
			// 元が日本語モードで入っている
			// 01234567890
			// yyyy/mm/dd → mm/dd/yyyy 以下同じ
			nslog(@"日→英");
			NSString *yyyy=[date substringToIndex:4]; // yyyy 0〜 4文字
			NSString *tim =[date substringFromIndex:10]; // 時間
			NSString *mmdd=[date substringWithRange:NSMakeRange(5,5)]; // mm/dd
			return [NSString stringWithFormat:@"%@/%@%@",mmdd,yyyy,tim];
		}
		// もともと英語モードである：変換不要
		return [NSString stringWithString:date];
	}
	// 現在は日本語モード
	if (c2=='/') {
		// 元が英語モードで入っている
		nslog(@"英→日");
		// 01234567890
		// mm/dd/yyyy → yyyy/mm/dd 以下同じ
		NSString *mmdd=[date substringToIndex:5]; // mm/dd 0〜5文字
		NSString *tim =[date substringFromIndex:10]; // 時間
		NSString *yyyy=[date substringWithRange:NSMakeRange(6,4)]; // yyyy
		return [NSString stringWithFormat:@"%@/%@%@",yyyy,mmdd,tim];
	}
	// もともと日本語モードである：変換不要
	return [NSString stringWithString:date];
}

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

BOOL cmpRegularExpression(NSString *str,NSString *expression)
// 文字列strと正規表現expressionが一致するかどうか調べる
// 大文字小文字区別なし
// NO=不一致 , YES=一致
{
	nslog(@"cmpRegularExpression");
	// NSRegularExpressionはiOS 4.0以降で実装された正規表現用クラス
	NSError *error = NULL;
	// 正規表現インスタンスの作成
	NSRegularExpression *regexp = [NSRegularExpression regularExpressionWithPattern:expression
																			options:NSRegularExpressionCaseInsensitive	/* 大文字小文字区別なし */
																			  error:&error];
	if (error != nil) {
		nslog(@"Error=%@", error);
		// 念のため
		return (NO);
	}
	NSTextCheckingResult *match =[regexp firstMatchInString:str options:0 range:NSMakeRange(0, [str length])]; /* strの長さ全体が比較対象 */
	nslog(@"match.resultType=%llx",match.resultType); // NSTextCheckingTypeRegularExpression＝正規表現が返ってきている
	nslog(@"match.numberOfRanges=%d",(int)match.numberOfRanges);
	nslog(@"match.regularExpression=%@",match.regularExpression); // 正規表現そのものが入っている
	return (match.numberOfRanges>0);
}

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

// 正規表現でのバックスラッシュはC言語では\\になることに注意
#if 0 // これの方がより厳しいらしい
が、iOSではエラーになってしまうので使えない
// 電子メールと比較する正規表現:http://msdn.microsoft.com/ja-jp/library/01escwtf.aspx より
#define EMAIL_EXPRESSION	@"^(?(\x22\x22)(\x22\x22.+?\x22\x22@)|(([0-9a-zA-Z]((\\.(?!\\.))|[-!#\\$%&'\\*\\+/=\\?\\^`\\{\\}\\|~\\w])*)(?<=[0-9a-zA-Z])@))"	\
							@"(?(\\[)(\\[(\\d{1,3}\\.){3}\\d{1,3}\\])|(([0-9a-zA-Z][-\\w]*[0-9A-Z]\\.)+[a-zA-Z]{2,6}))$"
#else
#define EMAIL_EXPRESSION	@"^[a-zA-Z0-9!$&*.=^`|~#%'+\\/?_{}-]+@([a-zA-Z0-9_-]+\\.)+[a-zA-Z]{2,4}$"	
							// 途中に@が必須
#endif

BOOL isMailAddress(NSString *adrs)
// 文字列がメイルアドレスとして有効かどうか調べる
// NO=不一致 , YES=一致
// 厳密な表現は http://www.din.or.jp/~ohzaki/mail_regex.htm らしいが、あまりに長すぎるので簡易チェック
{
	nslog(@"isMailAddress");
	return cmpRegularExpression(adrs,EMAIL_EXPRESSION);
}

#define SERVER_EXPRESSION	@"^[a-zA-Z0-9!$&*.=^`|~#%'+\\/?_{}-]+([a-zA-Z0-9_-]+\\.)+[a-zA-Z]{2,4}$"	
							// 英数字.の繰り返し

BOOL isServerAddress(NSString *adrs)
// 文字列がサーバードレスとして有効かどうか調べる
// NO=不一致 , YES=一致
{
	nslog(@"isServerAddress");
	return cmpRegularExpression(adrs,SERVER_EXPRESSION);
}


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

NSString *localKeyName(NSString *defaultName)
{
	// ローカライズ別キー名を返す
	return [NSString stringWithFormat:@"%@:%@",NSLocalizedString(@"LOCAL",nil),defaultName];
}

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

static 
RGB_TABLE rgb[]={//B   R   G
	{  0,  0,  0},
	{250,  0,  0},
	{ 92,215,107},	//{  0,250,  0},	// 朱色
	{250,250,  0},
	{  0,  0,250},
	{250,  0,250},
	{  0,250,250},
	{255,255,255}
};

UIColor *colorByNo(NSInteger no)
// 番号から色を返す関数
// ローカルに確保された値を返すため、長期保持が必要ならretain/copyが必須(即使うなら必要なし)
{
	if (no>sizeof(rgb)/sizeof(RGB_TABLE)) no=PENCIL_COLOR_WHITE;
	UIColor *color=[UIColor colorWithRed:rgb[no].r/255.0f green:rgb[no].g/255.0f blue:rgb[no].b/255.0f alpha:1.0f];
	return color;
}

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

float getSystemVersion(void)
// iOSバージョンを得る
{
	NSString *version = [[UIDevice currentDevice]systemVersion];
	nslog(@"getSystemVersion=%@/SystemName=%@",version,[[UIDevice currentDevice]systemName]);
	nslog(@"Version %@(%f)", version,[version floatValue]);
	return [version floatValue];
}

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

BOOL isPointInRect(CGPoint point,CGRect rect)
// pointがrectに入っているかどうか
{
	return (point.x>=rect.origin.x && point.y>=rect.origin.y
			&& point.x<rect.origin.x+rect.size.width
			&& point.y<rect.origin.y+rect.size.height);
}

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

NSInteger strArray2No(NSString *str,NSArray *array)
// strがNSString *array[]の何番目にあるか調べる
{
	NSInteger no=0;
	NSEnumerator *emu=[array objectEnumerator];
	NSString *name;
	while (name=[emu nextObject]) {
		if ([str isEqualToString:name]) return (no);
		no++;
	}
	// 見つからなかった
	return (-1);
}

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

NSInteger pathArray2No(NSString *fname,NSArray *pathes)
// fnameがNSString *pathes[]の何番目にあるか調べる
// pathes = フルパス名
// fname  = ファイル名
{
	NSInteger no=0;
	NSEnumerator *emu=[pathes objectEnumerator];
	NSString *path;
	while (path=[emu nextObject]) {
		if ([[path lastPathComponent]isEqualToString:fname]) return (no);
		no++;
	}
	// 見つからなかった
	return (-1);
}

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

NSString *makeNowDateStr(void)
// 現在日時の文字列を得る
// ローカルに確保されるので、必要ならcopy/retainすること
{
	NSDateFormatter *formatter=[[NSDateFormatter alloc]init]; // initはiOS4.0で廃止されている
	[formatter setLocale:[NSLocale currentLocale]]; // Localeの設定(重要)
	[formatter setDateFormat:NSLocalStr(@"DATE")];
	NSDate *date=[NSDate date];
	NSString *string=[formatter stringFromDate:date];
	NSString *str=[NSString stringWithString:string]; // ローカルに確保
	return (str);
}

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

CGSize getFontSize(UIFont *font)
{
	CGSize spSize;
	if (  [font.familyName hasPrefix:@"Hiragino"]
		||[font.familyName hasPrefix:@"AppleGothic"]
		||[font.familyName hasPrefix:@"ApSanskrit"]
		) {
		// ヒラギノ/AppleGothic/梵字->pointSize
		spSize=[ZSPC sizeWithFont7:font];	// 全角スペース
		nslog(@"spSize補正前:w=%f,h=%f",spSize.width,spSize.height);
		spSize.height=font.pointSize; // lineHeightでは縦に余裕がありすぎるのでpointSizeにする
		nslog(@"spSize補正後:w=%f,h=%f",spSize.width,spSize.height);
	} else {
		// ヒラギノ/AppleGothic以外はWを基準にする
		spSize=[@"W" sizeWithFont7:font];	// 一番幅の広いフォント(Wの方がZSPCより幅が広い）
		nslog(@"spSize(W):w=%f,h=%f",spSize.width,spSize.height);
	}
	return spSize;
}

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