/***
 * Esta classe exibe balões de mensagens.
 *
 * @author Carlos Alberto Tomatis Loth (catloth@terra.com.br)
 *
 */
var BalloonTooltip = function( )
{
	this._imagesLocation = "/html/js/BalloonTooltip/img";

	// Definição de constantes de posicionamento do balão.
	// As constantes são definidas como múltiplos de dois para que seja possível
	// combinar as constantes através do operador OR.
	this._posTop     = 1;
	this._posMiddle	 = 2;
	this._posBottom  = 4;
	this._posLeft    = 8;
	this._posCenter  = 16;
	this._posRight   = 32;

	// Armazena internamente a posição atual do balão de mensagens relativa ao controle
	// que originou a exibição do balão.
	// Esta variável ajuda a selecionar e posicionar a seta que indica a origem do balão de
	// mensagens.
	// Este campo pode pode ser formado pela combinação OR das constantes de posicionamento
	// definidas anteriormente.
	this._currentPos = 0;

	// Definição do array que contém as imagens que servem para indicar a qual controle
	// originou a mensagem que está sendo exibida no balão de mensagens.
	this._arrows = new Array( new Image( 17, 18 ), new Image( 17, 18 ), new Image( 17, 18 ), new Image( 17, 18 ), new Image( 17, 18 ), new Image( 17, 18 ) );
	this._arrows[ 0 ].src = this._imagesLocation + "/atl.gif";	// Superior esquerdo "|\"
	this._arrows[ 1 ].src = this._imagesLocation + "/atc.gif";	// Superior central  "/\"
	this._arrows[ 2 ].src = this._imagesLocation + "/atr.gif";	// Superior direito  "/|"
	this._arrows[ 3 ].src = this._imagesLocation + "/abl.gif";	// Inferior esquerdo "\|"
	this._arrows[ 4 ].src = this._imagesLocation + "/abc.gif";	// Inferior central  "\/"
	this._arrows[ 5 ].src = this._imagesLocation + "/abr.gif";	// Inferior direito  "\|"

	// Definição do array que contém os ícones que indicam o propósito
	// da mensagem exibida pelo balão.
	this.Icons = new Array( new Image( 16, 16 ), new Image( 16, 16 ), new Image( 16, 16 ), new Image( 16, 16 ), new Image( 18, 18 ), new Image( 18, 18 ) );
	this.Icons[ 0 ].src = this._imagesLocation + "/alert.gif";		// indica um ALERTA
	this.Icons[ 1 ].src = this._imagesLocation + "/critical.gif";	// indica um ERRO
	this.Icons[ 2 ].src = this._imagesLocation + "/info.gif";		// indica uma INFORMAÇÃO
	this.Icons[ 3 ].src = this._imagesLocation + "/question.gif";	// indica um QUESTIONAMENTO
	// Define os botões utilizados para fechar o balão.
	this.Icons[ 4 ].src = this._imagesLocation + "/x0.gif";		// botão normal
	this.Icons[ 5 ].src = this._imagesLocation + "/x1.gif";		// botão com o mouse sobre ele

	// Define o tamanho das imagens que indicam a origem do balão.
	this._arrowWidth = 17;
	this._arrowHeight = 18;

	// Armazena internamente se o navagador é o Internet Explorer.
	// NOTA: Esta verificação é feita a fim de utilizar um artifício para solucionar um bug
	// relacionado ao posicionamento do balão no browser Internet Explorer.
	this._isIE = navigator.userAgent.indexOf( "MSIE" ) > -1;

	// Armazena o HTML base do balão.
	this._HTML =	'	<div id="BalloonTooltip" class="hidden">\n' +
					'		<table id="BalloonTooltip_balloonTooltipTable" class="BalloonTooltip" cellpadding="0" cellspacing="0" border="0">\n' +
					'			<tr>\n' +
					'				<td class="corner"><img src="' + this._imagesLocation + '/tl.gif" width=6" height="6"/></td>\n' +
					'				<td><img id="BalloonTooltip_topBorder" src="' + this._imagesLocation + '/t.gif" height="6" width="1"/></td>\n' +
					'				<td class="corner"><img src="' + this._imagesLocation + '/tr.gif" width="6" height="6"/></td>\n' +
					'			</tr>\n' +
					'			<tr>\n' +
					'				<td><img id="BalloonTooltip_leftBorder" src="' + this._imagesLocation + '/l.gif" height="1" width="6"/></td>\n' +
					'				<td class="bg">\n' +
					'					<table class="content" cellpadding="0" cellspacing="0" border="0">\n' +
					'						<tr>\n' +
					'							<td><img id="BalloonTooltip_icon" width="16" height="16"/></td>\n' +
					'							<td id="BalloonTooltip_title" class="title"></td>\n' +
					'							<td><img src="' + this._imagesLocation + '/x0.gif" width="18" height="18" onclick="balloonTooltip.hide( );" onmouseover="this.src=balloonTooltip.Icons[ 5 ].src;" onmouseout="this.src=balloonTooltip.Icons[ 4 ].src"/></td>\n' +
					'						</tr>\n' +
					'						<tr>\n' +
					'							<td nowrap colspan="3" class="message" id="BalloonTooltip_message"></td>\n' +
					'						</tr>\n' +
					'					</table>\n' +
					'				</td>\n' +
					'				<td><img id="BalloonTooltip_rightBorder" src="' + this._imagesLocation + '/r.gif" height="1" width="6"/></td>\n' +
					'			</tr>\n' +
					'			<tr>\n' +
					'				<td class="corner"><img src="' + this._imagesLocation + '/bl.gif" width="6" height="6"/></td>\n' +
					'				<td><img id="BalloonTooltip_bottomBorder" src="' + this._imagesLocation + '/b.gif" height="6" width="1"/></td>\n' +
					'				<td class="corner"><img src="' + this._imagesLocation + '/br.gif" width="6" height="6"/></td>\n' +
					'			</tr>\n' +
					'		</table>\n' +
					'	</div>\n' +
					'	<img class="hidden" border="0" id="BalloonTooltip_balloonTooltipArrow" width="17" height="18" style="position: absolute; z-index: +1000" />\n';

	// Escreve o HTML base do balão no documento que incluiu este arquivo de script
	document.write( this._HTML );

	// Por praticidade, armazena referências aos principais elementos que compõem 
	// o balão de mensagens
	this._balloonTooltip		= document.getElementById( "BalloonTooltip" );
	this._title					= document.getElementById( "BalloonTooltip_title" );
	this._message				= document.getElementById( "BalloonTooltip_message" );
	this._arrow					= document.getElementById( "BalloonTooltip_balloonTooltipArrow" );
	this._icon					= document.getElementById( "BalloonTooltip_icon" );
	this._balloonTooltipTable	= document.getElementById( "BalloonTooltip_balloonTooltipTable" );

	this._topBorder		= document.getElementById( "BalloonTooltip_topBorder" );
	this._leftBorder	= document.getElementById( "BalloonTooltip_leftBorder" );
	this._rightBorder	= document.getElementById( "BalloonTooltip_rightBorder" );
	this._bottomBorder	= document.getElementById( "BalloonTooltip_bottomBorder" );

	// Armazena o estado atual do balão de mensagens.
	// (true = está visível; false = não está visível)
	this.IsVisible		= false;

	// Armazena internamente o controle ao qual o balão de mensagens
	// se refere.
	this._control		= null;
	
	// Caso o browser seja o Internet Explorer executa as rotinas de sobreposição de objetos 
	// que possuem janela (por exemplo, o controle SELECT, OBJECTS, etc)
	if ( this._isIE )
	{
		// Cria uma máscara utilizando IFRAMES para o balão de mensagens
		this._balloonMask		= this._createBalloonMask( );

		// Para fins de praticidade armazena 
		this._topMask			= document.getElementById( "BalloonTooltip_topMask" );
		this._middleMask		= document.getElementById( "BalloonTooltip_middleMask" );
		this._bottomMask		= document.getElementById( "BalloonTooltip_bottomMask" );

		// Cria as máscaras para as imagens que indicam a origem da mensagem que é
		// exibida pelo balão de mensagens.
		// Cria a máscara superior esquerda
		this._topLeftArrowMask		= this._createWindowedMask(	"10000000000000000-" + 
																"11000000000000000-" +
																"11100000000000000-" +
																"11110000000000000-" +
																"11111000000000000-" +
																"11111100000000000-" +
																"11111110000000000-" +
																"11111111000000000-" +
																"11111111100000000-" +
																"11111111110000000-" +
																"11111111111000000-" +
																"11111111111100000-" +
																"11111111111110000-" +
																"11111111111111000-" +
																"11111111111111100-" +
																"11111111111111110-" +
																"11111111111111111-" +
																"11111111111111111" );
		this._topLeftArrowMask.style.position = "absolute";
		document.body.appendChild( this._topLeftArrowMask );

		// Cria a máscara superior direita
		this._topRightArrowMask		= this._createWindowedMask(	"00000000000000001-" + 
																"00000000000000011-" +
																"00000000000000111-" +
																"00000000000001111-" +
																"00000000000011111-" +
																"00000000000111111-" +
																"00000000001111111-" +
																"00000000011111111-" +
																"00000000111111111-" +
																"00000001111111111-" +
																"00000011111111111-" +
																"00000111111111111-" +
																"00001111111111111-" +
																"00011111111111111-" +
																"00111111111111111-" +
																"01111111111111111-" +
																"11111111111111111-" +
																"11111111111111111" );
		this._topRightArrowMask.style.position = "absolute";
		document.body.appendChild( this._topRightArrowMask );

		// Cria a máscara inferior esquerda
		this._bottomLeftArrowMask	= this._createWindowedMask(	"11111111111111111-" + 
																"11111111111111111-" +
																"11111111111111110-" +
																"11111111111111100-" +
																"11111111111111000-" +
																"11111111111110000-" +
																"11111111111100000-" +
																"11111111111000000-" +
																"11111111110000000-" +
																"11111111100000000-" +
																"11111111000000000-" +
																"11111110000000000-" +
																"11111100000000000-" +
																"11111000000000000-" +
																"11110000000000000-" +
																"11100000000000000-" +
																"11000000000000000-" +
																"10000000000000000" );
		this._bottomLeftArrowMask.style.position = "absolute";
		document.body.appendChild( this._bottomLeftArrowMask );

		// Cria a máscara inferior direita
		this._bottomRightArrowMask	= this._createWindowedMask(	"11111111111111111-" + 
																"11111111111111111-" +
																"01111111111111111-" +
																"00111111111111111-" +
																"00011111111111111-" +
																"00001111111111111-" +
																"00000111111111111-" +
																"00000011111111111-" +
																"00000001111111111-" +
																"00000000111111111-" +
																"00000000011111111-" +
																"00000000001111111-" +
																"00000000000111111-" +
																"00000000000011111-" +
																"00000000000001111-" +
																"00000000000000111-" +
																"00000000000000011-" +
																"00000000000000001" );
		this._bottomRightArrowMask.style.position = "absolute";
		document.body.appendChild( this._bottomRightArrowMask );
	}

	// Define os tratadores de eventos para os eventos que reposicionam o balão
	// de mensagens caso a janela venha a ser redimensionada ou rolada.
	window.onscroll	= this._onPositionChange;
	window.onresize	= this._onPositionChange;

	}

