var hintManager =
{
	types:
	{
		none: 0,
		generic: 1,
		textBox: 2,
		dropDownList: 3
	},

	activeHint: null,
	defaultHint: null,

	arIDMapping: new Hashtable(),
	arTextEditorMapping: new Hashtable(),

	blnExecuteDocumentMouseDown: false,
	blnLabelMouseMouseDown: false,
	
	container: null,
	parentTD: null,
	scrollingContent: false,

	initialize: function()
	{
		var mouseDownFunction = new Function("event", "hintManager.documentMouseDown()");
		S.Event.add(document, "mousedown", mouseDownFunction);
		
		this.arIDMapping.each(function(key, value)
		{
		    if (!(value instanceof DefaultHint))
		    {
			    value.bindEvents();
		    }
		});
		
		// Window resize and scroll handling.
		if (document.documentElement)
		{
		    this.parentTD = S.GetParentByTagName("td", this.container);
		    S.Event.add(window, "resize", this.windowResize.bind(this));
		    S.Event.add(window, "scroll", this.windowScroll.bind(this));
		    this.initializeScroll();
		}
	},
	
	initializeScroll: function()
	{
	    this.scrollingContent = (document.documentElement.scrollHeight != document.documentElement.clientHeight);
	},
	
	windowResize: function(e)
	{
	    this.windowScroll(e);
	},
	
	windowScroll: function(e)
	{
	    if (this.scrollingContent)
	    {
	        var position = S.Element.getPosition(this.container);
	        
	        if (position.y < (document.documentElement.scrollTop + 15))
	            this.container.style.paddingTop = (document.documentElement.scrollTop - position.y + 15) + "px";
	        else
	            this.container.style.paddingTop = "0px";
	    }
	    else
	    {
	        this.container.style.paddingTop = "0px";
	    }
	},

	documentMouseDown: function(e)
	{
		if (!this.blnExecuteDocumentMouseDown)
		{
			this.blnExecuteDocumentMouseDown = true;
			return;
		}
		
		if (this.defaultHint != null)
		{
			this.defaultHint.showHint();
		}

		if (this.activeHint != null)
		{
			this.activeHint.hideHint();
			this.activeHint = null;
		}

		this.blnExecuteDocumentMouseDown = false;
	},
	
	displaySubmithint: function(ID)
	{
	    var hint = this.arIDMapping.get(ID);
	    
	    if (this.defaultHint != null)
		{
			this.defaultHint.hideHint();
		}

		if (this.activeHint != null)
		{
			this.activeHint.hideHint();
		}
		
		this.setHint(null, hint.strID);
		hint.showHint();
	},
	
	handleTinyMCEEvent: function(tinyMCEEvent, textEditorID)
	{
	    if (tinyMCEEvent.type == "click")
	    {
	        var hint = this.arTextEditorMapping.get(textEditorID);
	        
	        if (hint != null)
	            this.setHint(null, hint.strID);
	    }
	},

	mouseDown: function(e)
	{
		this.blnExecuteDocumentMouseDown = false;
	},
	
	labelMouseDown: function(e)
	{
	    this.blnLabelMouseMouseDown = true;
	},

	add: function(hint)
	{
		if (hint instanceof DefaultHint)
		{
			this.defaultHint = hint;
		}
		
		if (hint instanceof TextEditorHint)
		{
		    this.arTextEditorMapping.set(hint.textEditorID, hint);
		}

		this.arIDMapping.set(hint.strID, hint);
	},

	showHint: function(event, hintID)
	{
		var hint = this.arIDMapping.get(hintID);

		if (hint != null)
		{
			hint.showHint();
		}

		if (this.defaultHint != null)
		{
			this.defaultHint.hideHint();
		}

		if (this.activeHint != null && this.activeHint != hint)
		{
			this.activeHint.hideHint();
		}
	},

	hideHint: function(event, hintID)
	{
		var hint = this.arIDMapping.get(hintID);

		if (hint != null && hint != this.activeHint)
		{
			hint.hideHint();
		}

		if (this.activeHint != null)
		{
			this.activeHint.showHint();
		}
		else if (this.defaultHint != null)
		{
			this.defaultHint.showHint();
		}
	},

	setHint: function(event, hintID)
	{
		var hint = this.arIDMapping.get(hintID);
		
		if (this.activeHint != null && this.activeHint != hint)
		{
			this.activeHint.hideHint();
		}

		if (hint != null)
		{
			this.activeHint = hint;
			this.activeHint.showHint();
		}
		
		if (this.defaultHint != null)
	    {
		    this.defaultHint.hideHint();
	    }
	},

	unSetHint: function(event, hintID)
	{
	    if (!this.blnLabelMouseMouseDown)
	    {
		    if (this.activeHint != null)
		    {
			    this.activeHint.hideHint();
		    }
    		
		    this.activeHint = null;
		    
		    if (this.defaultHint != null)
		    {
			    this.defaultHint.showHint();
		    }
		}
		
		this.blnLabelMouseMouseDown = false;
	}
};

S.Event.add(window, "load", hintManager.initialize.bind(hintManager));

