if (typeof(window.RadInputNamespace) == "undefined")
{
	window.RadInputNamespace = new Object();
};

function RadMaskedTextBox() 
{
    if(typeof(arguments.length) == "undefined" || arguments.length == 0)
        return;
    
	var clientID = arguments[0];

	RadTextBox.Extend(this);
	RadControlsNamespace.EventMixin.Initialize(this);
	RadControlsNamespace.DomEventMixin.Initialize(this);
	
    this.CallBase("DisposeOldInstance", arguments);
	//TODO: call base constructor and start relying on the base class's selection logic
	
	if (arguments.length)
	{
		this.StartUp(arguments[0], arguments[1]);
	}	
	
	this.form = this.field.form;
};

RadMaskedTextBox.prototype.ShouldUseAttachEvent = function(target)
{
	return (target.attachEvent && !window.opera && !window.netscape);
}

RadMaskedTextBox.prototype.StartUp = function (fieldID, skin)
{
	// public properties
	this.PromptChar = '_';
	this.DisplayPromptChar = '_';
	this.ReadOnly = false;
	this.DisplayFormatPosition = 0;
	this.HideOnBlur = false;
	this.ResetCaretOnFocus = false;
	this.EmptyMessage = '';
	this.AutoPostBack = false;
	this.AllowEmptyEnumerations = false;
	this.ShowHint = false;
	this.RoundNumericRanges = true;
	this.FocusOnStartup = false;
	this.parts = [];
	this.partIndex = [];
	this.displayPartIndex = [];
	this.value = '';
	this.blurred = true;
		
	this.hiddenField = document.getElementById(fieldID + "_Value");
	this.validationField = document.getElementById(fieldID);
	this.field = document.getElementById(fieldID + "_TextBox");	
	this.Enabled = !this.field.disabled;
	
	this.field.oldValue = this.field.value;
	this.ID = fieldID;
	this.lastState = null;
	this.length = 0;
	this.displayLength = 0;
	
	this.internalValueUpdate = false;	
	this.projectedValue = "";
	
	this.Hint = new RadInputHint(this, skin);
	
	this.isTextarea = this.field.tagName.toLowerCase() == 'textarea';
	
	this.safari = navigator.userAgent.indexOf('Safari') > -1;
	this.mozilla = navigator.userAgent.indexOf('Gecko') > -1;
		
	this.AttachEventHandlers();	
	
	this.AttachDomEvent(window, "unload", "Dispose");
	
	//TODO: delegate class changes to RadTextBox
	// css classes
	if (skin)
	{
		this.field.overClass =		"radHoverCss_" + skin;
		this.field.focusClass =		"radFocusedCss_" + skin;
		this.field.defaultClass =	this.field.className ? this.field.className : "radEnabledCss_" + skin;
		this.field.errorClass =		"radInvalidCss_" + skin;
		this.field.className = this.field.defaultClass;
	}
	else
	{
		var defClass =				this.field.className;
		this.field.overClass =		defClass;
		this.field.focusClass =		defClass;
		this.field.defaultClass =	defClass;
		this.field.errorClass =		defClass;
	}
	
	this.field.focused = false;
	
	this.FixAbsolutePositioning();
}

RadMaskedTextBox.prototype.Dispose = function()
{
//TODO: get the try/catch block back in place before releasing

//	try
//	{   
		this.CallBase("Dispose", arguments);
		
        if (this.ShouldUseAttachEvent(window))
        {
	        for (var prop in this.handlers)
	        {
	            if (!this.handlers.hasOwnProperty(prop))
                    continue;
                
		        this.field.detachEvent(prop, this.handlers[prop]);
		        this.handlers[prop] = null;
	        }
        	
	        this.disposeEventHandler = null;
			this.handlers = null;
        }

        for (var prop in this.field)
        {
	        if (typeof(this.field[prop]) == 'function')
	        {
		        try
		        {
			        this.field[prop] = null;
		        }
		        catch(e)
		        { }
	        }
        }
        	
        this.hiddenField = null;
        this.validationField = null;
        
        this.field.oldValue = null;   
        this.parts = null;
    
        
        this.Hint = null; 
        
        this.form = null;   
        this.field.parentNode.removeChild(this.field);
        this.field = null;  
//	}
//	catch(e)
//	{}
}