/**
 * Exibe o balão de mensagens.
 * 
 * @param title		Especifica o título do balão de mensagens.
 * @param message	Especifica a mensagem a ser exibida no balão de mensagens.
 * @param icon		Especifica o icone que indicará o propósito do balão de mensagens.
 * @param control	Especifica o controle ao qual a mensagem exibida pelo balão se refere.
 *
 * @remarks	O título do balão de mensagens será exibido em negrito.
 *
 *			As mensagens são exibidas em uma célula de tabela com o atributo NOWRAP, ou seja
 *			as quebras de linha da mensagem devem ser explicitadas através da utilização da 
 *			tag HTML <br/>.
 *
 *			O parâmetro icon deve pertencer ao seguinte intervalo de valores:
 *			0 - Exibe o ícone que indica que o balão está exibindo um ALERTA.	
 *			1 - Exibe o ícone que indica que o balão está exibindo um ERRO.
 *			2 - Exibe o ícone que indica que o balão está exibindo uma INFORMAÇÃO.
 *			3 - Exibe o ícone que indica que o balão está exibindo um QUESTIONAMENTO.
 *
 *			O parâmetro control especifica a qual controle a mensagem exibida pelo balão se refere.
 *			Sendo assim, o balão de mensagens irá se posicionar próximo ao controle, exibindo uma
 *			imagem que aponta para o controle.
 *
 * @author Carlos Alberto Tomatis Loth (catloth@terra.com.br)
 *
 */
