function RadTextBox(id, config, styles)
{
    this.DisposeOldInstance(id);
    this.Constructor(id);
    this.Initialize(config, styles);
}

RadTextBox.Extend = function (descendant)
{
    for (var i in this.prototype)
    {
        if (descendant[i]) continue;
        descendant[i] = this.prototype[i];
    }
}

//error event reasons
RadInputErrorReason = {
	ParseError: 0,
	OutOfRange: 1
}


RadTextBox.prototype = 
{
    DisposeOldInstance : function(id)
    {
        try
        {
            var oldTextBox = window[id];
            if (oldTextBox != null)
            {
                oldTextBox.Dispose();
	            window[id] = null;
            }
        }
        catch(e)
        {}
    },

    Constructor : function (id)
    {
        this.ID = id;
        
        this.WrapperElementID = id + "_wrapper";
        this.TextBoxElement = document.getElementById(id + "_text");
        this.HiddenElement = document.getElementById(id);
        
        this.SelectionEnd = 0;
        this.SelectionStart = 0;
        
        
        // state flags
        this.Focused = false;
        this.Enabled = true;
        this.Hovered = false;
        this.Invalid = false;
        this.IsEmptyMessage = false;
        
        this.valueListener = new Telerik.TextInputEvents.ValueListener(this);
        
   	    RadControlsNamespace.EventMixin.Initialize(this);
	    RadControlsNamespace.DomEventMixin.Initialize(this);
    },

	Dispose : function ()
    {
		this.DisposeDomEventHandlers();
		this.DisposeEventHandlers();
		
		if (this.valueListener)
			this.valueListener.Dispose();

        if (this.valueChangedAction != null)
	        window.clearTimeout(this.valueChangedAction);
		
        var property;
        for (property in this)
        {
            property = null;
        }
    },

    CallBase : function (methodName, args)
    {
        //Opera and Safari do not support "arguments.callee.caller"//
        return RadTextBox.prototype[methodName].apply(this, args);
    },

    Initialize : function (config, styles)
    {
        this.Styles = styles;
        
        this.LoadCongfiguration(config);
        this.LoadClientEvents(config);
        
        this.AttachEventHandlers();
        
        this.UpdateDisplayValue();
        this.UpdateCssClass();
        
        this.InitializeButtons();
        
        var input = this;
        this.AttachDomEvent(window, "unload", "Dispose");
        
        this.RaiseEvent('OnLoad', null);
    },

    LoadCongfiguration : function (config)
    {
        for (var i in config)
        {
            if (i != "ClientEvents")
            {
                this[i] = config[i];
            }
        }
    },

    LoadClientEvents : function (config)
    {
        var eventHandler = null;
        for (var eventName in config.ClientEvents)
        {
            var eventHandler = eval(config.ClientEvents[eventName])
            if (typeof(eventHandler) == "function")
                this.AttachEvent(eventName, eventHandler);
        }    
    },

    AttachEventHandlers : function ()
    {
        this.AttachToTextBoxEvent("keypress", "TextBoxKeyPressHandler");
        this.AttachToTextBoxEvent("blur", "TextBoxBlurHandler");
        this.AttachToTextBoxEvent("focus", "TextBoxFocusHandler");
        this.AttachToTextBoxEvent("mouseout", "TextBoxMouseOutHandler");   
        this.AttachToTextBoxEvent("mouseover", "TextBoxMouseOverHandler");
        
        if (window.addEventListener)
		{
		    //Gecko, Opera?
		    this.AttachToTextBoxEvent("DOMMouseScroll", "TextBoxMouseWheelHandler");
		}
		else
		{
			//IE
		    this.AttachToTextBoxEvent("mousewheel", "TextBoxMouseWheelHandler");
		}
    },
    
    TextBoxKeyPressHandler : function (e)
    {
        var isIE = /MSIE/.test(navigator.userAgent);
        var keyCode =  isIE ? e.keyCode : e.which;
        
        if ((keyCode == 13) 
			&& (this.TextBoxElement.tagName.toUpperCase() != "TEXTAREA"))
        {
            this.Blur(); 
            return true;
        }
        
        this.UpdateHiddenValueOnKeyPress();
    },
    
    UpdateHiddenValueOnKeyPress: function()
    {
		var oldValue = this.GetTextBoxValue();
		var newValue = this.GetTextBoxValue();
		this.valueListener.AddChangeEventRequest(newValue, oldValue);
		this.UpdateHiddenValue();
    },

    AttachToTextBoxEvent : function (event, handler)
    {
        this.AttachDomEvent(this.TextBoxElement, event, handler);
    },

	TextBoxBlurHandler : function (e)
    {
        this.Focused = false;   
         
        this.SetValue(this.GetTextBoxValue());
    
        this.RaiseEvent('OnBlur', {"DomEvent" : e});
    },

    TextBoxFocusHandler : function (e)
    {
        this.Focused = true;
        this.UpdateDisplayValue();
        this.UpdateCssClass();
        this.UpdateSelectionOnFocus();
        this.RaiseEvent('OnFocus', {"DomEvent" : e});
    },


    TextBoxMouseOutHandler : function (e)
    {
        this.Hovered = false;
        this.UpdateCssClass();
        this.RaiseEvent('OnMouseOut', {"DomEvent" : e});
    },


    TextBoxMouseOverHandler : function (e)
    {
        this.Hovered = true;
        this.UpdateCssClass(); 
        this.RaiseEvent('OnMouseOver', {"DomEvent" : e});
    },
    
    //Handle Wheel
    TextBoxMouseWheelHandler : function(e)
	{
	    var delta;
	    if (this.Focused)
	    {
            this.MouseWheelActionInProgress = true;
            
            if (e.wheelDelta) 
            { 
                /* IE/Opera. */
                delta = e.wheelDelta/120;
                /** In Opera 9, delta differs in sign as compared to IE.*/
                if (window.opera)
                    delta = -delta;
            } 
            else if (e.detail) 
            {
                    /** Mozilla case. In Mozilla, sign of delta is different than in IE. Also, delta is multiple of 3.*/
                    delta = - e.detail/3;
            }
            
            if (delta > 0)
            {
                this.HandleWheel(false);
            }
            else
            {
                this.HandleWheel(true);
            }
            
            this.MouseWheelActionInProgress = false;
            
            return true;
        }
        return false;
	},
	
	DelayValueChangedEvent: function()
	{
		return this.MouseWheelActionInProgress == true;
	},
	
    HandleWheel : function(isNegativeWheel)
	{
	},



    //*******public methods*******
    Disable : function ()
    {
        this.Enabled = false;
        this.TextBoxElement.disabled = "disabled";
        this.UpdateCssClass();
        this.RaiseEvent('OnDisable', null);
    },

    Enable : function ()
    {
        this.Enabled = true;
        this.TextBoxElement.disabled = "";
        this.UpdateCssClass();
        this.RaiseEvent('OnEnable', null);
    },
    
    Focus : function ()
    {
        this.TextBoxElement.focus();
    },

    Blur : function ()
    {
        this.TextBoxElement.blur();
    },

    SetValue : function (newValue)
    {
        var oldValue = this.GetValue();
        var validValue = this.SetHiddenValue(newValue);
        if (validValue == false)
			return;
			
        if (oldValue != newValue)
        {
            this.valueListener.QueueChangeEventRequest(newValue, oldValue);
        }
			
        this.SetTextBoxValue(this.GetEditValue());
        this.UpdateDisplayValue();
        this.UpdateCssClass();
    },
    
    RaiseValueChangedEvent: function(newValue, oldValue)
    {
		var shouldPostBack = this.RaiseEvent('OnValueChanged', this.ValueChangedEventArgs(newValue, oldValue));
        if (this.AutoPostBack && shouldPostBack)
        {
            this.RaisePostBackEvent();
        }	
    },
    
    Clear : function ()
    {
        this.SetValue("");
    },

    SetTextBoxValue : function (value)
    {
        if (this.TextBoxElement.value != value)
        {
            this.TextBoxElement.value = value;
        }
    },

    GetTextBoxValue : function (value)
    {
        return this.TextBoxElement.value;
    },


    GetWrapperElement : function()
    {
        return document.getElementById(this.WrapperElementID);
    },

    UpdateDisplayValue : function()
    {
        if (this.Focused)
        {
            this.SetTextBoxValue(this.GetEditValue());
        }
        else
        {
            if (this.IsEmpty() && this.EmptyMessage)
            {
                this.IsEmptyMessage = true;
                this.SetTextBoxValue(this.EmptyMessage);
            }
            else
            {
                this.IsEmptyMessage = false;
                this.SetTextBoxValue(this.GetDisplayValue());
            }
        }
    },

    UpdateSelectionOnFocus : function()
    {
        switch (this.SelectionOnFocus)
        {
            case 0: //None
                break;
            case 1: //CaretToBeginning
                this.SetCaretPosition(0);
                break;
            case 2: //CaretToEnd
                if (this.TextBoxElement.value.length > 0)
                {
                    this.SetCaretPosition(this.TextBoxElement.value.length);
                }
                break;
            case 3: //SelectAll
                this.SelectAllText();
                break;            
            default : 
				this.SetCaretPosition(0); //CaretToBeginning
				break;
        }
    },

    RaiseErrorEvent : function(args)
    {
		if (this.InEventRaise)
			return;
			
		this.InEventRaise = true;
		
		var cancelErrorStyle = this.RaiseEvent('OnError', args);
		if (cancelErrorStyle != false)
		{
			this.Invalid = true;
			this.UpdateCssClass();
	    	
			var instance = this;
			var restore = function()
			{
				instance.Invalid = false
				instance.UpdateCssClass();
			}
			setTimeout(restore, 100);	        
        }
        
        this.InEventRaise = false;
    },

    RaisePostBackEvent : function()
    {
        eval(this.PostBackEventReferenceScript);
    },

    UpdateCssClass  : function ()
    {        
        if (this.Enabled && (!this.IsEmptyMessage) && (!this.IsNegative()))
        {
             this.TextBoxElement.style.cssText = this.Styles["EnabledStyle"][0];
             this.TextBoxElement.className = this.Styles["EnabledStyle"][1];
        }     
        
        if (this.Enabled && (!this.IsEmptyMessage) && this.IsNegative())
        {
             this.TextBoxElement.style.cssText = this.Styles["NegativeStyle"][0];
             this.TextBoxElement.className = this.Styles["NegativeStyle"][1];
        }  
        
        if (this.Enabled && this.IsEmptyMessage)
        {
             this.TextBoxElement.style.cssText = this.Styles["EmptyMessageStyle"][0];
             this.TextBoxElement.className = this.Styles["EmptyMessageStyle"][1];
        }   
        
        if (this.Hovered)
        {
            this.TextBoxElement.style.cssText = this.Styles["HoveredStyle"][0];
            this.TextBoxElement.className = this.Styles["HoveredStyle"][1];
        }
        
        if (this.Focused)
        {
            this.TextBoxElement.style.cssText = this.Styles["FocusedStyle"][0];
            this.TextBoxElement.className = this.Styles["FocusedStyle"][1];   
        }
        
        if (this.Invalid)
        {
            this.TextBoxElement.style.cssText = this.Styles["InvalidStyle"][0];
            this.TextBoxElement.className = this.Styles["InvalidStyle"][1];
        }   
        
        if (!this.Enabled)
        {
            this.TextBoxElement.style.cssText = this.Styles["DisabledStyle"][0];
            this.TextBoxElement.className = this.Styles["DisabledStyle"][1];        
        }
    },

    /* IE needs these */

    CalculateSelection : function ()
    {
        if (window.opera || !document.selection)
        {
            this.SelectionEnd = this.TextBoxElement.selectionEnd;
            this.SelectionStart = this.TextBoxElement.selectionStart;
            return;
        }
        
        var s1 = document.selection.createRange();
        if (s1.parentElement() != this.TextBoxElement) return;
        var s = s1.duplicate();

        s.move('character', -this.TextBoxElement.value.length);
        
        s.setEndPoint('EndToStart', s1);
        
        var sel1 = s.text.length;
        var sel2 = s.text.length +  s1.text.length;
        this.SelectionEnd = Math.max(sel1, sel2);
        this.SelectionStart = Math.min(sel1, sel2);
    },

    ApplySelection : function ()
    {
            if (window.opera || !document.selection)
            {
                this.TextBoxElement.selectionStart = this.SelectionStart;
                this.TextBoxElement.selectionEnd = this.SelectionEnd;
                return;
            }

            this.TextBoxElement.select();
            sel = document.selection.createRange();
            sel.collapse();
            sel.moveStart('character', this.SelectionStart);
            sel.collapse();
            sel.moveEnd('character', this.SelectionEnd - this.SelectionStart);
            sel.select();        
    },

    SelectText : function (start, end)
    {
        this.SelectionStart = start;
        this.SelectionEnd = end;
        this.ApplySelection();
    },

    SelectAllText : function ()
    {
        if (this.TextBoxElement.value.length > 0)
        {
             this.SelectText(0, this.TextBoxElement.value.length);
             return true;
        }
        return false;
    },

    SetCaretPosition : function (position)
    {   
        this.SelectionStart = position;
        this.SelectionEnd = position;
        this.ApplySelection();
    },

    UpdateHiddenValue : function()
    {
        return this.SetHiddenValue(this.TextBoxElement.value);
    },

    // InitializeButtons
    InitializeButtons : function()
    {
        this.Button = null;
		var domElement = document.getElementById(this.WrapperElementID);
        var spans = domElement.getElementsByTagName("span");
        
        for (i = 0; i < spans.length; i++)
        {
			if (spans[i].className.indexOf("radInpButtonCss") != (-1))
            {
                this.Button = spans[i];
                this.AttachDomEvent(this.Button, "click", "ButtonClickHandler");
            }            
        }   
    },

    ButtonClickHandler : function (e)
    {
        var args = { "ButtonName":"Button" };
        this.RaiseEvent('OnButtonClick', args);
    },


    // virtual methods

    SetHiddenValue : function(value)
    {
        if (this.HiddenElement.value != value)
        {
            this.HiddenElement.value = value;
        }
        return true;
    },
    
    ValueChangedEventArgs : function(newValue, oldValue)
    {
		if (oldValue == null)
			oldValue = this.HiddenElement.value;
			
		return { "NewValue": newValue, "OldValue": oldValue };
    },

    GetValue : function ()
    {
        return this.HiddenElement.value;
    },

    GetDisplayValue : function ()
    {
        return this.HiddenElement.value;
    },

    GetEditValue : function ()
    {
        return this.HiddenElement.value;
    },

    IsEmpty : function ()
    {
        return this.HiddenElement.value == "";
    }, 

    IsNegative : function ()
	{
		return false;
	}
};    
    

