//---------------------------------------------------------------------------------------------
//
//  FileControl2.m
//
//  Created by AIG-Soft on 2012/8/13
//  Copyright 2012-12 AIG-Soft. All rights reserved.
//
//---------------------------------------------------------------------------------------------
// パスにサロゲートペア文字が含まれていた場合正しく動作しないかもしれない(仕様)

#import "FileControl2.h"
#import "libs.h"
#include <sys/types.h>
#include <sys/stat.h>

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

/// ディレクトリ「tmp」のフルパスを得る
NSString *makeFullPathForTemporaryPath(NSString *basename)
{
	printFuncs(@"%@",basename);
#ifdef DEBUG
	// シミュレーター環境で実機と同じ場所にする
	return [NSHomeDirectory() stringByAppendingFormat:@"/tmp/%@",basename];
#else
	// NSTemporaryDirectory()は実機とシミュレーター環境では場所がぜんぜん違う
	return [NSTemporaryDirectory() stringByAppendingString:basename];
#endif
}

/// ディレクトリ「Documents」のフルパスを得る
/// iTunesからのデータやりとりもここ
NSString *getDocumentsPath(void)
{
//	printFunc();
	NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
#if 0
	for (NSString *path in paths) {
		nslog(@"path=%@",path);
	}
#endif
	// paths[0]を取り出す;そこにディレクトリ名が入っているらしい
	NSString *documentsDirectory = (([paths count] > 0)?		// 見つかったら
									/* これ↑は単なるポインタ参照 */
									paths[0]	// 最初のもの
									: NSTemporaryDirectory() );	// なければ一時ディレクトリ
//	nslog(@"documentsDirectory=%@",documentsDirectory);
	return (documentsDirectory);
}


/// リソースパスを得る
/// 予めリソース内にresource.txtを入れておくこと
NSString *getResourcePath(void)
{
//	printFunc();
	NSString *path=makeFullPathForResource(@"resource", @"txt");
//	NSLog(@"ResourcePath=%@",path);
	
	NSString *fname=[path lastPathComponent];
	return [path substringToIndex:[path length]-[fname length]]; // リソースパスにはサロゲートペアは入らないので問題なし
}


/// フルパス名の中のディレクトリ名を差し替える
/// @param [in] path 元のフルパス名
/// @param [in] repDir 差し返すディレクトリ名
NSString *replaceDirectory(NSString *path,NSString *repDir)
{
//	printFunc();
	NSString *fname=[path lastPathComponent];
//	NSString *dir  =[path substringToIndex:[path length]-[fname length]];
//	NSLog(@"path   =%@",path);
//	NSLog(@"dir    =%@",dir);
	NSString *newPath=[repDir stringByAppendingPathComponent:fname];
//	NSLog(@"newPath=%@",newPath);
	return newPath;
}

/// pathを解釈し、現在のDocumentとリソースディレクトリで適宜置き換える
NSString *autoReplaceDocumentOrResourceDirectory(NSString *path)
{
//	printFunc();
	NSString *repDir;
	NSString *fname=[path lastPathComponent];

	// pathのディレクトリ名部分のみ取り出す
	NSString *dir=[path substringToIndex:[path length]-[fname length]];
	if ([[dir lastPathComponent]isEqualToString:@"Documents"]) {
		nslog(@"Documentsの時");
		repDir=getDocumentsPath();
	} else {
		nslog(@"リソースの時");
		repDir=getResourcePath();
	}
	NSString *newPath=[repDir stringByAppendingPathComponent:fname];
//	NSLog(@"newPath=%@",newPath);
	return newPath;
}


/// データファイル名をフルパス名にする(NSString版)
/// ファイル検索はしない
/// ディレクトリ「Documents」である。iTunesからのデータやりとりもここ。
/// リソースのファイル名には使えない
NSString *makeFullPathForSaveData(NSString *fname)
{
	// ファイルパスの末尾にファイル名を追加
	return [getDocumentsPath() stringByAppendingPathComponent:fname];
}