RadMaskedTextBox.prototype.FixAbsolutePositioning = function ()
{
	var f = this.field;
	if (
	f.previousSibling && 
	f.previousSibling.tagName.toLowerCase() == "label" &&
	f.style.position == "absolute")
	{
		f.style.position = "static";
		var parent = f.parentNode;
		parent.style.position = "absolute";
		parent.style.top = f.style.top;
		parent.style.left = f.style.left;
	}
}

RadMaskedTextBox.prototype.Initialize = function ()
{
	this.Visualise();
	if (this.FocusOnStartup)
	{
		this.Focus();
	}
	
	this.RecordInitialState();
}

RadMaskedTextBox.prototype.Enable = function ()
{
	this.field.disabled = "";	
	this.Enabled = true;
}

RadMaskedTextBox.prototype.Disable = function ()
{
	this.field.disabled = "disabled";	
	this.Enabled = false;
}

RadMaskedTextBox.prototype.RecordInitialState = function ()
{
	this.initialFieldValue = this.field.value;
}

RadMaskedTextBox.prototype.Focus = function ()
{
	this.field.focus();
	this.field.selectionStart = this.field.selectionEnd = 0;
}

RadMaskedTextBox.prototype.PartAt = function(index)
{
	return this.partIndex[index];
}



RadMaskedTextBox.prototype.SetDisabledClass = function (className)
{
	this.field.disabledClass =	className;
	if	(this.field.disabled)
	{
		this.field.className = this.field.disabledClass;
	}
};

RadMaskedTextBox.prototype.SetFocusClass = function (className)
{
	this.field.focusClass =	className;
};

RadMaskedTextBox.prototype.SetErrorClass = function (className)
{
	this.field.errorClass =	className;
};

RadMaskedTextBox.prototype.SetOverClass = function (className)
{
	this.field.overClass =	className;
};


RadMaskedTextBox.prototype.CreatePartCollection = function (parts, promptChar)
{
	var chunk;
	var collection = [];
	var length = 0;
	for (var j = 0; j < parts.length; j ++)
	{
		chunk = parts[j];
		chunk.PromptChar = promptChar;
		chunk.SetController(this);
		chunk.index = this.parts.length;
		collection[collection.length] = chunk;
		
		
		// link the parts
		if (collection.length > 1)
		{
			collection[collection.length - 2].NextChunk = chunk;
		}
		
		chunk.NextChunk = null;
		
		var chunkLength = chunk.GetLength();

		
		chunk.offset = length;
		length += chunkLength;
	}
	
	return collection;
}

RadMaskedTextBox.prototype.SetMask = function ()
{
	this.parts = this.CreatePartCollection(arguments, this.PromptChar);
	
	for (var i = 0; i < this.parts.length; i ++)
	{
		var chunkLength = this.parts[i].GetLength();
		for (var j = this.length; j < this.length + chunkLength; j ++)
		{
			this.partIndex[j] = this.parts[i];
		}			
		
		this.length += chunkLength;
	}
};

RadMaskedTextBox.prototype.SetDisplayMask = function ()
{
	this.displayParts = this.CreatePartCollection(arguments, this.DisplayPromptChar);
	
	for (var i = 0; i < this.displayParts.length; i ++)
	{
		var part = this.displayParts[i];
		var chunkLength = part.GetLength();
		if (part.ch) // skip literal
		{
			continue;
		}
		for (var j = this.displayLength; j < this.displayLength + chunkLength; j ++)
		{
			this.displayPartIndex[j] = this.displayParts[i];
		}			
		
		this.displayLength += chunkLength;
	}	
}