BalloonTooltip.prototype.show = function( title, message, icon, control )
{
	// Ajusta o título e o corpo da mensagem
	this._title.innerHTML	= title;
	this._message.innerHTML	= message;

	// Ajusta o ícone que indica o propósito da mensagem
	if ( icon == 0 )
		this._icon.src = this.Icons[ 0 ].src;
	else if ( icon == 1 )
		this._icon.src = this.Icons[ 1 ].src;
	else if ( icon == 2 )
		this._icon.src = this.Icons[ 2 ].src;
	else
		this._icon.src = this.Icons[ 3 ].src;

	// Posiciona o balão próximo ao controle ao qual a mensagem se refere
	this._moveNearControl( control );
	this.IsVisible = true;
}

/**
 * Oculta o balão de mensagens.
 *
 * @author Carlos Alberto Tomatis Loth (catloth@terra.com.br)
 *
 */
BalloonTooltip.prototype.hide = function( )
{
	// Oculta o balão e a seta que aponta para o controle de origem
	this._balloonTooltip.className	= "hidden";
	this._arrow.className			= "hidden";

	this._topBorder.style.width		= 1;
	this._leftBorder.style.height	= 1;
	this._bottomBorder.style.width	= 1;
	this._rightBorder.style.height	= 1;

	// Verifica se está sendo executado dentro do Internet Explorer.
	if ( this._isIE )
	{
		// Oculta a máscara do balão
		this._balloonMask.className = "hidden";

		// Oculta as máscaras para as seta indicadoras de origem
		this._topLeftArrowMask.className		= "hidden";
		this._topRightArrowMask.className		= "hidden";
		this._bottomLeftArrowMask.className		= "hidden";
		this._bottomRightArrowMask.className	= "hidden";

		this._topLeftMask.children[ 0 ].className		= "hidden";
		this._topRightMask.children[ 0 ].className		= "hidden";
		this._bottomLeftMask.children[ 0 ].className	= "hidden";
		this._bottomRightMask.children[ 0 ].className	= "hidden";
	}

	this.IsVisible = false;
}