/// データファイル名をフルパス名にする(char *版)
/// 途中NSStringに変換しているだけ（手抜き）
char *makeFullPathForSaveDataWithCString(char *fname)
{
	return nsStringTocString(makeFullPathForSaveData(@(fname)));
}

/// 日時を伴ったファイル名を作成する
/// ローカル確保なので、長期保存にはretain/copyすること
NSString *makeFullPathForSaveDataFromDate(NSString *basename)
{
	// printFuncs(@"basename=%@",basename);
	// 現在日時の文字列を得る
	NSDateFormatter *formatter=[[NSDateFormatter alloc]init]; // initはiOS4.0で廃止されている
	[formatter setLocale:[NSLocale currentLocale]]; // Localeの設定(重要)
	[formatter setDateFormat:@"yyyyMMdd_HHmmss_"];
	NSDate *date=[NSDate date];	// 一旦インスタンスに入れないとメモリリークを起こす
	NSString *dtstr=[formatter stringFromDate:date]; // 一旦インスタンスに入れないとメモリリークを起こす
	NSString *str=[[NSString alloc]initWithString:dtstr];
	// 一発で記述するとメモリリークを起こす
	//	NSString *str=[[NSString alloc]initWithString:[formatter stringFromDate:date]];
	//	nslog(@"str1=%@(%d)+%@(%d)",str,[str length],basename,[basename length]);
	NSString *fname=[str stringByAppendingString:basename];
	return (makeFullPathForSaveData(fname));
}

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

// アプリケーション用ディレクトリ(システム領域と呼ぶ)のフルパスを得る
// ローカル確保なので、長期保存にはretain/copyすること
NSString *getSystemPath(void)
{
//	printFunc();
	
	//	/Users/ユーザー名/Library/Application Support/iPhone Simulator/バージョン/Applications/番号/アプリ名.app/
	// これを直接得る関数が存在しない。
	// [[NSBundle mainBundle]pathForResource:]はファイル検索を伴ってしまうので、
	// 絶対にあると思われるディレクトリを使って検索する
	NSString *path=[[NSBundle mainBundle]pathForResource:@"en.lproj" ofType:@""];
	if (path==nil) {
		path=[[NSBundle mainBundle]pathForResource:@"ja.lproj" ofType:@""];
		
	}
	// 一応英→日の順で調べるが、どちらもなければ諦める
	if (path==nil) return(nil);
	nslog(@"システムパス＝%@",path);
	//	/Users/ユーザー名/Library/Application Support/iPhone Simulator/バージョン/Applications/番号/アプリ名.app/en.jproj
	// の形式で帰ってくるので、最後の部分を取り除く
	NSString *lastpath=[path lastPathComponent];
	nslog(@"最後の部分 ＝%@",lastpath);
	//
	size_t lenAll=[path length]; // 全体長
	size_t lenLastPath=[lastpath length]; // 最後の部分の長さ
	NSString *systemDirectory=[path substringWithRange:NSMakeRange(0, lenAll-lenLastPath-1)]; // -1はlastPath前の/
	nslog(@"システムディレクトリ=%@",systemDirectory);
	return (systemDirectory);
}

// リソース内のパスを得る(char *版)
// 途中NSStringに変換しているだけ（手抜き）
char *makeFullPathForResourceWithCString(char *fname)
{
	if (fname==NULL) return(NULL); // これは別に排除しておかなければならない
	printFuncs(@"%s",fname);
	NSString *str=makeFullPathForResource(@(fname),@"");
	return nsStringTocString(str);
}

// データファイル名をフルパス名にする(NSString版)
// makeFullPathForResource()がすでに使われているので。結果は同じはずである。
// ファイル検索はしない
NSString *makeFullPathForSystem(NSString *fname)
{
	// ファイルパスの末尾にファイル名を追加
	return [getSystemPath() stringByAppendingPathComponent:fname];
}

