/**
 * Copyright (c) 2008 michiyasu wada
 * http://www.seyself.com/
 * 
 * Distributed under The MIT License.
 * [http://www.opensource.org/licenses/mit-license.php]
 *
 * @author michiyasu wada / michi@seyself.com
 */


/**
 * 使用している JavaScript ライブラリ
 * 
 * [ecl.js]
 * Escape Codec Library: ecl.js (Ver.041208)
 * Copyright (C) http://nurucom-archives.hp.infoseek.co.jp/digital/
 * URL : http://nurucom-archives.hp.infoseek.co.jp/digital/
 * 
 * [deflate.js]
 * Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>
 * Version: 1.0.1
 * URL : http://www.onicos.com/staff/iz/amuse/javascript/expert/
 * 
 * [inflate.js]
 * Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>
 * Version: 1.0.0.1
 * URL : http://www.onicos.com/staff/iz/amuse/javascript/expert/
 *
 */

//________________________________________________________________________________________ Endian
function Endian(){}
Endian.BIG_ENDIAN = "bigEndian";
Endian.LITTLE_ENDIAN = "littleEndian";

//________________________________________________________________________________________ ObjectEncoding
function ObjectEncoding(){}
ObjectEncoding.dynamicPropertyWriter = null;
ObjectEncoding.AMF0 = 0;
ObjectEncoding.AMF3 = 3;
ObjectEncoding.DEFAULT = 3;

//________________________________________________________________________________________ ByteArray