/**
 * Posiciona o balão de mensagens próximo ao controle especificado por control.
 * 
 * @param control	Especifica o controle próximo ao qual o balão deve se posicionar.
 *
 * @remarks	Este método leva em consideração o espaço disponível ao redor do controle para 
 *			posicionar o balão de mensagens dentro da área visível do navegador. 
 *			Primeiramente, são calculados os espaços acima, abaixo, à esquerda e à direita do 
 *			balão de mensagens. Verticalmente é dada preferência ao posicionamento superior e 
 *			horizontalmente ao posicionamento à esquerda.
 *
 * @todo	Implementar o algoritmo de resolução de conflito caso não haja espaço suficiente nem
 *			acima nem abaixo do controle ao qual a mensagem se refere.
 *
 * @author Carlos Alberto Tomatis Loth (catloth@terra.com.br)
 *
 */
BalloonTooltip.prototype._moveNearControl = function( control )
{
	// Verifica se o controle está definido
	if ( control != null )
	{
		// Oculta o balão de mensagens
		this.hide( );

		// Calcula o espaço acima, à esquerda, à direita e abaixo do controle especificado
		var _spaceTop       = ( this._getAbsoluteTop( control ) - document.body.scrollTop );
		var _spaceLeft      = ( this._getAbsoluteLeft( control ) - document.body.scrollLeft );
		var _spaceRight     = ( document.body.clientWidth + document.body.scrollLeft ) - ( this._getAbsoluteLeft( control ) + control.offsetWidth );
		var _spaceBottom    = ( document.body.clientHeight + document.body.scrollTop ) - ( this._getAbsoluteTop( control ) + control.offsetHeight );

		// Armazena as dimensões atuais do balão (incluindo as dimensões da seta
		// que indica a origem do balão)
		var _balloonWidth   = ( this._balloonTooltipTable.offsetWidth ) + this._arrowWidth;
		var _balloonHeight  = ( this._balloonTooltipTable.offsetHeight ) + this._arrowHeight;

		// Armazenam a posição calculada para o balão de mensagens e para a seta que aponta 
		// para o controle
		var _balloonTop;
		var _balloonLeft;
		var _arrowTop;
		var _arrowLeft;

		this._topBorder.style.width		= this._balloonTooltipTable.offsetWidth - 12;
		this._leftBorder.style.height	= this._balloonTooltipTable.offsetHeight - 12;
		this._bottomBorder.style.width	= this._topBorder.offsetWidth;
		this._rightBorder.style.height	= this._leftBorder.offsetHeight;

		// Armazena a posição do controle ao qual a mensagem se refere
		var _controlTop		= this._getAbsoluteTop( control );
		var _controlLeft	= this._getAbsoluteLeft( control );

		// Apaga o valor anterior de posicionamento do balão de mensagens
		this._currentPos    = 0;

		// Este bloco IF ajusta o posicionamento vertical do balão de mensagens
		// Verifica se há espaço para posicionar o balão acima do controle
		if ( _balloonHeight <= _spaceTop )
		{
			// Calcula a posição vertical para posicionar o balão cima do controle
			_balloonTop	= _controlTop - this._balloonTooltip.offsetHeight - this._arrowHeight;
			_arrowTop	= _controlTop - this._arrowHeight - 1;

			// Armazena que o balão está posicionado acima do controle
			this._currentPos = this._currentPos | this._posTop;
		}
		// Verifica se há espaço para posicionar o balão abaixo do controle
		else if ( _balloonHeight <= _spaceBottom )
		{
			// Calcula a posição vertical para posicionar o balão abaixo do controle
			_balloonTop	= _controlTop + control.offsetHeight + this._arrowHeight;
			_arrowTop	= _controlTop + control.offsetHeight + 1;

			// Armazena que o balão está posicionado abaixo do controle
			this._currentPos = this._currentPos | this._posBottom;
		}
		// Caso contrário, não há espaço nem acima nem abaixo do balão.
		else
		{
			// TODO: Implementar algoritmo de resolução de conflitos no posicionamento vertical
			this._currentPos = this.currentPos | this._posMiddle;
		}

		// Este bloco IF ajusta o posicionamento horizontal do balão de mensagens
		// Verifica se há espaço para posicionar o balão à esquerda do controle
		if ( _balloonWidth <= _spaceLeft )
		{
			// Calcula a posição horizontal para posicionar o balão à esquerda do controle
			_balloonLeft	= _controlLeft - this._balloonTooltip.offsetWidth + this._arrowWidth;
			_arrowLeft		= _controlLeft - this._arrowWidth;

			// Armazena que o balão está posicionado à esquerda do controle
			this._currentPos = this._currentPos | this._posLeft;
		}
		// Verifica se há espaço para posicionar o à direita abaixo do controle
		else if ( _balloonWidth <= _spaceRight )
		{
			// Calcula a posição horizontal para posicionar o balão à direita do controle
			_balloonLeft = _controlLeft + control.offsetWidth - this._arrowWidth;
			_arrowLeft = _controlLeft + control.offsetWidth;

			// Armazena que o balão está posicionado à direita do controle
			this._currentPos = this._currentPos | this._posRight;
		}
		// Caso contrário, não há espaço nem acima nem abaixo do balão.
		else
		{
			// TODO: Implementar algoritmo de resolução de conflitos no posicionamento horizontal
			if ( ( this._currentPos & this._posMiddle ) == this._posMiddle )
			{
			}
			else
			{
				this._currentPos = this._currentPos | this._posCenter;
			}
		}

		// Ajusta a posição vertical do balão e da seta indicadora de origem
		this._balloonTooltip.style.top = _balloonTop;
		this._arrow.style.top = _arrowTop;

		// Ajusta a posição horizontal do balão e da seta indicadora de origem
		this._balloonTooltip.style.left = _balloonLeft;
		this._arrow.style.left = _arrowLeft;

		// Caso esteja sendo executado dentro do browser Internet Explorer
		// chama a rotina de ajuste de posicionamento no eixo z.
		if ( this._isIE )
			this._adjustBalloonMask( );

		// Torna o balão de mensagens visível e exibe a seta indicadora de origem
		this._balloonTooltip.className = "visible";
		this._showArrow( this._currentPos );

		// Armazena internamente o controle ao qual o balão de mensagens se refere
		this._control = control;
	}
}

