function HintBalloon(control_id, content, class_name, width, height) {

// PROPERTIES:
	this.errorOccurred = false;
	this.errorReport = "";

	this.control_id = control_id;
	this.content = content;
	this.class_name = class_name;
	this.width =  width;
	this.height = height;

	this.container = new Object();
	this.control = new Object();

	this.mouse_x;
	this.mouse_y;


	
// INIT SECTION:

	this.Init = function() {
		this.CheckDOM();
		if (this.errorOccurred) return this.errorReport;

		this.CheckParameters();
		if (this.errorOccurred) return this.errorReport;

		this.GetHintControl();
		if (this.errorOccurred) return this.errorReport;

		this.RenderHintContainer();
		this.AttachToHintControl();
	}

	this.CheckDOM = function() {
		this.errorOccurred = !(document.getElementById && document.createTextNode) ? true : false;
		if (this.errorOccurred) {
			this.errorReport = "The browser does not support DOM";
		}		
		return this.errorReport;
	}

	this.CheckParameters = function() {
		if (typeof(this.control_id) == "undefined") {
			this.errorOccurred = true;
			this.errorReport = "The control id is not given";
			return this.errorReport;
		}		

		if (typeof(this.content) == "undefined" || this.content.length == 0) {
			this.errorOccurred = true;
			this.errorReport = "The hint content is not given";
			return this.errorReport;
		}

		if (typeof(this.class_name) == "undefined" || this.class_name.length == 0) {
			this.errorOccurred = true;
			this.errorReport = "The hint class name is not given";
			return this.errorReport;
		}
	}

	this.GetHintControl = function() {
		this.control = document.getElementById(this.control_id);
		this.errorOccurred = (this.control) ? false : true;
		if (this.errorOccurred)	{
			this.errorReport = "Unable to retrieve the object to which the hint is to be attached";
			return this.errorReport;
		}
	}

	this.RenderHintContainer = function() {
		this.container = document.createElement('div');
		this.container.appendChild(document.createTextNode(this.content));
				
		this.container.className = this.class_name;
		this.container.style.position = "absolute";
		this.container.style.visibility = "hidden";

		if (typeof(this.width) != "undefined" && typeof(this.height) != "undefined") {
			this.container.style.width = this.width;
			this.container.style.height = this.height;
		}

		if (!this.control.parentNode.appendChild(this.container)) {
			this.errorOccurred = true;
			this.errorReport = "Unable to render a hint container";
			return this.errorReport;
		}

		this.SetPosition(0, 0);
	}

	this.AttachToHintControl = function() {
		this.control.HintBalloon = this;
		
		this.control.onmouseover = function(event) {
			if (this.HintBalloon.errorOccurred) return false;
			this.HintBalloon.SetMousePosition(event);
			this.HintBalloon.Show();
		}
		
		this.control.onmouseout = function(event) {
			if (this.HintBalloon.errorOccurred) return false;
			this.HintBalloon.SetMousePosition(event);
			this.HintBalloon.Hide();
		}
		
		this.control.onmousemove = function(event) {
			if (this.HintBalloon.errorOccurred) return false;
			this.HintBalloon.SetMousePosition(event);
			this.HintBalloon.Move(); 
		}
	}


// INNER METHODS:

	this.SetMousePosition = function(event) {
		if (event) {
			this.mouse_x = event.pageX;		
			this.mouse_y = event.pageY;		
			window.routeEvent(event);
		}
	}

	this.GetMouseX = function() {
		if (window.event || this.mouse_x) {
			return (window.event ? window.event.x + this.GetWinLeft() : this.mouse_x);
		}
		else {
			this.errorOccurred = true;
			this.errorReport = "Unable to retrieve mouse x coordinate";
			return 0;
		}
	}

	this.GetMouseY = function() {
		if (window.event || this.mouse_y) {
			return (window.event ? window.event.y + this.GetWinTop() : this.mouse_y);
		}
		else {
			this.errorOccurred = true;
			this.errorReport = "Unable to retrieve mouse y coordinate";
			return 0;
		}
	}

	
	this.GetWinLeft = function() {
		return document.getElementsByTagName('body')[0].scrollLeft;
	}
	
	this.GetWinRight = function() {
		return document.getElementsByTagName('body')[0].clientWidth;
	}

	this.GetWinTop = function() {
		return document.getElementsByTagName('body')[0].scrollTop;
	}
	
	this.GetWinBottom = function() {
		return this.GetWinTop() + document.getElementsByTagName('body')[0].clientHeight;
	}


	this.SetPosition = function(x, y) {
		this.container.style.left = x;
		this.container.style.top = y;
	}



// PUBLIC METHODS:	
	
	this.Show = function() {
		var curX = this.GetMouseX() + 10;
		if (this.errorOccurred) return false;

		var curY = this.GetMouseY() + 10;
		if (this.errorOccurred) return false;

		if (typeof(this.width) != "undefined" && typeof(this.height) != "undefined") {
			var winLeft = this.GetWinLeft();
			var winRight = this.GetWinRight();
			var winTop = this.GetWinTop();
			var winBottom = this.GetWinBottom();

			var right_x = curX + this.width;
			var right_y = curY + this.height;
				
			if (right_y > winBottom)	{
				curY = (winBottom - this.height > winTop) ? winBottom - this.height : winTop;			
			}

			if (right_x > winRight && curY > this.GetMouseY()) {
				curX = (winRight - this.width > winLeft) ? winRight - this.width : winLeft;
			}
		}

		this.SetPosition(curX, curY);
		this.container.style.visibility = "visible";
	}


	this.Hide = function() {
		this.container.style.visibility = "hidden";
		this.SetPosition(0, 0);
	}


	this.Move = function() {
		this.Hide();		
		this.Show();		
	}



// INIT:

	this.Init();

}