RadMaskedTextBox.prototype.SetValue = function (value)
{
	this.internalValueUpdate = true;
	this.UpdatePartsInRange(value, 0, this.length);
	this.internalValueUpdate = false;
	this.Visualise();
};

RadMaskedTextBox.prototype.SafariSelectionFix = function (e)
{
	var selectionInfo = this.StrCompare(this.lastState.fieldValue, e.fieldValue)
	
	e.selectionStart = selectionInfo[0];
	e.selectionEnd = selectionInfo[0];
	this.lastState.selectionStart = selectionInfo[1];
	this.lastState.selectionEnd = selectionInfo[2];
}

RadMaskedTextBox.prototype.HandleValueChange = function (e)
{
	if (this.ReadOnly)
	{
		this.Visualise();
		return false;
	}

	if (this.lastState == null) return;
	var i, j;	
	
	if (this.safari)
	{
		this.SafariSelectionFix(e);
	}

	// handle deleted chars
	if (this.lastState.fieldValue.length > e.fieldValue.length)
	{
		// end of the mask
		if (e.selectionStart == this.field.value.length)
		{
			this.partIndex[this.partIndex.length - 1].SetValue("", this.partIndex.length - 1);
		}	
					
		// backspace
		if (this.lastState.selectionEnd > e.selectionStart)
		{
			i = this.lastState.selectionEnd;
			while (i -- > e.selectionStart)
			{
				this.partIndex[i].SetValue("", i);
				// e.selectionEnd --;
			}
		}
		
		// delete
		else
		{

			i = this.lastState.selectionEnd + 1;
			while (i -- > e.selectionStart)
			{
				this.partIndex[i].SetValue("", i);
				e.selectionEnd ++;
			}
		}
		/**/
	}
	
	var updatedPartStart = this.lastState.selectionStart;
	var updatedPartEnd = Math.min(e.selectionStart, this.length);
	
	var updatedPart = e.fieldValue.substr(updatedPartStart, updatedPartEnd - updatedPartStart);
	var selectionOffset = this.UpdatePartsInRange(updatedPart, updatedPartStart, updatedPartEnd);
	e.selectionEnd += selectionOffset;
	this.FixSelection(e);	
};


RadMaskedTextBox.prototype.SetPartValues = function (partIndex, maxLength, value, from, to)
{
	var currentChar;
	var i = 0;
	var j = from;
	var consumedTextLength = 0;
	value = value.toString();
	while (i < to - from && j < maxLength)
	{
		currentChar = value.charAt(i);
		if (currentChar == this.PromptChar)
		{
			currentChar = "";
		}
		
		if (partIndex[j].SetValue(currentChar, j))
		{
			i ++;
		}
		else
		{
			consumedTextLength ++;
		}

		j ++;
	}	
	
	return consumedTextLength;
}

RadMaskedTextBox.prototype.UpdateDisplayPartsInRange = function (value, from, to)
{
	this.SetPartValues(this.displayPartIndex, this.displayLength, value, from, to);
}

RadMaskedTextBox.prototype.UpdatePartsInRange = function (value, from, to)
{
	var selectionOffset = this.SetPartValues(this.partIndex, this.length, value, from, to);
	this.Visualise();
	return selectionOffset;
}

RadMaskedTextBox.prototype.SetCursorPosition = function (position)
{
	if (!this.field.focused) return;
	this.CalculateSelection();
	if (document.all && !window.opera)
	{
		this.field.select();
		sel = document.selection.createRange();
		var rnscount = this.field.value.substr(0, position).split("\r\n").length - 1;
		sel.move('character', position - rnscount);
		sel.select();
	}
	else
	{
		this.field.selectionStart = position;
		this.field.selectionEnd = position;
	}
}

RadMaskedTextBox.prototype.FixSelection = function (eventData)
{
	this.SetCursorPosition(eventData.selectionEnd);
};