/**
 * Posiciona a seta que indica a origem do balão de mensagens.
 *
 * @author Carlos Alberto Tomatis Loth (catloth@terra.com.br)
 *
 */
BalloonTooltip.prototype._showArrow = function( pos )
{
	// Verifica se está sendo executado no browser Internet Explorer
	if ( this._isIE )
	{
		// Oculta as máscaras para as seta indicadoras de origem
		this._topLeftArrowMask.className		= "hidden";
		this._topRightArrowMask.className		= "hidden";
		this._bottomLeftArrowMask.className		= "hidden";
		this._bottomRightArrowMask.className	= "hidden";
	}

	// Verifica se o balão de mensagens está posicionado acima do controle
	if ( ( pos & this._posTop ) == this._posTop )
	{
		// Verifica se o balão de mensagens está posicionado à esquerda do controle
		if ( ( pos & this._posLeft ) == this._posLeft )
		{
			// Exibe a seta indicadora de origem que aponta para o canto inferior direito do balão
			this._arrow.src = this._arrows[ 5 ].src;
			
			// Verifica se está sendo executado no browser Internet Explorer
			if ( this._isIE )
			{
				// Posiciona e exibe a máscara da seta que aponta para o canto inferior direito do 
				// balão de mensagens
				this._bottomRightArrowMask.style.top	= this._arrow.offsetTop;
				this._bottomRightArrowMask.style.left	= this._arrow.offsetLeft;
				this._arrow.style.zIndex				= +400000;
				this._bottomRightArrowMask.style.zIndex	= +300000;
				this._bottomRightArrowMask.className	= "visible";
			}
		}
		// Verifica se o balão de mensagens está posicionado no centro do controle
		else if ( ( pos & this._posCenter ) == this._posCenter )
		{
			// Exibe a seta indicadora de origem que aponta para o centro inferior do balão
			this._arrow.src = this._arrows[ 4 ].src;
		}
		// Verifica se o balão de mensagens está posicionado à direita do controle
		else if ( ( pos & this._posRight ) == this._posRight )
		{
			// Exibe a seta indicadora de origem que aponta para o canto inferior esquerdo do balão
			this._arrow.src = this._arrows[ 3 ].src;
			
			// Verifica se está sendo executado no browser Internet Explorer
			if ( this._isIE )
			{
				// Posiciona e exibe a máscara da seta que aponta para o canto inferior esquerdo do 
				// balão de mensagens
				this._bottomLeftArrowMask.style.top		= this._arrow.offsetTop;
				this._bottomLeftArrowMask.style.left	= this._arrow.offsetLeft;
				this._arrow.style.zIndex				= +400000;
				this._bottomLeftArrowMask.style.zIndex	= +300000;
				this._bottomLeftArrowMask.className		= "visible";
			}
		}
	}
	// Verifica se o balão de mensagens está posicionado abaixo do controle
	else if ( ( pos & this._posBottom ) == this._posBottom )
	{
		// Verifica se o balão de mensagens está posicionado à esquerda do controle
		if ( ( pos & this._posLeft ) == this._posLeft )
		{
			// Exibe a seta indicadora de origem que aponta para o canto superior direito do balão
			this._arrow.src = this._arrows[ 2 ].src;

			// Verifica se está sendo executado no browser Internet Explorer
			if ( this._isIE )
			{
				// Posiciona e exibe a máscara da seta que aponta para o canto superior esquerdo do 
				// balão de mensagens
				this._topRightArrowMask.style.top		= this._arrow.offsetTop;
				this._topRightArrowMask.style.left		= this._arrow.offsetLeft;
				this._arrow.style.zIndex				= +400000;
				this._topRightArrowMask.style.zIndex	= +300000;
				this._topRightArrowMask.className		= "visible";
			}
		}
		// Verifica se o balão de mensagens está posicionado no centro do controle
		else if ( ( pos & this._posCenter ) == this._posCenter )
		{
			// Exibe a seta indicadora de origem que aponta para o centro superior do balão
			this._arrow.src = this._arrows[ 1 ].src;
		}
		// Verifica se o balão de mensagens está posicionado à direita do controle
		else if ( ( pos & this._posRight ) == this._posRight )
		{
			// Exibe a seta indicadora de origem que aponta para o canto superior esquerdo do balão
			this._arrow.src = this._arrows[ 0 ].src;

			// Verifica se está sendo executado no browser Internet Explorer
			if ( this._isIE )
			{
				// Posiciona e exibe a máscara da seta que aponta para o canto superior esquerdo do 
				// balão de mensagens
				this._topLeftArrowMask.style.top	= this._arrow.offsetTop;
				this._topLeftArrowMask.style.left	= this._arrow.offsetLeft;
				this._arrow.style.zIndex			= +400000;
				this._topLeftArrowMask.style.zIndex	= +300000;
				this._topLeftArrowMask.className	= "visible";
			}
		}
	}

	// Exibe a seta que indica a origem do balão
	this._arrow.className = "visible";
}