if (typeof(window.RadControlsNamespace) == "undefined")
{
    window.RadControlsNamespace = new Object();
};

RadControlsNamespace.AppendStyleSheet = function(callback, clientID, pathToCssFile)
{
    if (!pathToCssFile) 
    { 
	    return; 
    }

    if (!callback)
    {
	    document.write("<" + "link" + " rel='stylesheet' type='text/css' href='" + pathToCssFile + "' />");
    }
    else
    {
	    var linkObject = document.createElement("link");
	    linkObject.rel = "stylesheet";
	    linkObject.type = "text/css";
	    linkObject.href = pathToCssFile;
	    var StyleSheetHolder = document.getElementById(clientID + "StyleSheetHolder");
	    if(StyleSheetHolder != null)
	    {
		    document.getElementById(clientID + "StyleSheetHolder").appendChild(linkObject);
	    }
    }
};



//test
if (typeof(console) == "undefined")
{
   console = {
        log : function (msg)
        {
            if (!this.logElement)
            {
                this.logElement = document.createElement("div");
                this.logElement.style.cssText = "border:2px inset buttonface;font:10px tahoma;padding:20px;height:200px;overflow:scroll;position:absolute;bottom:0;";
                document.body.insertBefore(this.logElement, document.body.firstChild);
            }
            
           
            var msgNode = document.createTextNode((new Date().toString()) + ": " + msg);
            this.logElement.appendChild(msgNode);
            this.logElement.appendChild(document.createElement("hr"));
        }            
    }
}

