//************************************************************
// sprintf.js
//	2004/03/31
//	MW web studio http://homepage1.nifty.com/aok2/
//	aoki makoto <gzl03577@nifty.ne.jp>
//
//	string sprintf ( string i_format [, mixed i_arg1, mixed i_arg2, ...] )
//	string vsprintf( string i_format, array i_args )
//  string hex( number i_num )
//  string oct( number i_num )
//  string bin( number i_num )
//
//	%b		?????
//	%c		???????????????????????
//	%d		??????
//	%e %E	????? ???? 1.234567e+012
//	%f 		????? ???? 123456700000.000000
//	%g %G	%e ??? %f ?????
//	%o		?????
//	%s		?????
//	%x	%X	16????
//
//	????					???
//	sprintf("%08b",   0x34 )	"00110100"
//	sprintf("%c",     0x41 )	"A"
//	sprintf("%+03d",  3    )	"+03"
//	sprintf("%12.3E", 0.345)	"  3.450E-001"
//	sprintf("%12.3f", 0.345)	"       0.345"
//	sprintf("%-9o",   255  )	"377      "
//	sprintf("%-9s",   "ABC")	"ABC      "
//	sprintf("%9s",    "ABC")	"      ABC"
//	sprintf("%04x",   255  )	"00ff"
//	sprintf("%04X",   255  )	"00FF"
//
//	%u       ?????
//	#        ?????
//	??? * ?????
//	???? ?????
//************************************************************

//============================================================
//	string sprintf ( string i_format [, mixed i_arg1, mixed i_arg2, ...] )
//============================================================
function sprintf( i_format )
{
	var args = new Array();
	
	for ( var i = 1; i < sprintf.arguments.length; ++i )
	{
		args[ args.length ] = sprintf.arguments[i];
	}
	return vsprintf( i_format, args );
}