function Hint(hintDivID)
{
	this.strID = hintDivID;
	this.hintDivID = hintDivID;

	this.hintDiv = S.Get(this.hintDivID);

	this.eventFunctions =
	{
		showHint: new Function("event", "hintManager.showHint(event, '" + this.strID + "')"),
		hideHint: new Function("event", "hintManager.hideHint(event, '" + this.strID + "')"),
		setHint: new Function("event", "hintManager.setHint(event, '" + this.strID + "')"),
		unSetHint: new Function("event", "hintManager.unSetHint(event, '" + this.strID + "')"),
		mouseDown: new Function("event", "hintManager.mouseDown(event, '" + this.strID + "')"),
		labelMouseDown: new Function("event", "hintManager.labelMouseDown(event, '" + this.strID + "')")
	}
}

Hint.prototype.bindEvents = function() { }

Hint.prototype.showHint = function()
{
	this.hintDiv.style.display = "block";
}

Hint.prototype.hideHint = function()
{
	this.hintDiv.style.display = "none";
}

function DefaultHint(hintDivID)
{
	this.base = Hint;
	this.base(hintDivID);
}
DefaultHint.prototype = new Hint;

DefaultHint.prototype.bindEvents = function() { }

function SubmitHint(hintDivID)
{
	this.base = Hint;
	this.base(hintDivID);
}
SubmitHint.prototype = new Hint;

SubmitHint.prototype.bindEvents = function() { }

function TextBoxHint(hintDivID, textBoxHtmlElementID)
{
	this.base = Hint;
	this.base(hintDivID);

	this.textBoxHtmlElementID = textBoxHtmlElementID;
	this.textBoxHtmlElement = S.Get(this.textBoxHtmlElementID);
}
TextBoxHint.prototype = new Hint;

TextBoxHint.prototype.bindEvents = function()
{
    S.Event.add(this.textBoxHtmlElement, "mouseover", this.eventFunctions.showHint);
	S.Event.add(this.textBoxHtmlElement, "mouseout", this.eventFunctions.hideHint);
	S.Event.add(this.textBoxHtmlElement, "focus", this.eventFunctions.setHint);
	S.Event.add(this.textBoxHtmlElement, "blur", this.eventFunctions.unSetHint);
	S.Event.add(this.textBoxHtmlElement, "mousedown", this.eventFunctions.mouseDown);
}

function RadioButtonHint(hintDivID, radioButtonHtmlElementID, containerControlHtmlElementID)
{
	this.base = Hint;
	this.base(hintDivID);

	this.radioButtonHtmlElementID = radioButtonHtmlElementID;
	this.radioButtonHtmlElement = S.Get(this.radioButtonHtmlElementID);

	this.containerControlHtmlElementID = containerControlHtmlElementID;
	this.containerControlHtmlElement = S.Get(this.containerControlHtmlElementID);
}
RadioButtonHint.prototype = new Hint;

RadioButtonHint.prototype.bindEvents = function()
{
	S.Event.add(this.containerControlHtmlElement, "mouseover", this.eventFunctions.showHint);
	S.Event.add(this.containerControlHtmlElement, "mouseout", this.eventFunctions.hideHint);
	S.Event.add(this.containerControlHtmlElement, "blur", this.eventFunctions.unSetHint);
	S.Event.add(this.containerControlHtmlElement, "mousedown", this.eventFunctions.mouseDown);

	S.Event.add(this.containerControlHtmlElement, "click", this.eventFunctions.setHint);
	S.Event.add(this.containerControlHtmlElement, "focus", this.eventFunctions.setHint);
}

function DropDownListHint(hintDivID, dropDownListHtmlElementID)
{
	this.base = Hint;
	this.base(hintDivID);

	this.dropDownListHtmlElementID = dropDownListHtmlElementID;
	this.dropDownListHtmlElement = S.Get(this.dropDownListHtmlElementID);
}
DropDownListHint.prototype = new Hint;

DropDownListHint.prototype.bindEvents = function()
{
	S.Event.add(this.dropDownListHtmlElement, "mouseover", this.eventFunctions.showHint);
	S.Event.add(this.dropDownListHtmlElement, "mouseout", this.eventFunctions.hideHint);
	S.Event.add(this.dropDownListHtmlElement, "focus", this.eventFunctions.setHint);
	S.Event.add(this.dropDownListHtmlElement, "blur", this.eventFunctions.unSetHint);
	S.Event.add(this.dropDownListHtmlElement, "mousedown", this.eventFunctions.mouseDown);
}

function CheckBoxHint(hintDivID, checkBoxHtmlElementID, containerControlHtmlElementID)
{
	this.base = Hint;
	this.base(hintDivID);

	this.checkBoxHtmlElementID = checkBoxHtmlElementID;
	this.checkBoxHtmlElement = S.Get(this.checkBoxHtmlElementID);

	this.containerControlHtmlElementID = containerControlHtmlElementID;
	this.containerControlHtmlElement = S.Get(this.containerControlHtmlElementID);
}
CheckBoxHint.prototype = new Hint;