// システム内のパスを得る(char *版)
// 途中NSStringに変換しているだけ（手抜き）
char *makeFullPathForSystemWithCString(char *fname)
{
	if (fname==NULL) return(NULL); // これは別に排除しておかなければならない
	printFuncs(@"%s",fname);
	NSString *str=makeFullPathForSystem(@(fname));
	return nsStringTocString(str);
}

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

NSString *getResourceOrSavedataPath(NSString *fname)
{
	// まずiTunesとのやり取りパス内を探す(外部が優先)
	NSString *path=makeFullPathForSaveData(fname);
	nslog(@"saveパス=%@",path);
	// 検索する
//	if (![[NSFileManager defaultManager]isReadableFileAtPath:path]) {	// v3.50
	if (!isFileExist(path)) {
		nslog(@"外部がなかったらリソース内を探す");
		nslog(@"fname=%@",fname);
		path=makeFullPathForResource(fname,@""); // ファイル検索付き;見つからなかったらnilが返る
		nslog(@"リソースパス=%@",path);
		// nilが返ることもある
	}
	return (path);
}

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

/// 読めるファイルが存在するかどうか調べる
/// @return YES=存在する , NO=存在しない
BOOL isFileExist(NSString *path)
{
	printFunc();
	return [[NSFileManager defaultManager] fileExistsAtPath:path];
}

//------------------------------------------------------------------------------
		 
/// ディレクトリbasepath以下中の拡張子extを持つ/持たないファイルのリストを得る(下位ディレクトリも含む)
/// ディレクトリ名も取得できる
/// 拡張子チェックはファイル名のみ
/// ローカル確保なので、長期保存にはretain/copyすること
/// fhave : YES=拡張子一致/NO=不一致
/// freg  : YES=正規表現比較 , NO=単純文字列比較
/// mode  : FILES_*
NSArray *files(NSString *basepath,NSString *ext,BOOL fhave,int mode,BOOL freg)
{
	printFunc();
	nslog(@"basepath=%@,ext=%@",basepath,ext);
	
	NSFileManager *fileManager = [NSFileManager defaultManager];
	NSArray *pathListAll=[NSArray arrayWithArray:[fileManager subpathsAtPath:basepath]]; // これで返ってくるのはディレクトリ名/ファイル名.ext
	nslog(@"pathListAll=%@",pathListAll);
	
	BOOL fnoext=([ext isEqualToString:@""]||[ext isEqualToString:@"*"]); // 拡張子チェックをしないかどうか
	nslog(@"fnoext=%d",fnoext);
	
	NSMutableArray *pathList=[[NSMutableArray alloc]init];
	for (NSString *path in pathListAll) {
		nslog(@"path=%@",path);
		BOOL isDir;
		if ([fileManager fileExistsAtPath:
			 //makeFullPathForSaveData(path) // v2.8までのバグ；basedirをどう与えようとデータ領域しか検索できなかった
			 [basepath stringByAppendingPathComponent:path] isDirectory:&isDir]) {
			if (isDir) {
				nslog(@"dir =%@",path);
				// ディレクトリはチェック対象にしない
				if (!(mode&FILES_DIR)) continue;
				// dir.extという名前のディレクトリの時のため、ディレクトリ名では拡張子チェックはしない
				// 最後が/で終わるのがディレクトリ名
				[pathList addObject:[NSString stringWithFormat:@"%@/%@/",basepath,path]];
			} else {
				// ファイルである
				nslog(@"file=%@",path);
				if (!(mode&FILES_FILE)) continue;
				BOOL fmatch=YES;
				if (!fnoext) {
					// 拡張子チェック
					if (freg) { // 正規表現比較
						nslog(@"正規表現拡張子比較:%@ : %@",[path pathExtension],ext);
						fmatch=(cmpRegularExpression([path pathExtension],ext)==fhave); // 拡張子一致/不一致
					} else { // 単純文字列比較
						// nslog(@"ext=%@(%d)",[path pathExtension],[[path pathExtension]isEqualToString:ext]);
						fmatch=([[path pathExtension]isEqualToString:ext]==fhave); // 拡張子一致/不一致
					}
				} // 拡張子判定なしの時は常に一致
				if (fmatch) {
					[pathList addObject:[NSString stringWithFormat:@"%@/%@",basepath,path]];
				}
			}
		}
#ifdef DEBUG
		else {
			// ファイルとしておかしい時も検索対象外にする
			nslog(@"異常path=%@",path);
		}
#endif
	}
	nslog(@"チェック後pathList=%@",pathList); // ここにはフルパス名が入る
	// NSArrayに変換して返す
	NSArray *list=[NSArray arrayWithArray:pathList];
	 // mutableは解放
	return (list);
}

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