//============================================================
//	string vsprintf ( string i_format, array i_args )
//============================================================
function vsprintf( i_format, i_args )
{
	var src = i_format;
	var	dst = "";
	var left_part, match_part, right_part;
	var flags, width, precision, type;
	
	for( var i = 0; 0 <= src.search(/%([#0 \-\+]*)([1-9]*[0-9]*)([\.][0-9]*|)([%bcdeEfgGoxXs]{1})/);  )
	{
		left_part  = RegExp.leftContext;
		right_part = RegExp.rightContext;
		flags      = RegExp.$1 + '';
		width      = RegExp.$2 + '';
		precision  = RegExp.$3 + '';
		type       = RegExp.$4 + '';

		if ( type == '%' )
		{
			match_part = '%';
		}
		else if( i < i_args.length )
		{
			match_part = _sprintf(flags, width, precision, type, i_args[i]);
			++i;
		}
		else
		{
			match_part = '';
		}
		
		dst += (left_part + match_part);
		src = right_part;
	}
	dst += src;

	return dst;
}

//------------------------------------------------------------
// local function
//------------------------------------------------------------
function _sprintf( i_flags, i_width, i_precision, i_type, i_value )
{
	switch( i_type )
	{
	case 'b':	func = _sprintf_b; break;
	case 'c':	func = _sprintf_c; break;
	case 'd':	func = _sprintf_d; break;

	case 'e':
	case 'E':
	case 'f':
	case 'g':
	case 'G':	func = _sprintf_f; break;
	
	case 'o':	func = _sprintf_o; break;
	case 's':	func = _sprintf_s; break;

	case 'x':
	case 'X':	func = _sprintf_x; break;
	
	default:	return '';
	}

	return func( i_flags, i_width, i_precision, i_type, i_value );
}

//------------------------------------------------------------
// local function
//------------------------------------------------------------
function _sprintf_b( i_flags, i_width, i_precision, i_type, i_value )
{
	// -	??
	// 0	i_precision?????????
	var align;
	var left_pad_char;		// case align=right
	var right_pad_char;		// case align=left
	var pad_len;
	var s;
	
	s = bin( Math.floor(i_value) );

	align          = (0 <= i_flags.search(/\-/)) ? 'left' : 'right';
	left_pad_char  = (0 <= i_flags.search(/0/) && i_precision == '') ? '0' : ' ';
	right_pad_char = ' ';

	if ( i_precision != '' )
	{
		s = (s == '0') ? '' : s;
		
		pad_len = Number(i_precision.substr(1)) - s.length;
		if ( 0 < pad_len )
		{
			s = str_repeat('0', pad_len) + s;
		}
	}

	if( i_width != '' )
	{
		pad_len = Number(i_width) - s.length;
		if( 0 < pad_len )
		{
			if ( align == 'left' )
			{
				s = s + str_repeat(right_pad_char, pad_len);
			}
			else
			{
				s = str_repeat(left_pad_char, pad_len) + s;
			}
		}
	}

	return s;
}

//------------------------------------------------------------
// local function
//------------------------------------------------------------
function _sprintf_c( i_flags, i_width, i_precision, i_type, i_value )
{
	var align;
	var pad_len;
	var right_pad_char;
	var left_pad_char;
	var s;

	s = '';
	s = String.fromCharCode( Number(i_value) );

	align          = (0 <= i_flags.search(/\-/)) ? 'left' : 'right';
	left_pad_char  = (0 <= i_flags.search(/0/) ) ? '0' : ' ';
	right_pad_char = ' ';

	if( i_width != '' )
	{
		pad_len = Number(i_width) - strlen_b(s);
		if( 0 < pad_len )
		{
			if ( align == 'left' )
			{
				s = s + str_repeat(right_pad_char, pad_len);
			}
			else
			{
				s = str_repeat(left_pad_char, pad_len) + s;
			}
		}
	}

	return s;
}

//------------------------------------------------------------
// local function
//------------------------------------------------------------
function _sprintf_d( i_flags, i_width, i_precision, i_type, i_value )
{
	var align;
	var left_pad_char;		// case align=right
	var right_pad_char;		// case align=left
	var pad_len;
	var sign;
	var s;

	s = String(Math.floor(Math.abs( i_value )));

	align          = (0 <= i_flags.search(/\-/)) ? 'left' : 'right';
	left_pad_char  = (0 <= i_flags.search(/0/) && i_precision == '') ? '0' : ' ';
	right_pad_char = ' ';

	if ( i_precision != '' )
	{
		s = (s == '0') ? '' : s;
		
		pad_len = Number(i_precision.substr(1)) - s.length;
		if ( 0 < pad_len )
		{
			s = str_repeat('0', pad_len) + s;
		}
	}

	if( i_flags.search(/\+/) >= 0 )
	{
		sign = ( i_value >= 0 ) ? '+' : '-';
	}
	else if( i_flags.search(/ /) >= 0 )
	{
		sign = ( i_value >= 0 ) ? ' ' : '-';
	}
	else
	{
		sign = ( i_value >= 0 ) ? '' : '-';
	}

	if( i_width != '' )
	{
		pad_len = Number(i_width) - sign.length - s.length;
		if( 0 < pad_len )
		{
			if ( align == 'left' )
			{
				s = sign + s + str_repeat(right_pad_char, pad_len);
			}
			else if ( left_pad_char == '0' )
			{
				// "+0000123"
				s = sign + str_repeat(left_pad_char, pad_len) + s;
			}
			else
			{
				// "    +123"
				s = str_repeat(left_pad_char, pad_len) + sign + s;
			}
		}
		else
		{
			s = sign + s;
		}
	}
	else
	{
		s = sign + s;
	}
	
	return s;
}

//------------------------------------------------------------
// local function
//------------------------------------------------------------
function _sprintf_f( i_flags, i_width, i_precision, i_type, i_value )
{
	var precision;
	var s = '';
	var num_l, num_r, num_e;
	var sign
	var point;

	precision = (i_precision == '') ? 6 : Number(i_precision.substr(1));

	var arr = __float( i_value, i_type );
	num_l = arr[0];
	num_r = arr[1];
	num_e = arr[2];

	if ( num_r.length <= precision )
	{
		num_r += str_repeat('0', precision);
		num_r = num_r.substr(0, precision);
	}
	else
	{
		var n = num_r.length - precision;
		num_r = parseFloat( num_r );
		for ( ; 0 < n; --n )
		{
			num_r /= 10.0;
		}
		num_r = Math.round( num_r );
		num_r = String( num_r );
		num_r = str_repeat('0', precision) + num_r;
		num_r = num_r.substr( num_r.length - precision );
	}

	     if( i_flags.search(/\+/) >= 0 ){ sign = ( i_value >= 0 ) ? '+' : '-';	}
	else if( i_flags.search(/ / ) >= 0 ){ sign = ( i_value >= 0 ) ? ' ' : '-';	}
	else	                            { sign = ( i_value >= 0 ) ? ''  : '-';	}

	     if( i_flags.search(/#/) >= 0            ) { point = '.'; }
	else if( precision == 0 || num_r.length == 0 ) { point = '';  }
	else                                           { point = '.'; }

	if ( num_e != '' )
	{
		switch ( i_type )
		{
		case 'e':
		case 'g':
			num_e = 'e' + num_e;
			break;
		
		case 'E':
		case 'G':
			num_e = 'E' + num_e;
			break;
		}
	}
	
	var s = num_l + point + num_r + num_e;

	if ( i_width != '' )
	{
		var pad_len = Number(i_width) - (sign.length + s.length);
		if( 0 < pad_len )
		{
			if( i_flags.search(/\-/) >= 0 )
			{
				s = sign + s + str_repeat(' ', pad_len);
			}
			else
			{
				if( i_flags.search(/0/) >= 0 )
				{
					s = sign + str_repeat('0', pad_len) + s;
				}
				else
				{
					s = str_repeat(' ', pad_len) + sign + s;
				}
			}
		}
		else
		{
			s = sign + s;
		}
	}
	else
	{
		s = sign + s;
	}

	return s;
}

function __float( i_value, i_type )
{
	var num_l, num_r, num_e;

	(i_value.toString()).search( /([+\-]*)([0-9]*)([\.]*)([0-9]*)([Ee]*)([+\-]*[0-9]*)/ );
	num_l = RegExp.$2;
	num_r = RegExp.$4;
	num_e = RegExp.$6;

	switch ( i_type )
	{
	case 'g':
	case 'G':
		if ( num_e != '' )
		{
			num_e = sprintf("%+04d", num_e);
		}
		break;
		
	case 'e':
	case 'E':
		if ( num_e == '' )
		{
			num_e = 0;
			if ( 1 < num_l.length )
			{
				// 12345.67    --> 1.234567 e+04
				num_e = num_l.length - 1;
				num_r = num_l.substr(1) + num_r;
				num_l = num_l.substr(0,1);
			}
			else if ( num_l.length == 1 && num_l != '0' )
			{
				// 1.????
				// do nothing
			}
			else 
			{
				//  .00001234  ---> 1.234   e-05
				// 0.00123455  ---> 1.23455 e-03
				var n = num_r.search( /([1-9][0-9]*)$/ );
				if ( 0 <= n )
				{
					num_l = num_r.substr( n, 1 );
					num_r = num_r.substr( n + 1 );
					num_e = -(n + 1);
				}
			}
		}
		else
		{
			num_e = Number(num_e);
		}
		num_e = sprintf("%+04d", num_e);
		break;
		
	case 'f':
		if ( num_e != '' )
		{
			num_e = Number(num_e);
			if ( 0 < num_e )
			{
				if ( num_e <= num_r.length )
				{
					num_l += num_r.substr(0, num_e);
					num_r =  num_r.substr(num_e);
				}
				else
				{
					num_l += num_r;
					num_e -= num_r.length;
					num_r = "";
					num_l += str_repeat('0', num_e);
				}
			}
			else if ( num_e < 0 )
			{
				num_e = Math.abs(num_e);
				if ( num_e <= num_l.length )
				{
					num_r = num_l.substr(num_l.length - num_e) + num_r;
					num_l = num_l.substr(0, num_l.length - num_e);
				}
				else
				{
					num_r =  num_l + num_r;
					num_e -= num_l.length;
					num_l = "";
					num_r = str_repeat('0', num_e) + num_r;
				}
				if ( num_l == '' )
				{
					num_l = '0';
				}
			}
			num_e = '';
		}
		break;
		
	default:
		break;
	}
	
	return  new Array( num_l, num_r, num_e );
}

//------------------------------------------------------------
// local function
//------------------------------------------------------------
function _sprintf_o( i_flags, i_width, i_precision, i_type, i_value )
{
	// -	??
	// 0	i_precision?????????
	var align;
	var left_pad_char;		// case align=right
	var right_pad_char;		// case align=left
	var pad_len;
	var s;
	
	s = oct( Math.floor(i_value) );

	align          = (0 <= i_flags.search(/\-/)) ? 'left' : 'right';
	left_pad_char  = (0 <= i_flags.search(/0/) && i_precision == '') ? '0' : ' ';
	right_pad_char = ' ';

	if ( i_precision != '' )
	{
		s = (s == '0') ? '' : s;
		
		pad_len = Number(i_precision.substr(1)) - s.length;
		if ( 0 < pad_len )
		{
			s = str_repeat('0', pad_len) + s;
		}
	}

	if ( i_width != '' )
	{
		pad_len = Number(i_width) - s.length;
		if( 0 < pad_len )
		{
			if ( align == 'left' )
			{
				s = s + str_repeat(right_pad_char, pad_len);
			}
			else
			{
				s = str_repeat(left_pad_char, pad_len) + s;
			}
		}
	}

	return s;
}

//------------------------------------------------------------
// local function
//------------------------------------------------------------
function _sprintf_s( i_flags, i_width, i_precision, i_type, i_value )
{
	var align;
	var left_pad_char;		// case align=right
	var right_pad_char;		// case align=left
	var pad_len;
	var s;
	
	
	s = String(i_value);

	align          = (0 <= i_flags.search(/\-/)) ? 'left' : 'right';
	left_pad_char  = (0 <= i_flags.search(/0/) ) ? '0' : ' ';
	right_pad_char = ' ';

	if( i_precision != '' )
	{
		s = substr_b( s, 0, Number(i_precision.substr(1)) );
	}

	if( i_width != '' )
	{
		pad_len = Number(i_width) - strlen_b(s);
		if( 0 < pad_len )
		{
			if ( align == 'left' )
			{
				s = s + str_repeat(right_pad_char, pad_len);
			}
			else
			{
				s = str_repeat(left_pad_char, pad_len) + s;
			}
		}
	}

	return s;
}

//------------------------------------------------------------
// local function
//------------------------------------------------------------
function _sprintf_x( i_flags, i_width, i_precision, i_type, i_value )
{
	// -	??
	// 0	i_precision?????????
	var align;
	var left_pad_char;		// case align=right
	var right_pad_char;		// case align=left
	var pad_len;
	var s;
	
	s = '';
	s = hex( Math.floor(i_value) );
	s = (i_type == 'X') ? s.toUpperCase() : s.toLowerCase();

	align          = (0 <= i_flags.search(/\-/)) ? 'left' : 'right';
	left_pad_char  = (0 <= i_flags.search(/0/) && i_precision == '') ? '0' : ' ';
	right_pad_char = ' ';

	if ( i_precision != '' )
	{
		s = (s == '0') ? '' : s;
		
		pad_len = Number(i_precision.substr(1)) - s.length;
		if ( 0 < pad_len )
		{
			s = str_repeat('0', pad_len) + s;
		}
	}

	if( i_width != '' )
	{
		pad_len = Number(i_width) - s.length;
		if( 0 < pad_len )
		{
			if ( align == 'left' )
			{
				s = s + str_repeat(right_pad_char, pad_len);
			}
			else
			{
				s = str_repeat(left_pad_char, pad_len) + s;
			}
		}
	}

	return s;
}

//============================================================
// string hex( number i_num )
//============================================================
function hex( i_num )
{
	var num  = Number(i_num);
	var str  = '';
	
	//----------------------------------------
	// ??????????????????????????????
	// 0xF0FFFFFF >> 4	--> 0xFF0FFFFF
	// ??????????????????????????????????
	//----------------------------------------
	var mask = 0xF;
	
	do {
		str = "0123456789ABCDEF".substr((num & 0xF), 1) + str;
		num  >>= 4;
		mask <<= 4;
		
	} while( num != 0 && mask != 0 )

	return str;
}


//============================================================
// string oct( number i_num )
//============================================================
function oct( i_num )
{
	var bin_str;
	var str;
	var s, e;
	
	bin_str = bin( i_num );
		
	if ( bin_str.length < 3 )
	{
		e = bin_str.length;
	}
	else
	{
		e = bin_str.length % 3;
		if ( e == 0 ) e = 3;
	}
	
	
	str = '';
	for ( s = 0; s < bin_str.length; s = e, e += 3 )
	{
		buf = bin_str.substring(s, e);
		buf = bin2oct( buf );
		str += buf;
	}
	
	return str;
	
	
	function bin2oct( i_bin_str )
	{
		var chr;
		var bin;
		var mask;
		var num;
		
		num  = 0;
		mask = 1;
		for ( var i = i_bin_str.length - 1; 0 <= i; --i )
		{
			chr = i_bin_str.substr(i,1);
			bin = Number(chr);
			
			num += (mask * bin);
			mask <<= 1;
		}
		
		return String(num);
	}
}


//============================================================
// string bin( number i_num )
//============================================================
function bin( i_num )
{
	var num  = Number(i_num);
	var str  = '';
	
	//----------------------------------------
	// ??????????????????????????????
	// ???hex()
	//----------------------------------------
	var mask = 0x1;
	
	do {
		str = String(num & 0x1) + str;
		num  >>= 1;
		mask <<= 1;
		
	} while( num != 0 && mask != 0 )

	return str;
}


function str_repeat( i_str, i_repeat )
{
	var arr = new Array();
	
	for ( var i = i_repeat; i > 0; --i )
	{
		arr[ arr.length ] = i_str;
	}
	
	return arr.join('');
}


function strlen_b( i_str )
{
	var len;
	
	len = 0;
	for ( var i = 0; i < i_str.length; ++i )
	{
		if ( i_str.charCodeAt(i) < 0x100 )
		{
			len++;
		}
		else
		{
			len += 2;
		}
	}
	
	return len;
}

function substr_b( i_str, i_pos, i_len )
{
	var type_arr = new Array();
	var char_arr = new Array();
	var s;
	
	for ( var i = 0; i < i_str.length; ++i )
	{
		if ( i_str.charCodeAt(i) < 0x100 )
		{
			// ascii
			type_arr[ type_arr.length ] = 0;
			char_arr[ char_arr.length ] = i_str.substr(i,1);
		}
		else
		{
			// multibyte 1st
			type_arr[ type_arr.length ] = 1;
			char_arr[ char_arr.length ] = i_str.substr(i,1);
			
			// multibyte 2nd
			type_arr[ type_arr.length ] = 2;
			char_arr[ char_arr.length ] = i_str.substr(i,1);
		}
	}
	
	type_arr = type_arr.slice( i_pos, i_len );
	char_arr = char_arr.slice( i_pos, i_len );
	
	if ( 0 < type_arr.length )
	{
		// ??????????????????
		if ( type_arr[0] == 2 )
		{
			type_arr[0] = 0;
			char_arr[0] = ' ';
		}
		if ( type_arr[type_arr.length - 1] == 1 )
		{
			type_arr[type_arr.length - 1] = 0;
			char_arr[char_arr.length - 1] = ' ';
		}
	}
	
	s = '';
	for ( var i = 0; i < type_arr.length; ++i )
	{
		if ( type_arr[i] == 0 ||  type_arr[i] == 1 )
		{
			s += char_arr[i];
		}
	}
	
	return s;
}

