/**
 * This file is a part of Javascript ToolKit
 * 
 * Javascript ToolKit is a cross-browser javascript/DOM framework 
 * used to build rich web-based client interfaces with basic controls 
 * (dialog, button, imageButton, ...), complex controls 
 * (htmlEditor, colorChooser, grid, ...) and RPC components.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Copyright (C) 2005 Frédéric LECOINTRE <frederic.lecointre@burnweb.net>
 *
 * $Id: jtkUtilFunction.js,v 1.1 2005/04/07 07:57:48 gabriel_ Exp $ 
 */

/**
 * Modified from original file by Frédéric LECOINTRE  2007/08
 */


// MATH functions -----------------------------------------------------------------------
/**
 * 
 * @param integer i
 * @param integer length
 * @return string
 * @since 1.0.0
 */
Math.intToStringLeadingZero = function (i, length){

	var retval = new String(i);
	
	if (retval.length < length){
		retval = StringRepeat('0', length - retval.length) + retval;
	}//end if
	
	return retval;
}//end function

/**
 * 
 * @param integer i
 * @return string
 * @since 1.0.0
 */
Math.intToHexString = function (i) {
	return Math.intToUnsignedString(Math.parseIntEx(i), 4);
}//end function

/**
 * 
 * @param integer i
 * @return string
 * @since 1.0.0
 */
Math.intToOctalString = function (i) {
	return Math.intToUnsignedString(Math.parseIntEx(i), 3);
}//end function

/**
 * 
 * @param integer i
 * @return string
 * @since 1.0.0
 */
Math.intToBinaryString = function (i) {
	return Math.intToUnsignedString(Math.parseIntEx(i), 1);
}//end function

/**
 * 
 * @param integer i
 * @param integer shift
 * @return string
 * @since 1.0.0
 */
Math.intToUnsignedString = function ( i, shift) {

	i = Math.parseIntEx(i);
	var digits = new Array(
		'0' , '1' , '2' , '3' , '4' , '5' ,
		'6' , '7' , '8' , '9' , 'a' , 'b' ,
		'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
		'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
		'o' , 'p' , 'q' , 'r' , 's' , 't' ,
		'u' , 'v' , 'w' , 'x' , 'y' , 'z'
	    );
		
	var buf = new Array();
	var charPos = 32;
	var radix = 1 << shift;
	var mask = radix - 1;
	
	do { 
		buf[--charPos] = digits[i & mask];
		i >>>= shift;
	} while (i != 0);
	
	return buf.join('');
	
}//end function

/**
 * 
 * @param integer value
 * @param integer low
 * @param integer high
 * @param boolean ne
 * @return boolean
 * @since 1.0.0
 */
Math.inRange = function( value, low, high , ne ) {

	if(high == null)
		high = value +1;
		
	return (ne)? (value > low && value < high) : (value >= low && value <= high);
	
}//end function

/**
 * 
 * @param integer value
 * @param integer low
 * @param integer high
 * @param boolean ne
 * @return integer
 * @since 1.0.0
 */
Math.getInRange = function( value, low, high , ne ) {

	if(high == null)
		high = value +1;
	
	if( ne ){
		value = (value > low)? value  -1: low -1;
		value = (value < high)? value  -1: high -1;
	}//end if
	else{
		value = (value > low)? value : low;
		value = (value < high)? value : high;
	}//end if
	
	return value;
	
}//end function

/**
 * 
 * @param mixed value
 * @return integer
 * @since 1.0.0
 */
Math.parseIntEx = function( value) {
	return ( parseInt(value) || 0 );
}//end function

/**
 * 
 * @param mixed value
 * @return integer
 * @since 1.0.0
 */
Math.parseFloatEx = function( value) {
	return ( parseFloat(value) || 0 );
}//end function

/**
 * 
 * @param mixed value
 * @return boolean
 * @since 1.0.0
 */
Math.isInt = function(value) {

	var type = typeof(value);
	type = type.toLowerCase();
	if( type == 'number'){
		return  (Math.round(value) == value);
	}//end if
	else{
		return NaN;
	}//end else
	
}//end function

// String functions ---------------------------------------------------------------------