RadMaskedTextBox.prototype.GetValue = function()
{
	var result = [];
	for (var i = 0; i < this.parts.length; i++)
	{		
		result[i] = this.parts[i].GetValue();
	}
	return result.join('');
}

RadMaskedTextBox.prototype.GetValueWithLiterals = function()
{
	var result = [];
	for (var i = 0; i < this.parts.length; i++)
	{		
		result[i] = this.parts[i].ch || this.parts[i].GetValue();
	}
	return result.join('');
}

RadMaskedTextBox.prototype.GetVisibleValues = function (parts)
{
	var result = [];
	for (var i = 0; i < parts.length; i++)
	{		
		result[i] = parts[i].GetVisValue();
	}
	return result.join('');
}

RadMaskedTextBox.prototype.GetValueForField = function()
{
	return this.GetVisibleValues(this.parts);
}

RadMaskedTextBox.prototype.GetPrompt = function()
{
	var toPromptRep = new RegExp('.', 'g');
	var result = [];
	for (var i = 0; i < this.parts.length; i++)
	{		
		result[i] = this.parts[i].ch || this.parts[i].GetVisValue().replace(toPromptRep, this.PromptChar);
	}
	return result.join('');	
}


RadMaskedTextBox.prototype.Visualise = function ()
{	
	var fieldValue = this.GetValueForField();
	var value = this.GetValue();

	this.internalValueUpdate = true;
	
	var oldValue = this.projectedValue;
	
	
	this.Render(fieldValue);

	this.value = value;
	this.UpdateHiddenFieldValue();
	this.UpdateValidationFieldValue();
	this.internalValueUpdate = false;	
	
	this.projectedValue = this.field.value;

	
	if (oldValue != this.field.value)
	{	
		this.OnValueChange(null, oldValue, this.field.value);
	}
};

RadMaskedTextBox.prototype.Render = function (inputValue)
{
	if (this.blurred)
	{
		if (this.HideOnBlur && this.isEmpty())
		{
			this.field.value = this.GetBlurredValue();
		}
		else if (this.displayParts && this.displayParts.length)
		{
			this.field.value = this.GetDisplayValue();
		}
		else
		{
			this.field.value = inputValue;
		}
	}
	else
	{
		this.field.value = inputValue;		
	}
} 

RadMaskedTextBox.prototype.UpdateHiddenFieldValue = function ()
{
	this.hiddenField.value = this.GetValueForField();
}

RadMaskedTextBox.prototype.UpdateValidationFieldValue = function ()
{
	if (this.isEmpty())
	{
		this.validationField.value = "";
	}
	else
	{
		this.validationField.value = this.GetValueWithLiterals();
	}
}

RadMaskedTextBox.prototype.OnReset = function ()
{
	this.SetValue(this.initialFieldValue);
	this.Visualise();
}

RadMaskedTextBox.prototype.ValueHasChanged = function ()
{
	return this.field.value != this.field.oldValue;
}

//TODO:replace with the DomEventMixin
RadMaskedTextBox.prototype.attach = function(name, handler)
{
    if (this.handlers == null)
        this.handlers = {};
        
	if (this.ShouldUseAttachEvent(this.field))
	{
		this.handlers["on" + name] = handler;
		this.field.attachEvent("on" + name, handler);
	}
	else if (this.field.addEventListener)
	{
		this.field.addEventListener(name, handler, false);
	}
}	

// ie specific, in order to fix the first skip of onpropertychange	
RadMaskedTextBox.prototype.FakeOnPropertyChange = function()
{
	if (document.createEventObject)
	{
		if (event)
		{
			var ev = document.createEventObject(event);
		}
		else
		{
			var ev = document.createEventObject();
		}
		ev.propertyName = "value";
		this.field.fireEvent("onpropertychange", ev);
	}
}

