// プロトタイプ
Ini.prototype = {
	meta: {
		"@prefix": "<http://purl.org/net/ns/doas#>",
		"@about": "<io.js>", a: ":JavaScript",
		 title: "Ini file class",
		 created: "2009-01-17", release: {revision: "1.1", created: "2009-03-06"},
		 author: {name: "Logue", homepage: "<http://logue.be/>"},
		 acknowledgement: {name: "shoji", 'homepage': "<http://shoji.blog1.fc2.com/blog-entry-130.html>" },
		 license: "<http://www.gnu.org/licenses/gpl-3.0.html>"
	},
	initialize: function(file,isUnicode) {
		this.clear();
		this.isUnicode = false;
		if (isUnicode) this.isUnicode = true;	// Unicodeフォーマットとする
		if(window.ActiveXObject){
			this.fso = new ActiveXObject("Scripting.FileSystemObject"); // FileSystemObjectを作成
			file = file.replace('file:///','').replace(/\//g,'\\').replace(/%20/g,' ');	// FSOはURL形式を理解できない
		}else if (window.Components){
			netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
			file = file.replace('file:///','').replace(/\//g,'\\').replace(/%20/g,' ');	// XPCOMもURL形式を理解できない
		}else if(window.runtime.flash.filesystem ){
			this.air = window.runtime.flash.filesystem;
		}else{
			alert("Ini: Not supported browser.");
		}
		this.open(file);
	},

	// openメソッド - Iniファイルの読込
	open: function(filename) {
		var ini;
		if( filename != null ) this.filename = filename;
		var stream;
		if (this.fso){
			if (this.fso.FileExists(filename)){
				stream = this.fso.OpenTextFile(filename, 1, false, this.isUnicode).ReadAll(); // ファイルを開く
				ini = stream.split('\n');
			}else{
				alert("Ini: '" + filename + "' is not found.");
			}
		}else if (window.Components){
			// XPCOMワカラネ＼＾０＾／
			var stream = Components.classes['@mozilla.org/network/file-input-stream;1'].createInstance(Components.interfaces.nsIFileInputStream);
			console.log(filename);
			stream.init(filename, 1, 0, false);

			// 行を配列に読み込む
			var line = {}, lines = [], hasmore;
			do {
				hasmore = stream.readLine(line);
				ini.push(line.value); 
			} while(hasmore);

			if(converterStream) converterStream.close();

			stream.close();
		}else if(this.air){
			if( this.air.File.filename.exists){
				var filemode, encording;
				// FSOのエミュレート
				stream = new this.air.FileStream();
				if (this.isUnicode){
					encording = 'utf-16';	// Unicode
				}else{
					encording = this.air.File.systemCharset;	// ANSI
				}
				stream.open(filename, this.air.FileMode.READ);
				stream.readMultiByte(filename.size, encording);
				ini = stream.split(air.File.lineEnding);
				stream.close();
			}else{
				alert("Ini: '" + filename + "' is not found.");
			}
		}
		this.clear();
		
		var section, keyname, value;
		for(var i = 0; i < ini.length; i++ ){
			if (ini[i] && ini[i] != '\n'){
				var line = ini[i].replace(/^[ \t]+/,""); // 先頭の空白は削除
				// 空行ではない
				if( !line.match(/^[ \t]*$/) && !line.match(/^;/)){
					
					if( line.match(/^\[(.+)\]\s*$/) ){
						// セクション行
						section = RegExp.$1;
						this.items[ section ] = []; // セクション行を追加
					} else if( section != null && line.match('=') ) {
						// =で区切って、値名と=の間の空白文字と=と値の間の空白文字を削除し、関数に納める。by Logue
						// コメント行はスキップする。
						//    foo bar  =	blah
						//    ↓
						// 'foo bar'=blah
						var _line = line.split(";");				// 末尾のコメントを削除
						var args = _line[0].split("=");
						keyname = args.shift();
						keyname = keyname.replace(/\s*[\s]$/,'');	// キー名の末尾の空白文字を削除
						keyname = keyname.replace(/^[\s]*[\s]/,'');	// キー名の先頭の空白文字を削除
						value = args.join('=');
						value = value.replace(/^[\s]*[\s]/,'');	// 値の先頭の空白文字を削除
						value = value.replace(/\s*[\s]$/,'');	// 値の末尾の空白文字を削除
						this.items[ section ][ keyname ] = value;
					}
				}
			}
		}

		this.filename = filename;
		ini = null; delete ini;
	},

	// updateメソッド - iniファイルの更新
	// 改良の余地あり。
	update: function(filename) {
		if( filename == null ) filename = this.filename;
		
		var ini;

		try {
			if (this.fso){
				if (this.fso.FileExists(filename)){
					ini = this.fso.OpenTextFile(this.filename,2,true,this.isUnicode)
					for( var sectionname in this.items ){
						ini.WriteLine( '[' + sectionname + ']' );
						for( var keyname in this.items[sectionname] )
							ini.WriteLine( keyname + '\t=\t' + this.items[sectionname][keyname] );
						ini.WriteLine( '' );
					}
					ini.close();
				}else{
					alert("Ini: '" + filename + "' is not found.");
				}
			}else if(this.air){
				var filemode, encording;
				// FSOのエミュレート
				ini = new this.air.FileStream();
				if (this.isUnicode){
					encording = 'utf-16';
				}else{
					encording = this.air.File.systemCharset;
				}
				if( this.air.File.filename.exists){
					ini.open(filename, this.air.FileMode.WRITE);
					ini.writeMultiByte(filename.size, encording);
					for( var sectionname in this.items ){
						ini.writeMultiByte( '[' + sectionname + ']' );
						for( var keyname in this.items[sectionname] )
							ini.writeMultiByte( keyname + '\t=\t' + this.items[sectionname][keyname] );
						ini.writeMultiByte( '' );
					}
					ini.close();
				}else{
					alert("Ini: '" + filename + "' is not found.");
				}
			}else if(window.Components){
				if (filename.exists()) {
					var ini = Components.classes['@mozilla.org/network/file-output-stream;1'].createInstance(Components.interfaces.nsIFileOutputStream);
					ini.init(filename, 2, 0x200, false); // open as "write only"
					for( var sectionname in this.items ){
						ini.push( '[' + sectionname + ']' );
						for( var keyname in this.items[sectionname] ) ini.push(keyname + '\t=\t' + this.items[sectionname][keyname] );
						ini.push( '' );
					}

					var out = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance (Components.interfaces.nsIFileOutputStream);
					out.init (filename, 0x20 | 0x02, 00004, null);
					out.write(tbox.value, tbox.textLength);
					out.close();
				}else{
					alert("Ini: '" + filename + "' is not found.");
				}
			}
			ini = null; delete ini;
		}catch(e){
			console.error(e);
		}
	},

	// clearメソッド - 全削除
	clear: function() {
		try { delete this.items; } catch(e) {}
		this.items = new Array(); // 項目
		this.filename = null; // ファイル名
	},

	// getItemメソッド - 項目の値読み込み
	getItem: function(sectionname, keyname) {
		if( sectionname in this.items )
		if( keyname in this.items[sectionname] )
		return this.items[sectionname][keyname];
		return '';
	},

	// setItemメソッド - 項目の値設定
	setItem: function(sectionname, keyname, value, updateflag) {
		if( updateflag == null ) updateflag = true;
		if( !(sectionname in this.items) )
		this.items[ sectionname ] = new Array();
		this.items[ sectionname ][ keyname ] = value;
		if( updateflag && this.filename!=null ) this.update();
	}
};

// 各コンストラクタ
function Ini(){
	this.initialize.apply(this,arguments);
}