/**
 * Obtém a posição vertical absoluta do elemento especificado por element.
 * 
 * @author Carlos Alberto Tomatis Loth (catloth@terra.com.br)
 *
 */
BalloonTooltip.prototype._getAbsoluteTop = function( element )
{
	// Caso o elemento não possua pai de deslocamento encerra a recursão
	if ( element.offsetParent == null )
		return 0;
	// Caso contrário retorna a soma entre a posição vertical do elemento atual e a 
	// posição vertical do seu pai
	else
		return element.offsetTop + this._getAbsoluteTop( element.offsetParent );
}

/**
 * Obtém a posição horizontal absoluta do elemento especificado por element.
 *
 * @author Carlos Alberto Tomatis Loth (catloth@terra.com.br)
 *
 */
BalloonTooltip.prototype._getAbsoluteLeft = function( element )
{
	// Caso o elemento não possua pai de deslocamento encerra a recursão
	if ( element.offsetParent == null )
		return 0;
	// Caso contrário retorna a soma entre a posição horizontal do elemento atual e a 
	// posição horizontal do seu pai
	else
		return element.offsetLeft + this._getAbsoluteLeft( element.offsetParent );
}

/**
 * Cria uma máscara de IFRAMES para possibilitar a exibição de elementos acima de windowed elements
 *
 * @param mask Um string que codifica a máscara que deve ser criada.
 *
 * @remarks Este método só é utilizado caso esteja sendo executado no browser Internet Explorer
 *			A máscara deve ser especificada utilizando seguinte codificação de matrizes:
 *
 *			linha1-linha2-linha3-...-linhaN
 *
 *			Cada linha deve conter os pixels que devem sobrepor windowed elements no Internet Explorer,
 *			por exemplo, a string "00001-00001-00001-00001-00001" codifica uma máscara 5x5 na qual 
 *			última coluna de pixels deve ser exibida.
 *
 * @author Carlos Alberto Tomatis Loth
 *
 */