/**
 * @param string str
 * @param integer repeat
 * @access public
 * @return string
 * @since 1.0.0
*/
function StringRepeat(str, repeat) {

	var retval = new Array();
	var i = 0;
	
	for(i = 0; i < repeat; i++){
		retval[i] = str;
	}//end for
	
	return retval.join(null);
	
}//end function

/**
 * @param string str
 * @access public
 * @return string
 * @since 1.0.0
*/
function StringToBase64(str) {
	
	var output = "";
	var i = 0;
	var sextet = 0;
	var leftovers = 0;
	var octet = 0;

	for (i=0; i < str.length; i++) {
		octet = str.charCodeAt(i);
		switch( i % 3 ){ // traitement par groupe de trois octets
			case 0: // sextet contient le premier des quatres
				sextet = octet & 0xFC; // conserve les six premiers bits 0xFC = 252 = 11111100
				sextet = sextet >> 2; // decale Ã  droite de deux bits. -> 00xxxxxx
				leftovers = octet & 0x03 ; // conserve les deux derniers bits 0x03 = 3 = 00000011
				
			break;
			case 1: //sextet contient le deuxieme des quatres
				leftovers = leftovers << 4; // decale Ã  gauche de 4 bit -> 00xx0000
				sextet = octet & 0xF0; // conserve les quatres premiers bits 0xF0 = 240 = 11110000
				sextet = sextet >> 4; // decale Ã  droite de 4 bit -> 0000xxxxx
				sextet = leftovers | sextet; //remplace les quatres premiers bits de leftovers par ceux de sextet
				leftovers = octet & 0x0F ; // conserve les quatres derniers bits 0x0F = 15 = 00001111
			break;
			case 2: // sextet contient le troisieme des quatres
				leftovers = leftovers << 2 // decale Ã  gauche de 2 bit -> 00xxxx00
				sextet = octet & 0xC0; // conserve les deux premiers bits 0xC0 = 192 = 11000000
				sextet = sextet >> 6; // decale Ã  droite de 6 bit -> 0000000xx
				sextet = leftovers | sextet; //remplace les quatres bits du centre de leftovers par ceux de sextet
				leftovers = octet & 0x3F; // conserve les six derniers bits 0x3F = 63 = 00111111
					// leftovers contient le quatrieme des quatres
			break;
		}//end switch

		output = output + __base64ToAscii(sextet);
		if( (i % 3) == 2 ) // encode la quatrieme caracteres
			output = output + __base64ToAscii(leftovers);
	}//end for

	switch( str.length % 3 ){ // traitement de fin de chaine
		case 0:// la longeur de la chaine est un multiple de trois. plus rien Ã  faire
		break ;
		case 1: // il reste deux bits en encoder
			leftovers = leftovers << 4 ; // decale Ã  gauche de 4 bit -> xx0000
			output = output + __base64ToAscii(leftovers);
			output = output + "=="; // ajout des caracteres non-traduit de fin de chaines
		break ;
		case 2: // il reste quatres bits Ã  encoder
			leftovers = leftovers << 2 ; // decale Ã  gauche de 2 bit -> xxxx00
			output = output + __base64ToAscii(leftovers);
			output = output + "="; // ajout des caracteres non-traduit de fin de chaines
		break ;
	}//end switch

	return output;
	
}//end function

