module yamalib.auxil.properties;

private import std.stream;
private import std.string;
private import std.conv;
private import std.file;
private import std.path;
private import std.stdio;

private import y4d_aux.filesys;

/**
	JAVAにあるような、プロパティファイル
*/
class Properties {
	
	static Properties getInstance(char[] filename) {
		char[] lowFilename = cast(char[]) std.string.tolower(filename);

/+
		//test
		Properties prop = new Properties();
		prop.load(filename);
		return prop;
+/
		Properties* p = (lowFilename in INSTANCE_MAP);
		if (p is null) {
			Properties prop = new Properties();
			if (prop.load(filename)) {
				INSTANCE_MAP[lowFilename] = prop;
			}
			return prop;
		}
		p.checkLastMod();
		return *p;
	}
	
	/// プロパティの取得
	char[] getProperty(char[] key) {
		char[]* p;
		p = (key in mp);
		if (p is null) {
			return null;
		}
		return (*p).dup;
	}
	
	/// プロパティの取得
	char[] getProperty(char[] key, char[] def) {
		char[]* p;
		p = (key in mp);
		if (p is null) {
			return def;
		}
		
		return *p;
	}
	
	/// プロパティの取得
	long getPropertyNum( char[] key, long def ) {
		char[] value = getProperty( key );
		if ( value is null ) {
			return def;
		}

		long num = def;
		try {
			num = std.conv.toLong( value );
		} catch (ConvError e) {
		}
		
		return num;
	}
	
	/// デジマルの取得
	double getPropertyDecimal( char[] key, double def ) {
		char[] value = getProperty( key );
		if ( value is null ) {
			return def;
		}

		double num = std.string.atof(value);
		if (value!="0" && num==0){
			num = def; // これ解析失敗か
		}
		
		return num;
	}
	
	/// プロパティのすべてのキーを取得
	char[][] getPropertyNames() {
		return cast(char[][]) mp.keys;
	}
	
private
	this() {
	}

	/// ファイルの最終変更時間を取得
	static long getModTime(char[] filename) {
		long modTime = -1L;
		try {
			long createTime, accessTime;
			std.file.getTimes(filename, createTime, accessTime, modTime);
		} catch {
			// ファイルにアクセス失敗...
		}
		return modTime;
	}
	
	/// ファイル名を取り除きパスだけにします
	static char[] getDirPath(char[] filename) {
		char[][] path = cast(char[][]) .split(.replace(filename, "/", "\\"), "\\");
		if (path.length == 1) {
			// カレントディレクトリ
			return cast(char[]) ".\\";	
		}
		char[] resultPath;
		foreach(i,aPath; path) {
			// 最後はファイル名
			if (i == path.length-1) {
				break;
			}
			resultPath ~= aPath ~ "\\";
		}
		return resultPath;
	}
	
	/// ファイル名だけ取り出します
	static char[] getFileNameOnly(char[] pathFilename) {
		char[][] path = cast(char[][]) .split(.replace(pathFilename, "/", "\\"), "\\");
		return path[length-1];
	}
	
	/// ファイルの最終変更時間をチェックし変更されていれば再読込を行う
	void checkLastMod() {
		if ( getModTime(propname) > lastWriteTime ) {
			load(propname);
		}
	}
	
	/// 読み込みます
	bool load(char[] filename) {
		propname = filename;
printf("propName -- %*s\n",filename);
		lastWriteTime = getModTime(filename);
		ubyte[] mem = cast(ubyte[]) FileSys.read(filename);
		if (!mem) {
			writefln("Properties file not found : {%s}", filename);
			return false; // 読み込みエラー
		}
		
		std.stream.MemoryStream m = new std.stream.MemoryStream(mem);
		while (!m.eof) {
			// 「#」はコメント
			char[][] buf = cast(char[][]) std.string.split( m.readLine(), "#");
			if ( buf.length < 1 ) {
				continue;
			}
			
			char[] linebuf = buf[0];
			int pos  = std.string.ifind(linebuf, '=');
			
			if ( -1 == pos ) {
				continue;
			}
			
			char[] key = linebuf[0..pos];
			char[] value = cast(char[]) "";
			if ( linebuf.length >= pos + 1 ) {
				value = linebuf[(pos+1)..length];
			}
			mp[key] = value;
		}
		m.close();
		return true;
	}
	
		
private:
	static Properties[char[]] INSTANCE_MAP;

	char[][char[]] mp;
	char[] propname;
	long lastWriteTime = -1L;

}