BalloonTooltip.prototype._createWindowedMask = function( mask )
{
	// Cria o elemento que table que dará suporte a máscara. 
	var _maskTable = document.createElement( "table" );
	
	// Descodifica a string que especifica a máscara nas linhas de uma matriz
	var _rows = mask.split( "-" );

	// Descodifica as strings que especifica a máscara em colunas de uma matriz
	for ( var i = 0; i < _rows.length; i++ )
		_rows[ i ] = _rows[ i ].split( "" );

	// Especifica os atributos da tabela de suporte à máscara
	_maskTable.cellPadding	= 0;
	_maskTable.cellSpacing	= 0;
	_maskTable.border		= 0;
	_maskTable.style.width	= _rows[ 0 ].length;
	_maskTable.style.height	= _rows.length;
	_maskTable.className	= "hidden";

	var _row;
	var _cell;
	
	// Percorre todas a linhas da máscara
	for ( var i = 0; i < _rows.length; i++ )
	{
		// Para cada linha na máscara é inserida uma linha na tabela de suporte
		_row = _maskTable.insertRow( );

		// Percorre todas as colunas da máscara
		for ( var j = 0; j < _rows[ i ].length; j++ )
		{
			// Para cada coluna da máscara insere uma coluna na tabela de suporte
			_cell = _row.insertCell( );

			// Verifica se o "pixel" atual da máscara deve ser exibido
			if ( _rows[ i ][ j ] == "1" )
			{
				var _contiguosRows = 0;

				// Percorre as linhas restantes da coluna corrente a fim de
				// encontrar "pixels adjcentes" que possam ser unificados em um retângulo
				for ( var k = i; k < _rows.length; k++ )
				{
					// Caso seja encontrado pixels adjacentes.
					if ( _rows[ k ][ j ] == "1" )
					{
						// Remove o "pixel" corrente da matriz máscara e incrementa
						// a altura do retângulo que será criado
						_rows[ k ][ j ] = "0";
						_contiguosRows++;
					}
					// Caso contrário encerra o laço
					else
					{
						break;
					}
				}

				// Se o número de pixels contígüos for maior do que 1
				// expande a coluna atual o número de linhas especificado por contiguosRows
				if ( _contiguosRows > 1 )
					_cell.rowSpan = _contiguosRows;

				// Especifica a largura e a altura da célula da tabela suporte
				_cell.style.width	= "1px";
				_cell.style.height	= "" + _contiguosRows + "px";

				// Cria o IFRAME que funcionará como máscara para windowed elements
				// no browser Internet Explorer
				_cell.innerHTML = '<iframe src="javascript:false" frameBorder="0" scrolling="no" style="width: 1px; height:  ' + _contiguosRows + 'px;"></iframe>';
			}
		}
	}

	// Retorna a tabela de suporte contendo os IFRAMES que formam a máscara especificada por mask
	return _maskTable;
}

/**
 * Cria uma máscara de IFRAMES para o balão de mensagens.
 *
 * @remarks Este método só tem utilizada quando for executado no Internet Explorer
 *
 * @author Carlos Alberto Tomatis Loth (catloth@terra.com.br)
 *
 */