RadMaskedTextBox.prototype.AttachEventHandlers = function ()
{
	var handler = this;

	var field = this.field;
	
	this.AttachDomEvent(field.form, "reset", "OnReset");
	//TODO: change field/this.field to this.TextBoxElement and convert to AttachTextBoxEvent calls
	this.AttachDomEvent(field, "keydown", "OnKeyDown");
	this.AttachDomEvent(field, "keypress", "OnKeyPress");
	
	var onMouseDown = function (e)
	{
		handler.FakeOnPropertyChange()
		handler.ActivityHandler(e);
	};
	
	var onMouseOut = function ()
	{
		if (!field.focused)
		{
			field.className = field.defaultClass;
		}
	}
	
	var onMouseOver = function ()
	{
		handler.FakeOnPropertyChange()
		if (!field.focused)
		{
			field.className = field.overClass;
		}
	}
	
	var onFocus = function (e)
	{
		field.focused = true;
		field.className = field.focusClass;
		handler.focusValue();
		handler.FakeOnPropertyChange()
		handler.ActivityHandler(e);
	};		
	
	var onMouseUp = function (e)
	{
		handler.FakeOnPropertyChange()
		handler.ValueHandler(e);
		handler.ActivityHandler(e);		
		handler.DisplayHint();
	}	
	
	var onPaste = function ()
	{
	
		if (handler.ReadOnly)
		{
			return false;
		}
		
		if (field.selectionStart == field.value.length)
		{
			return false;	
		}
		
		setTimeout (function () {handler.FakeOnPropertyChange()}, 1);
	}
	
	var onKeyUp = function ()
	{
		handler.FakeOnPropertyChange()
		handler.DisplayHint();
	}
	

	
	var onBlur = function ()
	{
		field.focused = false;	
		field.className = field.defaultClass;
		handler.blurValue();
		var innerHandler = handler;
		window.setTimeout(
		function()
		{
		    if (innerHandler.Hint)
		    {
		        innerHandler.Hint.Hide();
		    }
		}, 
		200);
		
		if (handler.AutoPostBack && handler.ValueHasChanged()) 
		{
			eval(handler.AutoPostBackCode);
		}
				
		field.oldValue = field.value;		
	}	

	this.attach("keyup", onKeyUp);
	this.attach("focus", onFocus);
	this.attach("mousedown", onMouseDown);	
	this.attach("mouseover", onMouseOver);
	this.attach("mouseout", onMouseOut);
	this.attach("mouseup", onMouseUp);		
	this.attach("blur", onBlur);			
	
	if (this.ShouldUseAttachEvent(field))
	{
		// ie specific
		this.attach("paste", onPaste);		
		this.attach('propertychange', function ()
		{
			handler.OnPropertyChange();
		});
		this.attach('mousewheel', function ()
		{
			return handler.OnMouseWheel(event);
		});
	}
	else
	{	
		var onInput = function (e)
		{
			handler.ValueHandler(e);
		}		

		this.attach('blur', onBlur, false);
		this.attach('input', onInput, false);
	}
	
	// Opera
	if (window.opera)
	{
		var intervalCheck = function () 
		{
			return handler.ValueHandler({});
		};
		setInterval(intervalCheck, 10);
	}
};

RadMaskedTextBox.prototype.GetBlurredValue = function ()
{
	return this.EmptyMessage;
}


RadMaskedTextBox.prototype.GetDisplayValue = function ()
{
	var value = this.value;
	while (value.length < this.displayLength)
	{
		if (this.DisplayFormatPosition)
		{
			value = this.PromptChar + value;
		}
		else
		{
			value += this.PromptChar;
		}
	}
	this.UpdateDisplayPartsInRange(value, 0, this.displayLength);
	return this.GetVisibleValues(this.displayParts);
}

RadMaskedTextBox.prototype.isEmpty = function ()
{
	return this.value == '';
}

RadMaskedTextBox.prototype.blurValue = function ()
{
	this.blurred = true;
	this.Visualise();
}