/**
 * @param string str
 * @access public
 * @return string
 * @since 1.0.0
*/
function Base64ToString(str) {
		
	var output = "";
	var i = 0;
	var x, c, v;
	var shiftreg = 0;

	for (i=0; i < str.length; i++) {
		x = this.__asciiToBase64(str.charCodeAt(i)); // chaque x contient 6 bits

		switch (i % 4){
			case 0: // besoin de 6 bits
				shiftreg = x; // 6 premiers bit du groupe de trois octets
				//continue;
			break;
			case 1: // v contient le code du premier caracteres des trois - besoin de 6 bits d'avant plus deux, reste quatre
				v = shiftreg << 2; //decale Ã  gauche de 2 bit -> xxxxxx00
				c = x >> 4 ; // decale Ã  droite de quatres bit -> 000000xx
				v = v | c; // place les deux derniers bit de c dans v
				shiftreg = x & 0x0F; // conserve les quatres derniers bits 0x0F = 15 = 00001111
			break;
			case 2:// v contient le code du deuxieme caracteres des trois - besoin de 4 bits d'avant plus 4, reste 2
				v = shiftreg << 4; //decale Ã  gauche de 4 bit -> xxxx0000
				c = x >> 2 ; // decale Ã  droite de deux bit -> 0000xxxx
				v = v | c; // place les quatres derniers bit de c dans v
				shiftreg = x & 0x03; // conserve les deux derniers bits 0x03 = 3 = 00000011
			break;
			case 3: // v contient le code du dernier caracteres des trois - besoin de 2 bits d'avant plus 4, reste 0
				v = shiftreg << 6; //decale Ã  gauche de 6 bit -> xx000000
				c = x >> 0 ; // decale Ã  droite de 0 bit -> 00xxxxxx
				v = v | c; // place les six derniers bit de c dans v
				shiftreg = x & 0x00; // ne conserve rien
			break;
		}//end switch
		
		if((i % 4) != 0)
			output = output + String.fromCharCode(v);
			
	}//end for
	
	return output;
	
}//end function

/**
 * @param integer c
 * @access private
 * @return string
 * @since 1.0.0
*/
function __base64ToAscii(c){
	if (0 <= c && c <= 25) // c entre 0 et 25
		return String.fromCharCode(c + 65); // plage de valeur comprise entre 65(A) et 90(Z)
	else if (26 <= c && c <= 51) // c entre 26 et 51
		return String.fromCharCode(c + 71); // plage de valeur comprise entre 97(a) et 122(Z)
	else if (52 <= c && c <= 61) // c entre 52 et 61
		return String.fromCharCode(c - 4); // plage de valeur comprise entre 48(0) et 57(9)
	else if (c == 62)
		return '+';
	else if( c == 63 )
		return '/';
	else
		return String.fromCharCode(0xFF); // impossible
}//end function

/**
 * @param integer i
 * @access private
 * @return integer
 * @since 1.0.0
*/
function __asciiToBase64(i){

	if (65 <= i && i <= 90)
		return i - 65;
	else if (97 <= i && i <= 122)
		return i - 71;
	else if (48 <= i && i <= 57)
		return i + 4;
	else if (i == 43) // +
		return 62;
	else if (i == 47) // /
		return 63;
	else
		return null;
			
}//end function

// Array functions ----------------------------------------------------------------------

/**
 * 
 * @param mixed obj
 * @param array array
 * @return mixed
 * @since 1.0.0
*/
function Array_search (obj, array) {

	var i;
	for(i in array){
		if(array[i] == obj) return i;
	}//end for

	return -1;
	
}//end function

// Date functions ----------------------------------------------------------------------

/**
 * 
 * @param date obj
 * @return string
 * @since 1.0.0
*/
function DateToISO8601(obj){

	var date = new Array();
	var time = new Array();
	var i;
	
	date[0] = Math.intToStringLeadingZero(obj.getYear(), 4);
	date[1] = Math.intToStringLeadingZero(obj.getMonth(), 2);
	date[2] = Math.intToStringLeadingZero(obj.getDate(), 2);

	time[0] = Math.intToStringLeadingZero(obj.getHours(), 2);
	time[1] = Math.intToStringLeadingZero(obj.getMinutes(), 2);
	time[2] = Math.intToStringLeadingZero(obj.getSeconds(), 2);

	return (date.join('') + 'T' + time.join(':'));
	
}//end function
 
/**
 * 
 * @param string isoStr
 * @return date
 * @since 1.0.0
*/
function ISO8601ToDate(isoStr){
	var reg = /^(\d{4})(\d{2})(\d{2})T(\d{2}):(\d{2}):(\d{2})/;
	if(reg.test(isoStr)){
	      return new Date(Math.parseIntEx(RegExp.$1), 
		  					Math.parseIntEx(RegExp.$2) -1, 
							Math.parseIntEx(RegExp.$3), 
							Math.parseIntEx(RegExp.$4), 
							Math.parseIntEx(RegExp.$5), 
							Math.parseIntEx(RegExp.$6));
	}//end if
	
}//end function