BalloonTooltip.prototype._createBalloonMask = function( )
{
	// Define o código HTML que cria a máscara do balão de mensagens
	var htmlMask =	'<table id="BalloonTooltip_balloonMask" cellpadding="0" cellspacing="0" class="hidden" style="position: absolute">\n' +
					'	<tr>\n' +
					'		<td id="BalloonTooltip_topLeftMask"></td>\n' +
					'		<td><iframe id="BalloonTooltip_topMask" src="javascript:false" scrolling="no" frameBorder="0" style="width: 1px; height: 6px"></iframe></td>\n' +
					'		<td id="BalloonTooltip_topRightMask"></td>\n' +
					'	</tr>\n' +
					'	<tr>\n' +
					'		<td colspan="3"><iframe id="BalloonTooltip_middleMask" src="javascript:false" scrolling="no" frameBorder="0" style="width: 1px; height: 1px"></iframe></td>\n' +
					'	</tr>\n' +
					'	<tr>\n' +
					'		<td id="BalloonTooltip_bottomLeftMask"></td>\n' +
					'		<td><iframe id="BalloonTooltip_bottomMask" src="javascript:false" scrolling="no" frameBorder="0" style="width: 1px; height: 6px"></iframe></td>\n' +
					'		<td id="BalloonTooltip_bottomRightMask"></td>\n' +
					'	</tr>\n' +
					'</table>\n'

	// Escreve a máscara do balão no documento que incluí este arquivo de script
	document.write( htmlMask );

	this._topLeftMask		= document.getElementById( "BalloonTooltip_topLeftMask" );
	this._topRightMask		= document.getElementById( "BalloonTooltip_topRightMask" );
	this._bottomLeftMask	= document.getElementById( "BalloonTooltip_bottomLeftMask" );
	this._bottomRightMask	= document.getElementById( "BalloonTooltip_bottomRightMask" );

	// Cria a máscara para a quina superior esquerda do balão de mensagens
	this._topLeftMask.appendChild( this._createWindowedMask(	"000001-" +
																"000111-" + 
																"001111-" + 
																"011111-" +
																"011111-" + 
																"111111" ) );

	// Cria a máscara para a quina superior direita do balão de mensagens
	this._topRightMask.appendChild( this._createWindowedMask(	"100000-" + 
																"111000-" +
																"111100-" + 
																"111110-" + 
																"111110-" + 
																"111111" ) );

	// Cria a máscara para a quina inferior esquerda do balão de mensagens
	this._bottomLeftMask.appendChild( this._createWindowedMask( "111111-" + 
																"011111-" + 
																"011111-" + 
																"001111-" + 
																"000111-" + 
																"000001" ) );

	// Cria a máscara para a quina inferior direita do balão de mensagens
	this._bottomRightMask.appendChild( this._createWindowedMask("111111-" + 
																"111110-" +
																"111110-" +
																"111100-" + 
																"111000-" + 
																"100000" ) );

	// Retorna o objeto que mascára o balão de mensagens
	return document.getElementById( "BalloonTooltip_balloonMask" );
}

/**
 * Posiciona a máscara do balão de mensagens para que ele possa sobrepor "windowed elements" caso
 * esteja sendo executado no browser Internet Explorer.
 *
 * @author Carlos Alberto Tomatis Loth(catloth@terra.com.br)
 *
 */
BalloonTooltip.prototype._adjustBalloonMask = function( )
{
	// Ajusta o tamanho da submáscara superior do balão de mensagens
	this._topMask.style.width		= this._balloonTooltipTable.offsetWidth - 12;
	this._topMask.style.height		= 6;

	// Ajusta o tamanho da submáscara central do balão de mensagens
	this._middleMask.style.width	= this._balloonTooltipTable.offsetWidth;
	this._middleMask.style.height	= this._balloonTooltipTable.offsetHeight - 12;

	// Ajusta o tamanho da submáscara inferior do balão de mensagens
	this._bottomMask.style.width	= this._balloonTooltipTable.offsetWidth - 12;
	this._bottomMask.style.height	= 6;

	// Ajuta a posição da máscara
	this._balloonMask.style.top		= this._balloonTooltip.offsetTop;
	this._balloonMask.style.left	= this._balloonTooltip.offsetLeft;

	// Ajusta a posição da máscara sobre o eixo z
	this._balloonTooltip.style.zIndex		= "+200000";
	this._balloonMask.style.zIndex			= "+100000";
	this._topLeftMask.style.zIndex			= "+100000";
	this._topRightMask.style.zIndex			= "+100000";
	this._bottomLeftMask.style.zIndex		= "+100000";
	this._bottomRightMask.style.zIndex		= "+100000";

	// Exibe o balão de mensagens
	this._balloonMask.className						= "visible";
	this._topLeftMask.children[ 0 ].className		= "visible";
	this._topRightMask.children[ 0 ].className		= "visible";
	this._bottomLeftMask.children[ 0 ].className	= "visible";
	this._bottomRightMask.children[ 0 ].className	= "visible";
}

BalloonTooltip.prototype._onPositionChange = function( )
{
	if ( this._isVisible )
		this._moveNearControl( this._control );
}

// Instancia uma nova instância da classe BalloonTooltip
var balloonTooltip = new BalloonTooltip( );