RadMaskedTextBox.prototype.focusValue = function ()
{
	this.blurred = false;
	if ((this.HideOnBlur && this.isEmpty()) || this.displayParts)
	{
		this.Visualise(); 
		this.field.select();
	}
	
	if (this.ResetCaretOnFocus)
	{
		this.ResetCursor();
	}
}

RadMaskedTextBox.prototype.ResetCursor = function ()
{
	this.SetCursorPosition(0);
}

RadMaskedTextBox.prototype.OnPropertyChange = function ()
{
	if (this.internalValueUpdate) return;
	if (event.propertyName == "value")
	{
		var e = event;
		var handler = this;
		var valueWrapper = function ()
		{
			handler.ValueHandler(e);
		}
		this.CalculateSelection();
		
		if (this.field.selectionStart > 0 || this.field.selectionEnd > 0)
		{
			valueWrapper();
		}
		else // failed to calculate selection - wait a second.
		{
			setTimeout(valueWrapper, 1);
		}
	}
}

RadMaskedTextBox.prototype.OnMouseWheel = function (e)
{
	if (this.ReadOnly)
	{
		return false;
	}
	this.CalculateSelection();
	var currentChunk = this.partIndex[this.field.selectionStart];
	if (currentChunk == null)
	{
		return true;
	}
	return currentChunk.HandleWheel(e);
}

RadMaskedTextBox.prototype.OnKeyDown = function (e)
{
	this.FakeOnPropertyChange();
	
	if (this.InSelection(e))
	{
		return true;
	}
	
	var currentChunk = this.partIndex[this.field.selectionStart];
	var keyCode = e.which ? e.which : e.keyCode;
	
	if (this.ReadOnly && (keyCode == 46 || keyCode == 8 || keyCode == 38 || keyCode == 40))
	{
		RadControlsNamespace.DomEvent.PreventDefault(e);
		return false;
	}
	
	
	
	if (keyCode == 13) // Enter
	{
		return true;
	}	
	
	if (currentChunk == null && keyCode != 8)
	{
		return true;
	}
	

	if (currentChunk != null)
	{
		if (currentChunk.HandleKey(e))
		{
			RadControlsNamespace.DomEvent.PreventDefault(e);
			return false;
		}
	}

	
	var selectionEnd = this.field.selectionEnd;
	
	var handled = false;
	
	// delete or interval
	if ((keyCode == 46) && selectionEnd < this.field.value.length && !window.opera) 
	{
		currentChunk.SetValue("", this.field.selectionStart);
		selectionEnd ++;
		handled = true;
	}
	
	else if (keyCode == 8 && selectionEnd && !window.opera) // backspace
	{
		this.partIndex[this.field.selectionStart - 1].SetValue("", this.field.selectionStart - 1);
		selectionEnd --;
		handled = true;
	}
	
	if (handled)
	{
		return this.UpdateAfterKeyHandled(e, selectionEnd);		
	}

	this.OnActivity(e);
	return true;
}



RadMaskedTextBox.prototype.OnKeyPress = function (e)
{	
	if (this.ReadOnly)
	{
		RadControlsNamespace.DomEvent.PreventDefault(e);
		RadControlsNamespace.DomEvent.StopPropagation(e);
		return false;
	}

	if (this.InSelection(e))
	{
		return true;
	}	
	
	var currentChunk = this.partIndex[this.field.selectionStart];
	
	if (currentChunk == null)
	{
		return true;
	}
	
	if (this.mozilla || window.opera)
	{
		// keypress sneaks in here, prevent it;
		if (e.which == 8)
		{
			RadControlsNamespace.DomEvent.PreventDefault(e);
			RadControlsNamespace.DomEvent.StopPropagation(e);
			return false;
		}

		if (!e.which)
		{
			this.OnActivity (e);
			
			RadControlsNamespace.DomEvent.StopPropagation(e);
			return true;
		}
	}
	
	var selectionEnd = this.field.selectionEnd;
	var keyCode = e.which ? e.which : e.keyCode;
	
	if (keyCode == 13) // Enter
	{
		return true;
	}	
	
	var ch = String.fromCharCode(keyCode);
	if (currentChunk.CanHandle(ch))
	{
		while (selectionEnd < this.field.value.length)
		{
			if (this.partIndex[selectionEnd].SetValue(ch, selectionEnd))
			{
				selectionEnd ++;
				break;
			}
			selectionEnd ++;
		}
	}
	
	var result = this.UpdateAfterKeyHandled (e, selectionEnd)
	if (!result)
	{
		RadControlsNamespace.DomEvent.PreventDefault(e);
	}
	
	RadControlsNamespace.DomEvent.StopPropagation(e);	
	return result;
}