CheckBoxHint.prototype.bindEvents = function()
{
	S.Event.add(this.containerControlHtmlElement, "mouseover", this.eventFunctions.showHint);
	S.Event.add(this.containerControlHtmlElement, "mouseout", this.eventFunctions.hideHint);
	S.Event.add(this.containerControlHtmlElement, "mousedown", this.eventFunctions.mouseDown);

	S.Event.add(this.containerControlHtmlElement, "click", this.eventFunctions.setHint);
	S.Event.add(this.containerControlHtmlElement, "focus", this.eventFunctions.setHint);
	S.Event.add(this.containerControlHtmlElement, "blur", this.eventFunctions.unSetHint);
	
	// If the check box have an label, clicking this, will cause the check box to fire the
    // blur event, causing the hint to flash because its being hidden and the shown again.
    // Here we are listening to this event so we can prevent it.
    var label = getLabel(this.containerControlHtmlElement, this.checkBoxHtmlElement.id);
    	    
    if (label != null)
    {
        S.Event.add(label, "mousedown", this.eventFunctions.labelMouseDown);
    }
}

function RadioButtonListHint(hintDivID, radioButtonListHtmlElementID, containerControlHtmlElementID)
{
	this.base = Hint;
	this.base(hintDivID);

	this.radioButtonListHtmlElementID = radioButtonListHtmlElementID;
	this.radioButtonListHtmlElement = S.Get(this.radioButtonListHtmlElementID);

	this.containerControlHtmlElementID = containerControlHtmlElementID;
	this.containerControlHtmlElement = S.Get(this.containerControlHtmlElementID);
}
RadioButtonListHint.prototype = new Hint;

RadioButtonListHint.prototype.bindEvents = function()
{
    var radioButtons = this.radioButtonListHtmlElement.getElementsByTagName("INPUT");
    
    for (var i = 0; i < radioButtons.length; i++)
    {
        var radioButton = radioButtons[i];
        S.Event.add(radioButton, "click", this.eventFunctions.setHint);
	    S.Event.add(radioButton, "focus", this.eventFunctions.setHint);
    }
    
	S.Event.add(this.containerControlHtmlElement, "mouseover", this.eventFunctions.showHint);
	S.Event.add(this.containerControlHtmlElement, "mouseout", this.eventFunctions.hideHint);
	S.Event.add(this.containerControlHtmlElement, "mousedown", this.eventFunctions.mouseDown);
}

function GenericHint(hintDivID, containerControlHtmlElementID)
{
	this.base = Hint;
	this.base(hintDivID);

	this.containerControlHtmlElementID = containerControlHtmlElementID;
	this.containerControlHtmlElement = S.Get(this.containerControlHtmlElementID);
}
GenericHint.prototype = new Hint;

GenericHint.prototype.bindEvents = function()
{
    var inputs = this.containerControlHtmlElement.getElementsByTagName("INPUT");
    
    for (var i = 0; i < inputs.length; i++)
    {
        var input = inputs[i];
        S.Event.add(input, "click", this.eventFunctions.setHint);
	    S.Event.add(input, "focus", this.eventFunctions.setHint);
	    S.Event.add(input, "blur", this.eventFunctions.unSetHint);
	    
	    // If the check box have an label, clicking this, will cause the check box to fire the
	    // blur event, causing the hint to flash because its being hidden and the shown again.
	    // Here we are listening to this event so we can prevent it.
	    var label = getLabel(this.containerControlHtmlElement, input.id);
	    	    
	    if (label != null)
	    {
	        S.Event.add(label, "mousedown", this.eventFunctions.labelMouseDown);
	    }
    }
    
    var selects = this.containerControlHtmlElement.getElementsByTagName("SELECT");
    
    for (var i = 0; i < selects.length; i++)
    {
        var select = selects[i];
        S.Event.add(select, "click", this.eventFunctions.setHint);
	    S.Event.add(select, "focus", this.eventFunctions.setHint);
	    S.Event.add(select, "blur", this.eventFunctions.unSetHint);
    }
    
	S.Event.add(this.containerControlHtmlElement, "mouseover", this.eventFunctions.showHint);
	S.Event.add(this.containerControlHtmlElement, "mouseout", this.eventFunctions.hideHint);
	S.Event.add(this.containerControlHtmlElement, "mousedown", this.eventFunctions.mouseDown);
}

function TextEditorHint(hintDivID, containerControlHtmlElementID, textEditorID)
{
    this.base = GenericHint;
	this.base(hintDivID, containerControlHtmlElementID);
	
	this.textEditorID = textEditorID;
}
TextEditorHint.prototype = new GenericHint;

TextEditorHint.prototype.bindEvents = function()
{
    S.Event.add(this.containerControlHtmlElement, "mouseover", this.eventFunctions.showHint);
	S.Event.add(this.containerControlHtmlElement, "mouseout", this.eventFunctions.hideHint);
}

function getLabel(htmlContainer, ID)
{
    var labels = htmlContainer.getElementsByTagName("LABEL");
    
    for (var i = 0; i < labels.length; i++)
    {
        var label = labels[i];
                
        if (label.htmlFor == ID)
            return label;
    }
    
    return null;
}