function ByteArray()
{
	var data = "";
	
	this.endian = Endian.BIG_ENDIAN;
	this.objectEncoding = ByteArray.defaultObjectEncoding;
	this.position = 0;
	this.__defineGetter__("length", function(){ return data.length; });
	this.__defineSetter__("length", function( i ){ 
				if( data.length < i ){
					var d = i-data.length;
					this.position = data.length;
					for(var j=0;j<d;j++) this.writeByte(0);
				}
				if( data.length > i ) data = data.substr(0,i);
			});
	this.__defineGetter__("bytesAvailable", function(){ return data.length-this.position; });
	
	
	this.compress = function()
	{
		data = zip_deflate( data );
	}
	this.readBoolean = function()
	{
		return !!(this.readUnsignedByte());
	}
	this.readByte = function()
	{
		if(data.length <= this.position) throw "EOFError: Error #2030: End of file was encountered.";
		var a = data[this.position++].charCodeAt(0)&0xFF;
		if(a&0x80) return -((a^0xFF)+1);
		return a;
	}
	this.readBytes = function(bytes, offset, length)
	{
		offset = offset||0;
		length = length||data.length;
		for(var i=offset;i<length;i++){
			bytes.writeByte( data[i].charCodeAt(0) );
		}
	}
	this.readDouble = function()
	{
		var h = "";
		for(var j=0;j<8;j++){
			var a = this.readUnsignedByte().toString(16);
			if(a.length==1) a = "0"+a;
			h += a;
		}
		var i = Number( "0x"+h );
		var inf = Number("0x"+h.substr(0,2));
		var _nn = Number("0x"+h.substr(2,2));
		if(i==0) return 0;
		if( _nn == 248 && inf == 255 ) return NaN;
		if( inf == 127 ) return Infinity;
		if( inf == 255 ) return -Infinity;
		
		var s = ( i-0x8000000000000000 < 0 ) ? 1 : -1;
		var e = ( ((i*Math.pow(2,-52))>>0) & 0x7FF ) - 1023;
		e = Math.pow(2,e+1);
		var i2 = i.toString(2).split("").reverse().join("");
		var p2 = i2.substr(0,52).split("").reverse().join("");
		p2 = "1"+p2;
		var p = 0;
		for(var j=0;j<53;j++) if(p2[j]=="1") p += Math.pow(2, -j-1 );
		return p * e * s;
	}
	this.readFloat = function()
	{
		var a = this.readUnsignedByte().toString(16);
		var b = this.readUnsignedByte().toString(16);
		var c = this.readUnsignedByte().toString(16);
		var d = this.readUnsignedByte().toString(16);
		if(a.length==1) a = "0"+a;
		if(b.length==1) b = "0"+b;
		if(c.length==1) c = "0"+c;
		if(d.length==1) d = "0"+d;
		var i = Number( "0x"+a+b+c+d );
		var inf = Number("0x"+a);
		var _nn = Number("0x"+b);
		if(i==0) return 0;
		if( _nn == 248 && inf == 255 ) return NaN;
		if( inf == 127 ) return Infinity;
		if( inf == 255 ) return -Infinity;
		
		var s = ( i&0x80000000 ) ? -1 : 1;
		var e = ( (i>>23) & 0xFF ) - 127;
		e = Math.pow(2,e+1);
		var p2 = (i & 0x7FFFFF ).toString(2);
		var _s = "00000000000000000000000";
		p2 = "1"+_s.substr(0, 23-p2.length) + p2;
		var p = 0;
		for(var j=0;j<24;j++) if(p2[j]=="1") p += Math.pow(2, -j-1 );
		return p * e * s;
	}
	this.readInt = function()
	{
		if(data.length < this.position+4) throw "Error: Error #2030: ファイルの終端 (EOF) が検出されました。";
		var a = this.readUnsignedByte().toString(16);
		var b = this.readUnsignedByte().toString(16);
		var c = this.readUnsignedByte().toString(16);
		var d = this.readUnsignedByte().toString(16);
		if(a.length==1) a = "0"+a;
		if(b.length==1) b = "0"+b;
		if(c.length==1) c = "0"+c;
		if(d.length==1) d = "0"+d;
		var i = Number( "0x"+a+b+c+d );
		if( i&0x80000000 ) return -((i^0xFFFFFFFF)+1);
		return i;
	}
	this.readMultiByte = function(length, charSet)
	{
		var s = "";
		for(var i=0;i<length;i++){
			var a = this.readUnsignedByte().toString(16);
			if(a.length==1) a = "0"+a;
			s += "%"+a;
		}
		var res = "";
		charSet = charSet.toLowerCase();
		switch(charSet){
			case "unicode" : 
			case "utf-16" : res = UnescapeUTF16LE(s); break;
			
			case "unicodefffe" : case "utf-16be" : case "utf-16-be" : case "unicode-be" : 
			case "unicodebe" : res = UnescapeUnicode(s); break;
			
			case "utf-7" : case "csunicode11utf7" : case "unicode-1-1-utf-7" : case "x-unicode-2-0-utf-7" : 
			case "utf7" : res = UnescapeUTF7(s); break;
			
			case "utf-8" : case "unicode-1-1-utf-8" : case "unicode-2-0-utf-8" : case "x-unicode-2-0-utf-8" : 
			case "utf8" : res = UnescapeUTF8(s); break;
			
			case "sjis" : case "shift_jis" : case "csshiftjis" : case "cswindows31j" : 
			case "x-ms-cp932" : case "ms_kanji" : case "x-sjis" : 
			case "shift-jis" : res = UnescapeSJIS(s); break;
			
			case "jis" : 
			case "iso-2022-jp" : res = UnescapeJIS8(s); break;
			
			case "euc" : case "cseucpkdfmtjapanese" : 
			case "extended_unix_code_packed_format_for_japanese" : 
			case "x-euc" : case "x-euc-jp" : 
			case "euc-jp" : res = UnescapeEUCJP(s); break;
			
			default : res = window["Unescape"+GetEscapeCodeType(s)](s);
		}
		return res;
	}
	this.readObject = function()
	{
		
	}
	this.readShort = function()
	{
		var a = this.readUnsignedByte().toString(16);
		var b = this.readUnsignedByte().toString(16);
		if(a.length==1) a = "0"+a;
		if(b.length==1) b = "0"+b;
		var i = Number( "0x"+a+b );
		if( i&0x8000 ) return -((i^0xFFFF)+1);
		return i;
	}
	this.readUnsignedByte = function()
	{
		if(data.length <= this.position) throw "EOFError: Error #2030: End of file was encountered.";
		return data[this.position++].charCodeAt(0)&0xFF;
	}
	this.readUnsignedInt = function()
	{
		var a = this.readUnsignedByte().toString(16);
		var b = this.readUnsignedByte().toString(16);
		var c = this.readUnsignedByte().toString(16);
		var d = this.readUnsignedByte().toString(16);
		if(a.length==1) a = "0"+a;
		if(b.length==1) b = "0"+b;
		if(c.length==1) c = "0"+c;
		if(d.length==1) d = "0"+d;
		return Number( "0x"+a+b+c+d );
	}
	this.readUnsignedShort = function()
	{
		var a = this.readUnsignedByte().toString(16);
		var b = this.readUnsignedByte().toString(16);
		if(a.length==1) a = "0"+a;
		if(b.length==1) b = "0"+b;
		return Number( "0x"+a+b );
	}
	this.readUTF = function()
	{
		var s = "";
		var len = data.length;
		for(var i=0;i<len;i++){
			var a = (data[i].charCodeAt(0) & 0xFF).toString(16);
			if(a.length==1) a = "0"+a;
			s += "%"+a;
		}
		return UnescapeUTF8(s);
	}
	this.readUTFBytes = function(length)
	{
		var s = "";
		for(var i=0;i<length;i++){
			var a = this.readUnsignedByte().toString(16);
			if(a.length==1) a = "0"+a;
			s += "%"+a;
		}
		return UnescapeUTF8(s);
	}
	this.uncompress = function()
	{
		data = zip_inflate( data );
	}
	this.writeBoolean = function( bool )
	{
		data += String.fromCharCode(( value ? 1:0));
	}
	this.writeByte = function( i )
	{
		var p = this.position;
		var a = i&0xFF;
		if(a&0x80) a = -((a^0xFF)+1);
		data = data.substr(0,p) + String.fromCharCode( a ) + 
		       data.substr(p+1,data.length-p-1);
		this.position++;
	}
	this.writeBytes = function(bytes, offset, length)
	{
		offset = offset||0;
		length = length||bytes.length;
		bytes.position = offset;
		for(var i=offset;i<length;i++){
			this.writeByte( bytes.readByte() );
		}
	}
	
	var bindec = function( s )
	{
		var a = 0;
		if(s[0]=="1") a += 128;
		if(s[1]=="1") a += 64;
		if(s[2]=="1") a += 32;
		if(s[3]=="1") a += 16;
		if(s[4]=="1") a += 8;
		if(s[5]=="1") a += 4;
		if(s[6]=="1") a += 2;
		if(s[7]=="1") a += 1;
		return a;
	}
	this.writeDouble = function( n )
	{
		if(n==0){
			this.writeByte( 0 ); this.writeByte( 0 );
			this.writeByte( 0 ); this.writeByte( 0 );
			this.writeByte( 0 ); this.writeByte( 0 );
			this.writeByte( 0 ); this.writeByte( 0 );
		} else if(isNaN(n)){
			this.writeByte( 255 ); this.writeByte( 248 );
			this.writeByte( 0 );   this.writeByte( 0 );
			this.writeByte( 0 );   this.writeByte( 0 );
			this.writeByte( 0 );   this.writeByte( 0 );
		} else {
			var s = ( n < 0 ) ? "1" : "0";
			var t = Math.abs(n);
			var i2 = t.toString(2);
			var e = i2.indexOf(".") - 1;
			if(e<0) e = 0;
			var z = "0000000000000000000000000000000000000000000000000000";
			var p = i2.split(".").join("").substr(1,i2.length-1);
			p += z.substr(0,52-p.length);
			e = ((e + 1023) & 0x7FF).toString(2);
			e = z.substr(0,11-e.length) + e;
			var i = s + e + p;
			if(n==Infinity){
				this.writeByte( 127 );
			} else if(n==-Infinity){
				this.writeByte( 255 );
			} else {
				this.writeByte( bindec(i.substr(0 ,8)) );
			}
			this.writeByte( bindec(i.substr(8 ,8)) );
			this.writeByte( bindec(i.substr(16,8)) );
			this.writeByte( bindec(i.substr(24,8)) );
			this.writeByte( bindec(i.substr(32,8)) );
			this.writeByte( bindec(i.substr(40,8)) );
			this.writeByte( bindec(i.substr(48,8)) );
			this.writeByte( bindec(i.substr(56,8)) );
		}
	}
	this.writeFloat = function( n )
	{
		if(n==0){
			this.writeByte( 0 ); this.writeByte( 0 );
			this.writeByte( 0 ); this.writeByte( 0 );
		} else if(isNaN(n)){
			this.writeByte( 255 ); this.writeByte( 248 );
			this.writeByte( 0 );   this.writeByte( 0 );
		} else {
			var s = ( n&0x80000000 ) ? "1" : "0";
			var t = Math.abs(n);
			var i2 = t.toString(2);
			var e = i2.indexOf(".") - 1;
			if(e<0) e = 0;
			var z = "00000000000000000000000";
			var p = i2.split(".").join("").substr(1,i2.length-1);
			p += z.substr(0,23-p.length);
			e = ((e + 127) & 0xFF).toString(2);
			e = z.substr(0,8-e.length) + e;
			var i = s + e + p;
			if(n==Infinity){
				this.writeByte( 127 );
			} else if(n==-Infinity){
				this.writeByte( 255 );
			} else {
				this.writeByte( bindec(i.substr(0 ,8)) );
			}
			this.writeByte( bindec(i.substr(8 ,8)) );
			this.writeByte( bindec(i.substr(16,8)) );
			this.writeByte( bindec(i.substr(24,8)) );
		}
	}
	this.writeInt = function( i )
	{
		i = i>>0;
		if( i&0x80000000 ) i = -((i^0xFFFFFFFF)+1);
		this.writeByte( i>>24 & 0xFF );
		this.writeByte( i>>16 & 0xFF );
		this.writeByte( i>>8  & 0xFF );
		this.writeByte( i     & 0xFF );
	}
	this.writeMultiByte = function( str, charSet )
	{
		
	}
	this.writeObject = function( obj )
	{
		
	}
	this.writeShort = function( i )
	{
		i = i>>0;
		if( i&0x8000 ) i = -((i^0xFFFF)+1);
		this.writeByte( i>>8  & 0xFF );
		this.writeByte( i     & 0xFF );
	}
	this.writeUnsignedInt = function( i )
	{
		i = i>>0;
		if( i&0x80000000 ) i = -((i^0xFFFFFFFF)+1);
		this.writeByte( i>>24 & 0xFF );
		this.writeByte( i>>16 & 0xFF );
		this.writeByte( i>>8  & 0xFF );
		this.writeByte( i     & 0xFF );
	}
	this.writeUTF = function( str )
	{
		var len = data.length;
		data  = String.fromCharCode( len >> 8 );
		data += String.fromCharCode( len & 0xFF );
		data += str.toString();
		
	}
	this.writeUTFBytes = function( str ) 
	{
		data = str.toString();
	}
	this.toString = function()
	{
		var s = "";
		var len = data.length;
		for(var i=0;i<len;i++){
			var a = (data[i].charCodeAt(0) & 0xFF).toString(16);
			if(a.length==1) a = "0"+a;
			s += "%"+a;
		}
		return UnescapeUTF8( s );
	}

}
ByteArray.defaultObjectEncoding = 3;