RadMaskedTextBox.prototype.UpdateAfterKeyHandled = function (e, selectionEnd)
{
	
	this.Visualise();
	var eventData = new MaskedEventWrap(this.field, e);
	eventData.selectionEnd = selectionEnd;
	this.FixSelection(eventData);
	return false;
}

RadMaskedTextBox.prototype.InSelection = function (e)
{
	this.CalculateSelection();
	
	if (this.field.selectionStart != this.field.selectionEnd)
	{
		this.OnActivity(e);
		return true;
	}
	
	if (e.ctrlKey  || e.altKey || this.safari)
	{
		this.OnActivity(e);
		return true;
	}
	
	return false;
}

RadMaskedTextBox.prototype.ValueHandler = function (e)
{
	if (this.internalValueUpdate)
	{
		return true;
	}
	if (!e) e = window.event;
	
	this.CalculateSelection();

	var evWrap = new MaskedEventWrap(e, this.field);
	
	if (evWrap.fieldValue != this.projectedValue)
	{
		this.HandleValueChange(evWrap);
	}
	
	return true;
}

RadMaskedTextBox.prototype.ActivityHandler = function (e)
{
	if (this.internalValueUpdate)
	{
		return true;
	}	
	if (!e) e = window.event;
	this.OnActivity (e);
	
	return true;
}

RadMaskedTextBox.prototype.DisplayHint = function()
{
	if (!this.ShowHint) return;
	
	this.CalculateSelection();
	var currentChunk = this.partIndex[this.field.selectionStart];
	
	this.Hint.Hide();
	
	var selectionRect = null;
	
	if (document.selection)
	{
		var range = document.selection.createRange();
		if (range.getBoundingClientRect)
		{
			selectionRect = range.getBoundingClientRect();
		}
	}
	this.Hint.Show(currentChunk, selectionRect);
}



RadMaskedTextBox.prototype.OnActivity = function (e)
{
	this.CalculateSelection();
	this.lastState = new MaskedEventWrap(e, this.field);
};


RadMaskedTextBox.prototype.CalculateSelection = function ()
{
	if (document.selection && !window.opera)
	{
		var s1;
		try
		{
			s1 = document.selection.createRange();
		}catch(error)
		{
			//Inside frame
			return;	
		}
        if (s1.parentElement() != this.field) return;
        var s = s1.duplicate();
        if (this.isTextarea)
        {
			s.moveToElementText(this.field);
        }
        else
        {
			s.move('character', - this.field.value.length);
        }
        
        s.setEndPoint('EndToStart', s1);
        this.field.selectionStart = s.text.length;
        this.field.selectionEnd = this.field.selectionStart + s1.text.length;
        if (this.isTextarea)
        {
        }
        
	}
};