// 拡張子を変更する
// iOSではファイル名の大文字小文字が区別されるので注意
NSString *replaceExt(NSString *path,NSString *ext)
{
	printFunc();
	nslog(@"path=%@/ext=%@",path,ext);
	NSArray *components=[path componentsSeparatedByString:@"."];
	//
	nslog(@"components=%@",components);
	//
	NSUInteger cnt=[components count];
	nslog(@"components数=%tu",cnt);
	// 内容を変更するからNSMutableArrayに変更
	NSMutableArray *mucomponents=[NSMutableArray arrayWithArray:components];
	if (cnt==1) {
		// cnt==1はファイル名のみである
		// .basを追加
		nslog(@"ファイル名のみである");
	} else { // cnt>=2
		// fname.a.b.ext : 最後の'.'より後ろを拡張子とみなす
		NSString *ext0=components[cnt-1];
		if ([ext0 caseInsensitiveCompare:ext]==NSOrderedSame) {
			// すでに.basがあるときはそのまま
			nslog(@".basそのまま");
			return (path);
		}
	}
	[mucomponents addObject:ext];
	
	// 要素を再結合
	nslog(@"mucomponents=%@",mucomponents);
	//
	NSMutableString *newpath=[[NSMutableString alloc]init];
	for (NSString *s in mucomponents) {
		[newpath appendString:s];
		[newpath appendString:@"."];
	}
	// 最後の"."を消す
	nslog(@"newPath=%@(%d)",newpath,(int)[newpath length]);
	NSString *s=[NSString stringWithString:[newpath substringToIndex:[newpath length]-1]];
	nslog(@"s=%@",s);
	return (s);
}

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

// ファイル削除
void fileDelete(NSString *fname)
{
	printFuncs(@"%@",fname);
	if (fname==nil) {
		nslog(@"削除対象ファイルなし");
		return;
	}
	// ファイル削除
	NSFileManager *fileManager=[NSFileManager defaultManager];
	NSError *err;
	err=[[NSError alloc]init];
	if (![fileManager removeItemAtPath:fname error:&err]) {
		// 削除エラーは取らない；出るようならiOSがおかしいか、フラッシュがへたっている可能性が高いので、ここで対処できないから
		// !! error !!
		nslog(@"remove error:%@",err);
	}
}

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

BOOL fileCopy(NSString *src,NSString *des)
{
	printFunc();
	nslog(@"%@ → %@",src,des);
	
	NSFileManager *fp=[NSFileManager defaultManager];
	NSError *error;
	BOOL ret=[fp copyItemAtPath:src toPath:des error:&error];
	if (!ret) {
		nslog(@"error=%@",error);
	}
	return ret;
}

BOOL fileMove(NSString *src,NSString *des)
{
	printFunc();
	nslog(@"%@ → %@",src,des);
	
	NSFileManager *fp=[NSFileManager defaultManager];
	NSError *error;
	BOOL ret=[fp moveItemAtPath:src toPath:des error:&error];
	if (!ret) {
		nslog(@"error=%@",error);
	}
	return ret;
}

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

// ファイルの長さを返す
off_t filelength(FILE *fp)
{
	struct stat _stat;
	fstat(fileno(fp),&_stat);
	return (_stat.st_size);	// off_t = unsigned long
}

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