// safari specific
RadMaskedTextBox.prototype.StrCompare = function (str1, str2)
{
    var i;
    var selEnd, oldSelStart, oldSelEnd;
    i = 0;
    while (str1.charAt(i) == str2.charAt(i) && i < str1.length)
    {
        i ++;
    }
    oldSelStart = i;
    
    // reverse the strings, so that we may find the other endpoint;
    str1 = str1.substr(oldSelStart).split('').reverse().join('');
    str2 = str2.substr(oldSelStart).split('').reverse().join('');
    i = 0;
    while(str1.charAt(i) == str2.charAt(i) && i < str1.length)
    {
        i ++;
    }
    selEnd = oldSelStart + str2.length - i;
    
    oldSelEnd = str1.length - i + oldSelStart;
    return [selEnd, oldSelStart, oldSelEnd];
};

// enums/ranges call these

function RadInputEventArgs()
{
}

RadMaskedTextBox.prototype.FireEvent = function (eventHandler, chunk, oldValue, newValue)
{
    if (typeof(eventHandler) == "function")
    {
        eventHandler(this, {CurrentPart:chunk, OldValue:oldValue, NewValue:newValue});
    }
    else if (typeof(window[eventHandler]) == "function")
	{
		window[eventHandler](this, {CurrentPart:chunk, OldValue:oldValue, NewValue:newValue});
	}
	else if (eventHandler)
	{
		throw new Error("No such function: "+ eventHandler);
	}
}

RadMaskedTextBox.prototype.OnEnumChanged = function (chunk, oldValue, newValue)
{
	this.FireEvent(this.OnClientEnumerationChanged, chunk, oldValue, newValue);
}

RadMaskedTextBox.prototype.OnMoveUp = function (chunk, oldValue, newValue)
{
	this.FireEvent(this.OnClientMoveUp, chunk, oldValue, newValue);
};

RadMaskedTextBox.prototype.OnMoveDown = function (chunk, oldValue, newValue)
{
	this.FireEvent(this.OnClientMoveDown, chunk, oldValue, newValue);
};

RadMaskedTextBox.prototype.OnValueChange = function (chunk, oldValue, newValue)
{
	this.FireEvent(this.OnClientValueChanged, chunk, oldValue, newValue);
};

RadMaskedTextBox.prototype.OnShowHint = function (chunk)
{
	this.FireEvent(this.OnClientShowHint, chunk, this.field.value, this.field.value);
}

RadMaskedTextBox.prototype.OnChunkError = function (chunk, oldValue, newValue)
{
	this.FireEvent(this.OnClientError, chunk, oldValue, newValue);
	
	var currentClass = this.field.focusClass;
	this.field.className = this.field.errorClass;
	var controller = this;
	var restore = function ()
	{
		if (controller.field.className == controller.field.errorClass)
		controller.field.className = currentClass;
	}
	
	setTimeout(restore, 100);
};


function MaskedEventWrap (e, field)
{
	this.event = e;
	this.selectionStart = field.selectionStart;
	this.selectionEnd = field.selectionEnd;
	this.fieldValue = field.value;
};

MaskedEventWrap.prototype.IsUpArrow = function()
{
	return this.event.keyCode == 38;
}

MaskedEventWrap.prototype.IsDownArrow = function()
{
	return this.event.keyCode == 40;
}


// constructor wrappers
function rdmskd()
{
	return new RadDigitMaskPart();
};

function rdmskl(chars)
{
	return new RadLiteralMaskPart(chars);
};

function rdmske (opts)
{
	return new RadEnumerationMaskPart(opts);
};

function rdmskr(lower, upper, leftAlign, zeroFill)
{
	return new RadNumericRangeMaskPart(lower, upper, leftAlign, zeroFill);
};

function rdmsku()
{
	return new RadUpperMaskPart();
};

function rdmsklw()
{
	return new RadLowerMaskPart();
};

function rdmskp()
{
	return new RadPasswordMaskPart();
};

function rdmskf()
{
	return new RadFreeMaskPart();
};

//BEGIN_ATLAS_NOTIFY
if (typeof(Sys) != "undefined")
{
    if (Sys.Application != null && Sys.Application.notifyScriptLoaded != null)
    {
        Sys.Application.notifyScriptLoaded();
    }
}
//END_ATLAS_NOTIFY
