

var __aspxItemAttrsSeparator = "::";
var __aspxItemsSeparator = ";;";
var __aspxLoadRangeItemsCallbackPrefix = "LBCRI";
var __aspxLBIPostfixes = ['I', 'T'];
var __aspxLBIIdSuffix = "LBI";
var __aspxLBSIIdSuffix = __aspxLBIIdSuffix + "-1";
var __aspxLBTSIdSuffix = "_TS";
var __aspxLBBSIdSuffix = "_BS";
var __aspxLTableIdSuffix = "_LBT";
var __aspxLEVISuffix = "_VI";
var __aspxLBDSuffix = "_D";
var __aspxEmptyItemsRange = "0:-1";
var __aspxNbsp = "&nbsp;";

var __aspxCachedHoverItemKind = "cached" + __aspxHoverItemKind;
var __aspxCachedSelectedItemKind = "cached" + __aspxSelectedItemKind;
ASPxClientListEdit = _aspxCreateClass(ASPxClientEdit, {
    constructor: function(name) {
        this.constructor.prototype.constructor.call(this, name);        
        this.SelectedIndexChanged = new ASPxClientEvent();
        
        //set from server
	    this.savedSelectedIndex = -1;
	},
    RaiseValueChangedEvent: function() {
        var processOnServer = ASPxClientEdit.prototype.RaiseValueChangedEvent.call(this);
        processOnServer = this.RaiseSelectedIndexChanged(processOnServer);
        return processOnServer;
    },
    FindInputElement: function() {
        return this.FindStateInputElement();
    },
    FindStateInputElement: function(){
        return document.getElementById(this.name + __aspxLEVISuffix);
    },
    GetItemValue: function(index) {
        throw "Not implemented";
    },
    GetValue: function(){
        return this.GetItemValue(this.GetSelectedIndexInternal());
    },    
    GetSelectedIndexInternal: function(){
        return this.savedSelectedIndex;
    }, 
    SetSelectedIndexInternal: function(index){
        this.savedSelectedIndex = index;
    },
    // API
    RaiseItemDoubleClick: function() {
        var processOnServer = this.autoPostBack;
        if(!this.ItemDoubleClick.IsEmpty()){
            var args = new ASPxClientProcessingModeEventArgs(processOnServer);
            this.ItemDoubleClick.FireEvent(this, args);
            processOnServer = args.processOnServer;
        }
        return processOnServer;
    },
    RaiseSelectedIndexChanged: function(processOnServer) {
        if(!this.SelectedIndexChanged.IsEmpty()){
            var args = new ASPxClientProcessingModeEventArgs(processOnServer);
            this.SelectedIndexChanged.FireEvent(this, args);
            processOnServer = args.processOnServer;
        }
        return processOnServer;
    },
    UpdateHiddenInputs: function(index){
        var element = this.FindStateInputElement();
        if(_aspxIsExistsElement(element)) {
            var value = this.GetItemValue(index);
            if (value == null)
                value = "";
            element.value = value;
        }
    },
    GetSelectedItem: function(){
        var index = this.GetSelectedIndexInternal();
        return this.GetItem(index);
    },
    GetSelectedIndex: function(){
        return this.GetSelectedIndexInternal();
    },
    SetSelectedItem: function(item){
        var index = (item != null) ? item.index : -1;
        this.SelectIndexSilent(index);
    },
    SetSelectedIndex: function(index){
        this.SelectIndexSilent(index);
    }
});
ASPxClientListEditItem = _aspxCreateClass(null, {
	constructor: function(listEditBase, index, text, value, imageUrl){
	    this.listEditBase = listEditBase;
        this.index = index;
        this.imageUrl = imageUrl;
        this.text = text;
        this.value = value;
    }
});

_aspxListBoxScrollCallbackHelperBase = _aspxCreateClass(null, {
    constructor: function(listBoxControl) {
        this.listBoxControl = listBoxControl;
        this.itemsRange = "";
        this.defaultItemsRange = "0:" + (this.listBoxControl.callbackPageSize - 1);
    },
    OnScroll: function(){ },
    Reset: function(){ },
    IsScrolledToTopSpacer: function(){ return false; },
    IsScrolledToBottomSpacer: function(){ return false; },
    GetIsNeedToHideTopSpacer: function(){ return false; },
    GetIsNeedCallback: function(){ return false; },
    GetItemsRangeForLoad: function(){ return this.defaultItemsRange; },
    SetItemsRangeForLoad: function(){}
});
_aspxListBoxScrollCallbackHelper = _aspxCreateClass(_aspxListBoxScrollCallbackHelperBase, {
    constructor: function(listBoxControl) {
        this.constructor.prototype.constructor.call(this, listBoxControl);
        this.isScrolledToTopSpacer = false;
        this.isScrolledToBottomSpacer = false;
    },
    OnScroll: function(){
        this.DetectScrollDirection();
        this.ResetItemsRange();
        if(this.GetIsAnySpacerVisible())
            this.RecalcItemsRangeForLoad();
    },
    DetectScrollDirection: function(){
        var listBoxControl = this.listBoxControl;
        var divElement = listBoxControl.GetScrollDivElement();
        var listTable = listBoxControl.GetListTable();
        var scrollTop = divElement.scrollTop;
        var scrollBottom = divElement.scrollTop + divElement.clientHeight;
        var isTopSpacerVisible = listBoxControl.GetScrollSpacerVisibility(true);
        var isBottomSpacerVisible = listBoxControl.GetScrollSpacerVisibility(false);
        
        var topSpacerHeight = listBoxControl.isTopSpacerVisible ? parseInt(listBoxControl.GetScrollSpacerElement(true).clientHeight) : 0;
        
        this.isScrolledToTopSpacer = (scrollTop < topSpacerHeight) && isTopSpacerVisible;
        this.isScrolledToBottomSpacer = (scrollBottom >= topSpacerHeight + listTable.clientHeight) && isBottomSpacerVisible;
    },
    Reset: function(){
        this.ResetItemsRange();
        this.isScrolledToTopSpacer = false;
        this.isScrolledToBottomSpacer = false;
    },
    ResetItemsRange: function(){
        this.itemsRange = "";
    },
    RecalcItemsRangeForLoad: function(){
        if(this.listBoxControl.isCallbackMode) {
            if(this.isScrolledToTopSpacer || this.isScrolledToBottomSpacer)
                this.SetItemsRangeForLoad(this.isScrolledToTopSpacer);
        }
    },
    IsScrolledToTopSpacer: function(){
        return this.isScrolledToTopSpacer;
    },
    IsScrolledToBottomSpacer: function(){
        return this.isScrolledToBottomSpacer;
    },
    GetIsAnySpacerVisible: function(){
        return this.isScrolledToTopSpacer || this.isScrolledToBottomSpacer;
    },
    GetIsNeedCallback: function(){
        return !this.GetIsItemsRangeEmpty();
    },
    GetIsNeedToHideTopSpacer: function(){
        return this.isScrolledToTopSpacer && this.GetIsItemsRangeEmpty();
    },
    GetItemsRangeForLoad: function(){
        return (!this.GetIsItemsRangeEmpty() ? this.itemsRange : this.defaultItemsRange);
    },
    SetItemsRangeForLoad: function(isForTop){
        var listbox = this.listBoxControl;
        var beginIndex = isForTop ? 
            listbox.serverIndexOfFirstItem - listbox.callbackPageSize : 
            listbox.serverIndexOfFirstItem + listbox.GetItemCount();
        beginIndex = beginIndex < 0 ? 0 : beginIndex;
        
        var endIndex = isForTop ? 
            listbox.serverIndexOfFirstItem - 1 : 
            beginIndex + listbox.callbackPageSize - 1;
    
        this.itemsRange = beginIndex + ":" + endIndex;
        this.isScrolledToTopSpacer = isForTop;
        this.isScrolledToBottomSpacer = !isForTop;
    },
    GetIsItemsRangeEmpty: function(){
        return (this.itemsRange == "" || this.itemsRange == __aspxEmptyItemsRange);
    }
});
ASPxClientListBoxBase = _aspxCreateClass(ASPxClientListEdit, {
    constructor: function(name) {
        this.constructor.prototype.constructor.call(this, name);
        
        this.APILockCount = 0;
        this.isComboBoxList = false;
        this.isSyncEnabled = true;
        this.ownerName = "";
        // Cashe
        this.deletedItems = [];
        this.insertedItems = [];
        this.itemsValue = [];    
        this.ItemDoubleClick = new ASPxClientEvent();
    },
    GetItemCount: function(){
        return 0;
    },
    GetItemValue: function(index){
        if(0 <= index && index < this.GetItemCount())
            return this.PrepareItemValue(this.itemsValue[index]);
        return null;
    },
    PrepareItemValue: function(value) {
        return (typeof(value) == "string" && value == "" && this.convertEmptyStringToNull) ? null : value;
    },
    LoadItemsFromCallback: function(isToTop, itemStrings){
    },
    SetValue: function(value){
        var index = this.GetItemIndexByValue(value);
        this.SelectIndexSilent(index, false);
    },
    GetItemIndexByValue: function(value){
        for(var i = this.GetItemCount() - 1; i >= 0 ; i--){
            if(this.GetItemValue(i) == value)
                break;
        }
        return i;
    },
    SelectIndexSilent: function(index, initialize){
    },
    SelectIndex: function (index){
        if(this.SelectIndexSilent(index, false)){
            this.RaisePersonalStandardValidation();
            this.OnValueChanged();
        }
    },

    // API
    MakeItemVisible: function(index){
    },
    InitOnContainerMadeVisible: function(){
    },
    AddItem: function(text, value, imageUrl){
        var index = this.GetItemCount();
        this.InsertItemInternal(index, text, value, imageUrl);
        return index;
    },
    InsertItem: function(index, text, value, imageUrl){
        this.InsertItemInternal(index, text, value, imageUrl);
    },
    InsertItemInternal: function(index, text, value, imageUrl){
    },
    BeginUpdate: function(){
        this.APILockCount ++;
    },
    EndUpdate: function(){
        this.APILockCount --;
        this.Synchronize();
    },
    ClearItems: function(){
        this.BeginUpdate();
        this.UpdateArraysItemsCleared();
        this.ClearItemsCore();
        this.EndUpdate();
    },
    ClearItemsCore: function(){
    },
    ClearItemsForPerformCallback: function(){
        this.itemsValue = [];
        this.ClearItemsCore();
    },
    RemoveItem: function(index){
    },
    GetItem: function(index){
        return null;
    },
    PerformCallback: function(arg) {
    },
    GetCallbackArguments: function(){
        var args = this.GetCustomCallbackArg();
        args += this.GetLoadItemsRangeCallbackArg();
        return args;
    },
    GetLoadItemsRangeCallbackArg: function(){
        return this.FormatCallbackArg(__aspxLoadRangeItemsCallbackPrefix, this.GetItemsRangeForLoad());
    },
    FormatCallbackArg: function(prefix, arg) { // REFACTOR with ASPxGrigView, replace to Callback.js
        return (_aspxIsExists(arg) ? prefix + "|" + arg.length + ';' + arg + ';' : "");
    },
    GetItemsRangeForLoad: function(){
        return __aspxEmptyItemsRange;
    },
    GetCallbackOwnerControl: function(){
        if(this.ownerName != "" && !_aspxIsExists(this.ownerControl))
            this.ownerControl = aspxGetControlCollection().Get(this.ownerName);
        return this.ownerControl;
    },
    GetCustomCallbackArg: function(){
        return this.GetSyncroHiddenInput("CustomCallback").value;
    },
    SetCustomCallbackArg: function(arg){
        this.GetSyncroHiddenInput("CustomCallback").value = arg;
    },
    FormatAndSetCustomCallbackArg: function(arg){
        var formatArg = this.FormatCallbackArg("LECC", _aspxIsExists(arg) ? arg : "");
        this.SetCustomCallbackArg(formatArg);
    },
    SendCallback: function(){
    },
    
    AddItemClass: function(index, text, value, imageUrl){
        _aspxArrayInsert(this.itemsValue, value, index);
        if(this.isSyncEnabled){
            this.RefreshSynchroArraysIndex(index, true);
            var item = new ASPxClientListEditItem(this, index, text, value, imageUrl);
            _aspxArrayPush(this.insertedItems, item);
            this.Synchronize();
        }
    },
    UpdateSyncArraysItemDeleted: function(item, isValueRemovingRequired){
        if(isValueRemovingRequired)
            _aspxArrayRemoveAt(this.itemsValue, item.index);
        if(this.isSyncEnabled){
            var item = new ASPxClientListEditItem(this, item.index, item.text, item.value, item.imageUrl);
            var index = this.FindItemInArray(this.insertedItems, item);
            if(index == -1){
                this.RefreshSynchroArraysIndex(item.index, false);
                _aspxArrayPush(this.deletedItems, item);
            } else {
                this.RefreshSynchroArraysIndex(item.index, false);
                _aspxArrayRemoveAt(this.insertedItems, index);
            }
            this.Synchronize();
        }
    },
    UpdateArraysItemsCleared: function(){
        if(this.isSyncEnabled){
            for(var i = this.GetItemCount() - 1; i >= 0; i --)
                this.UpdateSyncArraysItemDeleted(this.GetItem(i), false);
        } 
        this.itemsValue = [];
    },
    RefreshSynchroArraysIndex: function(startIndex, isIncrease){
        this.RefreshSynchroArrayIndexIndex(this.deletedItems, startIndex, isIncrease);
        this.RefreshSynchroArrayIndexIndex(this.insertedItems, startIndex, isIncrease);
    },
    RefreshSynchroArrayIndexIndex: function(array, startIndex, isIncrease){
       var delta = isIncrease ? 1 : -1;
       for(var i = 0; i < array.length; i ++){
            if(array[i].index >= startIndex)
                array[i].index += delta;
       }   
    },
    FindItemInArray: function(array, item){
	    for(var i = array.length - 1; i >= 0; i--){
	        var currentItem = array[i];
	        if(currentItem.text == item.text && currentItem.value == item.value &&
	            currentItem.imageUrl == item.imageUrl)
	            break;
	    }
	    return i;
    },

    GetSyncroHiddenInput: function(syncroType){
        return _aspxGetElementById(this.name + syncroType);
    },
    Synchronize: function(){
        if(this.APILockCount == 0){
            if(this.isSyncEnabled){
                this.SynchronizeItems(this.deletedItems, "DeletedItems");
                this.SynchronizeItems(this.insertedItems, "InsertedItems");
            }
            this.CorrectSizeByTimer();
        }
    },
    CorrectSizeByTimer: function(){
    },
    SynchronizeItems: function(items, syncroType){
        // TODO think about lock items changes
        var inputElement = this.GetSyncroHiddenInput(syncroType);
        if(_aspxIsExistsElement(inputElement)){
            var itemsState = "";
            for(var i = 0; i < items.length; i++){
                itemsState += this.GetSynchronizedItemState(items[i]);
                if(i < items.length - 1) itemsState += __aspxItemsSeparator;
            }
            inputElement.value = itemsState;
        }
    },
    GetSynchronizedItemState: function(item){
        // TODO think about value ability to store date format
        if(_aspxIsExists(item)){
            var itemState = item.value;
            itemState += __aspxItemAttrsSeparator + this.GetCorrectString(item.index);
            itemState += __aspxItemAttrsSeparator + this.GetCorrectString(item.text);
            itemState += __aspxItemAttrsSeparator + this.GetCorrectString(item.imageUrl);
	        return itemState;
	    }
	    return "";
    },
    GetCorrectString: function(str){
        return _aspxIsExists(str) ? str : "";
    },
    OnCallback: function(result) {
    }
});

ASPxClientListBox = _aspxCreateClass(ASPxClientListBoxBase, {
    constructor: function(name) {
        this.constructor.prototype.constructor.call(this, name);
        
        this.freeUniqIndex = -1;
        this.isHasFakeRow = false;
        this.listTable = null;
        this.sampleItemTextCell = null;
        this.width = "";
        this.hasSampleItem = false;
        this.hoverClass = "";
        this.hoverCss = "";
        this.selectedClass = "";
        this.selectedCss = "";
        this.disabledClass = "";
        this.disabledCss = "";
        this.scrollHandlerLockCount = 0;
        // Callback
        this.allowMultipleCallbacks = false;
        this.isCallbackMode = false;
        this.callbackPageSize = -1;
        this.isTopSpacerVisible = false;
        this.isBottomSpacerVisible = false;
        this.serverIndexOfFirstItem = 0;
        this.scrollHelper = null;
        this.changeSelectAfterCallback = 0;
        // Cashe
        this.ownerControl = null;
        this.SampleItem = null;
        this.scrollDivElement = null;
        this.scrollPageSize = 4;
        this.itemsValue = [];
    },
    Initialize: function() {   
        this.LockScrollHandler();
        this.freeUniqIndex = this.GetItemCount();
        
        this.SelectIndexSilent(this.GetSelectedIndexInternal(), true);
        this.AdjustControl(false);
        this.scrollHelper = this.isCallbackMode ? new _aspxListBoxScrollCallbackHelper(this) : new _aspxListBoxScrollCallbackHelperBase(this);
        this.UnlockScrollHandler();
        ASPxClientEdit.prototype.Initialize.call(this);
    },
    InlineInitialize: function(){
        this.LockScrollHandler();
        this.InitializeItemsAttributes();
        this.InitSpecialKeyboardHandling();
        this.GenerateStateItems();
        this.UnlockScrollHandler();
        ASPxClientEditBase.prototype.InlineInitialize.call(this);
    },

    CallbackSpaceInit: function(){
        if(this.isCallbackMode){
            this.SetBottomScrollSpacerVisibility(this.isBottomSpacerVisible);
            this.SetTopScrollSpacerVisibility(this.isTopSpacerVisible);
            _aspxAttachEventToElement(this.GetScrollDivElement(), "scroll", aspxLBScroll);
            this.EnsureSelectedItemVisible();
        }
    },
    InitializeItemsAttributes: function() { 
        var listTable = this.GetListTable();
        if(this.isHasFakeRow){
            var isSyncEnabled = this.isSyncEnabled;
            this.isSyncEnabled = false;
            this.ClearItems();
            this.isSyncEnabled = isSyncEnabled;
        }
        
        listTable.ListBoxId = this.name;  
        
        var rows = listTable.rows;
        var count = rows.length;
        
        var rowIdConst = this.name + "_";
        if(this.hasSampleItem)
            this.InitializeItemAttributes(this.GetSampleItem(), rowIdConst + __aspxLBSIIdSuffix);
        rowIdConst += __aspxLBIIdSuffix;
        for(var i = 0; i < count; i ++)
            this.InitializeItemAttributes(rows[i], rowIdConst + i);
    },
    InitializeItemAttributes: function(row, rowId) {
        var cells = row.cells;
        var textCellId = rowId + __aspxLBIPostfixes[1];
        if(cells.length == 2) {
            cells[0].id = rowId + __aspxLBIPostfixes[0];
            cells[1].id = textCellId;
        } else
            cells[0].id = textCellId;
    },
    InitializePageSize: function(){
        var divElement = this.GetScrollDivElement();
        var listTable = this.GetListTable();
        var rows = listTable.rows;
        var count = rows.length;

        if(_aspxIsExists(divElement) && count > 0)
            this.scrollPageSize = Math.round(divElement.clientHeight / rows[0].offsetHeight) - 1;
    },
    GenerateStateItems: function() {
        var count = this.GetItemCount();
        var constName = this.name + "_" + __aspxLBIIdSuffix;
        var name = "";
        var controller = aspxGetStateController();
        var i = this.hasSampleItem ? -1 : 0 ;
        for(; i < count; i ++){
            name = constName + i;
            controller.AddHoverItem(name, this.hoverClass, this.hoverCss, __aspxLBIPostfixes, null, null);
            controller.AddSelectedItem(name, this.selectedClass, this.selectedCss, __aspxLBIPostfixes, null, null);
            controller.AddDisabledItem(name, this.disabledClass, this.disabledCss, __aspxLBIPostfixes, null, null);
        }
    },
    IsVisibleWhenCorrectingSize: function() {
        return this.IsDisplayed();
    },
    AdjustControlCore: function(){
        ASPxClientEdit.prototype.AdjustControlCore.call(this);
        
        this.CorrectSizeInternal();
        this.InitializePageSize();
        this.EnsureSelectedItemVisible();
        this.CallbackSpaceInit();
        if(!this.isComboBoxList && __aspxIE7) // FIX orevent to IE7 invisible scrollbar accounting
            this.CorrectWidth();
    },
    CorrectSizeInternal: function() {
        if(this.isComboBoxList)
            return;
        this.CorrectHeight();
        this.CorrectWidth();
    },
    CorrectSizeInternalByTimer: function() {
        if(this.IsVisible())
            this.CorrectSizeInternal();
    }, 
    
    CorrectHeight: function(){
        var mainElement = this.GetMainElement();
        var divElement = this.GetScrollDivElement();
        if(__aspxIE55) divElement.style.display = "none";
        divElement.style.height = "0px";
        var height = mainElement.offsetHeight;
        if(__aspxIE55) divElement.style.display = "";
        divElement.style.height = height + "px";
        var extrudedeHeight = mainElement.offsetHeight;
        var heightCorrection = extrudedeHeight - height;
        if(heightCorrection > 0){
            var divHeight = divElement.offsetHeight;
            divElement.style.height = (divHeight - heightCorrection) + "px";
            
            extrudedeHeight = mainElement.offsetHeight;
            var paddingsHeightCorrection = extrudedeHeight - height;
            if(paddingsHeightCorrection > 0)
                divElement.style.height = (divHeight - heightCorrection - paddingsHeightCorrection) + "px";
        } 
    },
    CorrectWidth: function(){
        var divElement = this.GetScrollDivElement();
        if(__aspxIE){
            var mainElement = this.GetMainElement();
            var scrollBarWidth = this.GetVerticalScrollBarWidth(); // Prevent IE7 fail WidthCorrection test
            mainElement.style.width = "";
            divElement.style.width = "100%";
            if(!__aspxIE55)
                divElement.style.paddingRight = "0px";
            if(this.width != ""){
                mainElement.style.width = this.width;
                divElement.style.width = "0px";
                var widthCorrectrion = __aspxIE55 ? 0 : scrollBarWidth;
                divElement.style.width = (mainElement.clientWidth - widthCorrectrion) + "px";
            }
            else{
                var widthCorrectrion = __aspxIE55 ? scrollBarWidth : 0;
                if(this.IsListBoxWidthLessThenList())
                    widthCorrectrion -= scrollBarWidth;
                divElement.style.width = (mainElement.clientWidth + widthCorrectrion) + "px";
            }
            if(!__aspxIE55)
                divElement.style.paddingRight = scrollBarWidth + "px";
        } else {
            if(this.width == ""){
                var listTable = this.GetListTable();
                var mainElement = this.GetMainElement();
                if(listTable.offsetWidth != 0 || !__aspxMozilla){ // Mozilla: Prevent width collapse when item collection is empty
                    divElement.style.width = (listTable.offsetWidth + this.GetVerticalScrollBarWidth()) + "px";
                    if(__aspxFirefox) // Prevent right border invisibility
                        mainElement.style.width = divElement.offsetWidth + "px";
                }
            }
        }
    },
    EnsureSelectedItemVisible: function(){
        var index = this.GetSelectedIndexInternal();
        if(index != -1)
            this.MakeItemVisible(index);
    },
    MakeItemVisible: function(index){
        if(!this.IsItemVisible(index))
            this.ScrollItemToTop(index);
    },
    IsItemVisible: function(index){
        var scrollDiv = this.GetScrollDivElement();
        var itemElement = this.GetItemElement(index);
        var topVisible = false;
        var bottomVisible = false;
        if(itemElement != null){
            var itemOffsetTop = itemElement.offsetTop + this.GetTopScrollSpacerHeight();
            topVisible = itemOffsetTop >= scrollDiv.scrollTop; // TODO  >=apply fix to another version
            bottomVisible = itemOffsetTop + itemElement.offsetHeight < scrollDiv.scrollTop + scrollDiv.clientHeight;
        }
        return (topVisible && bottomVisible);
    },
    ScrollItemToTop: function(index){
        this.LockScrollHandler();
        var scrollDiv = this.GetScrollDivElement();
        if(_aspxIsExists(scrollDiv)) // Render may be removed when callback processing
            scrollDiv.scrollTop = this.GetItemTopOffset(index);
        this.UnlockScrollHandler();
    },
    ScrollToItemVisible: function(index){
        if(!this.IsItemVisible(index)){
            var scrollDiv = this.GetScrollDivElement();
            var scrollTop = scrollDiv.scrollTop;
            var scrollDivHeight = scrollDiv.clientHeight;
            var itemOffsetTop = this.GetItemTopOffset(index);
            var itemHeight = this.GetItemHeight(index);
            
            var itemAbove = scrollTop > itemOffsetTop;
            var itemBelow = scrollTop  + scrollDivHeight < itemOffsetTop + itemHeight;
            if(itemAbove)
                scrollDiv.scrollTop = itemOffsetTop;
            else if(itemBelow){
                var scrollPaddings = scrollDiv.scrollHeight - this.GetListTable().offsetHeight - 
                    this.GetTopScrollSpacerHeight() - this.GetBottomScrollSpacerHeight();
                scrollDiv.scrollTop = itemOffsetTop + itemHeight - scrollDivHeight + scrollPaddings;
            }
        }
    },
    GetItemElement: function(index){
        var itemElement = this.GetItemRow(index);
        return __aspxSafari ? itemElement.cells[0] : itemElement;
    },
    GetItemTopOffset: function(index){
        var itemElement = this.GetItemElement(index);
        return (itemElement != null) ? itemElement.offsetTop + this.GetTopScrollSpacerHeight() : 0;
    },
    GetItemHeight: function(index){
        var itemElement = this.GetItemElement(index);
        return (itemElement != null) ? itemElement.offsetHeight : 0;
    },
    IsListBoxWidthLessThenList: function(){
        var divElement = this.GetScrollDivElement();
        var listTable = this.GetListTable();
        var listTabelWidth = listTable.style.width;
        var isLess = false;
        
        listTable.style.width = "";
        isLess = listTable.offsetWidth < divElement.offsetWidth;
        listTable.style.width = listTabelWidth;
        return isLess;
    },
    GetScrollDivElement: function(){
        if(!_aspxIsExistsElement(this.scrollDivElement))
            this.scrollDivElement = document.getElementById(this.name + __aspxLBDSuffix);
        return this.scrollDivElement;
    },
    GetItemCount: function(){
        var lbt = this.GetListTable();
        if(_aspxIsExists(lbt))
            return this.GetListTable().rows.length;
        return 0;
    },
    GetItemCell: function(index, isImageCell){
        var itemRow = this.GetItemRow(index);
        return (itemRow != null ? this.GetItemRowCell(itemRow, isImageCell) : null);
    },
    GetItemImageCell: function(index){ // TODO replace into API (used only by API script)
        return this.GetItemCell(index, true);
    },
    GetItemTextCell: function(index){
        return this.GetItemCell(index, false);
    },
    GetItemRow: function(index){
        var listTable = this.GetListTable();
        if(_aspxIsExists(listTable)){
            if(0 <= index && index < listTable.rows.length)
                return listTable.rows[index];
        }
        return null;
    },
    GetItemRowCell: function(rowElement, isImageCell){
        var cells = __aspxIE ? rowElement.childNodes : rowElement.cells;// Prevent IE cells undefining
        if(isImageCell)
            return cells.length == 2 ? cells[0] : null;
        return cells.length == 1 ? cells[0] : cells[1];
    },
    GetListTable: function(){
        if(!_aspxIsExistsElement(this.listTable))
            this.listTable = _aspxGetElementById(this.name + __aspxLTableIdSuffix);
        return this.listTable;
    },
    GetListTableHeight: function(){
        return this.GetListTable().offsetHeight;
    },
    SetValue: function(value){
        var index = this.GetItemIndexByValue(value);
        this.SelectIndexSilent(index, false);
    },
    GetVerticalScrollBarWidth: function(){
        var divElement = this.GetScrollDivElement();    
        var overflowYReserv = this.GetVerticalOverflow(divElement);
        this.SetVerticalOverflow(divElement, "auto");
        var borderWidthWithScroll = divElement.offsetWidth - divElement.clientWidth;
        if(__aspxIE7) return borderWidthWithScroll; // Prevent IE7 Border invisible
        this.SetVerticalOverflow(divElement, "hidden");
        var borderWidthWithoutScroll = divElement.offsetWidth - divElement.clientWidth;
        this.SetVerticalOverflow(divElement, overflowYReserv);
        return borderWidthWithScroll - borderWidthWithoutScroll;
    },
    GetVerticalOverflow: function(element){
        if(__aspxIE || __aspxSafari3)
            return element.style.overflowY;
        return element.style.overflow;
    },
    SetVerticalOverflow: function(element, value){
        if(__aspxIE || __aspxSafari3)
            element.style.overflowY = value;
        else
            element.style.overflow = value;
    },
            
    OnItemClick: function(index){
        this.SelectIndex(index);
        this.EnsureSelectedItemVisible();
        this.SetFocus();
    },
    OnItemDblClick: function(){
        this.RaiseItemDoubleClick();
    },
    SelectIndexSilent: function(index, initialize){
        var selectedIndex = this.GetSelectedIndexInternal();
        var isValidIndex = (-1 <= index && index < this.GetItemCount());
        if((selectedIndex != index && isValidIndex && !this.readOnly) || initialize){
            if (!initialize)
                this.SetHoverElement(null);
            
            var itemSelection = this.GetItemTextCell(index);
            var itemSelected = this.GetItemTextCell(selectedIndex);
            var controller = aspxGetStateController();
            controller.DeselectElementBySrcElement(itemSelected);
            controller.SelectElementBySrcElement(itemSelection);
            
            this.SetSelectedIndexInternal(index);
            this.UpdateHiddenInputs(index);
            if (!initialize)
                this.SetHoverElement(itemSelection);
            return true;
        }
        return false;
    },
    // LoadingPanel
    ShowLoadingPanel: function() {    
        if(!this.isComboBoxList){
            var loadingParentElement = this.GetScrollDivElement().parentNode;
            this.CreateLoadingDiv(loadingParentElement);
            this.CreateLoadingPanelWithAbsolutePosition(loadingParentElement);
        }
    },
    // CallbackMode
    ParseCallbackResult: function(result){
        var gottenEgdeOfCollection = false;
        var nothingToLoad = result == "";
        var isLoadindToTopByScroll = this.scrollHelper.IsScrolledToTopSpacer();
        if(!nothingToLoad){
            var itemStrings = result.split(__aspxItemsSeparator);
            this.LoadItemsFromCallback(isLoadindToTopByScroll, itemStrings);
            gottenEgdeOfCollection = itemStrings.length != this.callbackPageSize;
        }
        var noMoreItemsForLoadThisDirection = nothingToLoad || gottenEgdeOfCollection;
        this.SetScrollSpacerVisibility(isLoadindToTopByScroll, !noMoreItemsForLoadThisDirection);
        this.scrollHelper.Reset();
    },
    LoadItemsFromCallback: function(isToTop, itemStrings){
        this.BeginUpdate();
        if(isToTop){
            var scrollHeightCorrection = 0;
            for(var i = itemStrings.length - 1; i >= 0; i --){
                var itemStringAttrs = itemStrings[i].split(__aspxItemAttrsSeparator);
                this.InsertItem(0, itemStringAttrs[1], itemStringAttrs[0], itemStringAttrs[2]);
                scrollHeightCorrection += this.GetItemHeight(0);
            } 
            this.GetScrollDivElement().scrollTop += scrollHeightCorrection;
            this.serverIndexOfFirstItem -= itemStrings.length;
            if(this.serverIndexOfFirstItem < 0) this.serverIndexOfFirstItem = 0;
            
        } else {
            for(var i = 0; i < itemStrings.length; i ++){
                var itemStringAttrs = itemStrings[i].split(__aspxItemAttrsSeparator);
                this.AddItem(itemStringAttrs[1], itemStringAttrs[0], itemStringAttrs[2]);
            } 
        }
        if(this.changeSelectAfterCallback != 0) {
            var newIndex = this.GetSelectedIndexInternal() + this.changeSelectAfterCallback;
            newIndex = this.GetAdjustedIndex(newIndex);
            this.SelectIndexSilent(newIndex, false);
            
            if(this.scrollHelper.isScrolledToTopSpacer)
                this.ScrollItemToTop(newIndex);
            else
                this.ScrollToItemVisible(newIndex);
        }
        this.EndUpdate();
    },
    InCallback: function(){
        var callbackOwner = this.GetCallbackOwnerControl();
        if(callbackOwner != null)
            return callbackOwner.InCallback();
        return ASPxClientListEdit.prototype.InCallback.call(this);
    },
    GetItemsRangeForLoad: function(){
        return this.scrollHelper.GetItemsRangeForLoad();
    },
    GetScrollSpacerElement: function(isTop){
        return document.getElementById(this.name + (isTop ? __aspxLBTSIdSuffix : __aspxLBBSIdSuffix));
    },
    GetScrollSpacerVisibility: function(isTop){
        return isTop ? this.isTopSpacerVisible : this.isBottomSpacerVisible;
    },
    SetScrollSpacerVisibility: function(isTop, visibility){
        var spacer = this.GetScrollSpacerElement(isTop);
        if(_aspxIsExists(spacer)){
            if(visibility)
                spacer.style.height = this.GetScrollDivElement().clientHeight + "px";
            
            if(isTop)
                this.isTopSpacerVisible = visibility;
            else
                this.isBottomSpacerVisible = visibility;
                
            if(_aspxGetElementDisplay(spacer) != visibility){
                _aspxSetElementDisplay(spacer, visibility);
                _aspxGetElementVisibility(spacer, visibility);
            }
        }
    },
    SetTopScrollSpacerVisibility: function(visibility){
        this.SetScrollSpacerVisibility(true, visibility);
    },
    SetBottomScrollSpacerVisibility: function(visibility){
        this.SetScrollSpacerVisibility(false, visibility);
    },
    GetTopScrollSpacerHeight: function(){
        return this.isTopSpacerVisible ? this.GetScrollSpacerElement(true).clientHeight : 0;
    },
    GetBottomScrollSpacerHeight: function(){
        return this.isBottomSpacerVisible ? this.GetScrollSpacerElement(false).clientHeight : 0;
    },

    SendCallback: function(){
        if(!this.InCallback()){
            this.ShowLoadingPanel();
            var callbackOwner = this.GetCallbackOwnerControl();
            if(callbackOwner != null)
                callbackOwner.SendCallback();
             else {
                var argument = this.GetCallbackArguments();
                this.CreateCallback(argument);
            }
        }
    },
    OnCallback: function(result) {
        this.ParseCallbackResult(result);
        this.OnCallbackFinally();
    },
    OnCallbackError: function(result){
        ASPxClientListBoxBase.prototype.OnCallbackError.call(this, result);
        this.OnCallbackFinally();
    },
    OnCallbackFinally: function(){
        this.HideLoadingPanel();
        this.changeSelectAfterCallback = 0;
    },

    LockScrollHandler: function(){
        this.scrollHandlerLockCount ++;
    },
    UnlockScrollHandler: function(){
        this.scrollHandlerLockCount --;
    },
    IsScrollHandlerLocked: function(){
        return this.scrollHandlerLockCount > 0;
    },
    OnScroll: function(){
        if(this.IsScrollHandlerLocked()) return;
        
        if(!this.InCallback() && ( this.isTopSpacerVisible || this.isBottomSpacerVisible)) {
            this.scrollHelper.OnScroll();
            if(this.scrollHelper.GetIsNeedToHideTopSpacer())
                this.SetTopScrollSpacerVisibility(false);
            if(this.scrollHelper.GetIsNeedCallback())
                this.SendCallback();
        }
    },
    // Keyboard support
    InitializeKeyHandlers: function() {
        this.AddKeyDownHandler(ASPxKeyConsts.KEY_PAGEUP, "OnPageUp");
        this.AddKeyDownHandler(ASPxKeyConsts.KEY_PAGEDOWN, "OnPageDown");
        this.AddKeyDownHandler(ASPxKeyConsts.KEY_END, "OnEndKeyDown");
        this.AddKeyDownHandler(ASPxKeyConsts.KEY_HOME, "OnHomeKeyDown");
        this.AddKeyDownHandler(ASPxKeyConsts.KEY_UP, "OnArrowUp");
        this.AddKeyDownHandler(ASPxKeyConsts.KEY_DOWN, "OnArrowDown");
    },
    OnArrowUp: function(evt){
        this.SelectNeighbour(-1);
        return true;
    },
    OnArrowDown: function(evt){
        this.SelectNeighbour(1);
        return true;
    },
    OnPageUp: function(evt){
        this.SelectNeighbour(-this.scrollPageSize);
        return true;
    },
    OnPageDown: function(evt){
        this.SelectNeighbour(this.scrollPageSize);
        return true;
    },
    OnHomeKeyDown: function(evt){
        this.SelectNeighbour(-this.GetItemCount());
        return true;
    },
    OnEndKeyDown: function(evt){
        this.SelectNeighbour(this.GetItemCount());
        return true;
    },
    
    GetAdjustedIndex: function(index){
        if(index < 0) index = 0;
        else{
            var itemCount = this.GetItemCount();
            if(index >= itemCount) index = itemCount - 1;
        }
        return index;
    },
    SelectNeighbour: function (step){
        var itemCount = this.GetItemCount();
        if(itemCount > 0){
            this.changeSelectAfterCallback = 0;
            var selectedIndex = this.GetSelectedIndexInternal();
            var isFirstPageDown = selectedIndex == -1 && step == this.scrollPageSize;
            selectedIndex = isFirstPageDown ? step : selectedIndex + step;

            selectedIndex = this.GetAdjustedIndex(selectedIndex);
            this.SelectIndex(selectedIndex);

            if(this.GetIsNeedToCallbackLoadItemsToTop(selectedIndex, step, itemCount)){
                this.LoadItemsOnCallback(true, selectedIndex);
            } else if(this.GetIsNeedToCallbackLoadItemsToBottom(selectedIndex, step, itemCount)){
                this.LoadItemsOnCallback(false, selectedIndex);
            }
            this.ScrollToItemVisible(selectedIndex);
        }
    },
    GetIsNeedToCallbackLoadItemsToTop: function(selectedIndex, step, itemCount){
        return this.isCallbackMode && this.isTopSpacerVisible && 
            this.serverIndexOfFirstItem > 0 && ((step < 0 && selectedIndex <= 0) || step <= -itemCount);
    },
    GetIsNeedToCallbackLoadItemsToBottom: function(selectedIndex, step, itemCount){
        return this.isCallbackMode && this.isBottomSpacerVisible && 
            ((step > 0 && selectedIndex >= itemCount - 1) || step >= itemCount);
    },
    LoadItemsOnCallback: function(isToTop, index){
        this.changeSelectAfterCallback = index - this.GetSelectedIndexInternal();
        this.scrollHelper.SetItemsRangeForLoad(isToTop);
        this.SendCallback();
    },
    FindInputElement: function(){
        return document.getElementById(this.name + "_KBS");
    },
    
    // TODO Refactor this function - coincide with ASPxMenu and ASPxNavBar
    SetHoverElement: function(element){
        aspxGetStateController().SetCurrentHoverElementBySrcElement(element);
    },
    InitOnContainerMadeVisible: function(){
        this.AdjustControl(false);
    },
    SetSelectedIndex: function(index){
        if(index != this.GetSelectedIndexInternal())
            this.SelectIndexSilent(index, false);
    },
    ClearItemsCore: function(){
        this.ClearListTableContent();
        this.SetSelectedIndexInternal(-1);
        this.SetValue(null);
    },
    RemoveItem: function(index){
        if(0 <= index && index < this.GetItemCount()){
            this.UpdateSyncArraysItemDeleted(this.GetItem(index), true);
            var row = this.GetItemRow(index);
            if(_aspxIsExistsElement(row))
                row.parentNode.removeChild(row);
                
            var selectedIndex = this.GetSelectedIndexInternal();
            if(index < selectedIndex)
                this.SetSelectedIndexInternal(selectedIndex - 1);
            else if(index == selectedIndex)
                this.SetSelectedIndexInternal(-1);

        }
    },
    GetItem: function(index){
        var listTable = this.GetListTable();
        if(_aspxIsExists(listTable)){
            if(0 <= index && index < listTable.rows.length){
                var row = listTable.rows[index];
                var isImageExists = row.cells.length == 2;
                if(isImageExists)
                    var image = _aspxGetChildByTagName(row.cells[0], "IMG", 0);
                var textCell = row.cells[isImageExists ? 1 : 0];
                var text = _aspxGetInnerText(textCell);
                text = text.replace(new RegExp(String.fromCharCode(160), "g"), " ");
                var src = image == null ? "" : ASPxImageUtils.GetImageSrc(image);
                
                return new ASPxClientListEditItem(this, index, text, this.itemsValue[index], src);
            }
        }
        return null;
    },
    
    PerformCallback: function(arg) {
        this.SetScrollSpacerVisibility(true, false);
        this.SetScrollSpacerVisibility(false, false);
        
        this.ClearItemsForPerformCallback();
        this.serverIndexOfFirstItem = 0;
        this.SetScrollSpacerVisibility(true, false);
        this.SetScrollSpacerVisibility(false, false);
        
        this.FormatAndSetCustomCallbackArg(arg);
        this.SendCallback();
    },

    GetTableRowParent: function(table){
        if(table.tBodies.length > 0)
            return table.tBodies[0];
        return table;
    },
    ProtectWhitespaceSerieses: function(text){
        if(_aspxIsExists(text)){
            if(text == "" || text == " ") 
                text = __aspxNbsp;
            else{
                if(text.charAt(0) == ' ')
                    text = __aspxNbsp + text.slice(1);
                if(text.charAt(text.length - 1) == ' ')
                    text = text.slice(0, -1) + __aspxNbsp;
                text = text.replace(new RegExp("  ", "g"), " &nbsp;");
            }
        } 
        return text;
    },
    InsertItemInternal: function(index, text, value, imageUrl){
        if(!_aspxIsExists(imageUrl)) 
            imageUrl = "";
        if(!_aspxIsExists(value))     
            value = text;

        text = this.ProtectWhitespaceSerieses(text);
        
        var newItemRow = this.CreateNewItem();
        _aspxRemoveAttribute(newItemRow, "id");
        
        var listTable = this.GetListTable();
        var tbody = this.GetTableRowParent(listTable);
        var isAdd = listTable.rows.length <= index;
        if(isAdd)
            tbody.appendChild(newItemRow);
        else
            tbody.insertBefore(newItemRow, this.GetItemRow(index));
        
        var newIndex = this.FindFreeIndex();
        var newId = this.CreateItemId(newIndex);
        var newClientId = this.CreateItemClientId(newIndex);
        this.InitializeItemAttributes(newItemRow, newClientId, true);
        var sampleCellElement = this.GetSampleItemTextCell();
        aspxAddHoverItems(this.name, this.CreateStyleClasses(sampleCellElement, newId, __aspxLBIPostfixes, true));
        aspxAddSelectedItems(this.name, this.CreateStyleClasses(sampleCellElement, newId, __aspxLBIPostfixes, false));
        _aspxRemoveAttribute(sampleCellElement, __aspxCachedHoverItemKind);
        _aspxRemoveAttribute(sampleCellElement, __aspxCachedSelectedItemKind);
        this.PrepareItem(newItemRow, text, imageUrl);
        this.AddItemClass(index, text, value, imageUrl); // TODO make possible to remove
        
        var selectedIndex = this.GetSelectedIndexInternal();
        if(index <= selectedIndex && selectedIndex != -1){
            this.SetSelectedIndexInternal(selectedIndex + 1);
        }
    },
    PrepareItem: function(newItemRow, text, imageUrl){
        if(newItemRow.cells.length == 2){
            var imageCell = newItemRow.cells[0];
            var image = _aspxGetChildByTagName(imageCell, 'img', 0);
            if(!_aspxIsExists(image)){
                image = document.createElement('img');
                imageCell.innerHTML = "";
                imageCell.appendChild(image);
            }
            ASPxImageUtils.SetImageSrc(image, imageUrl);
            
            newItemRow.cells[1].innerHTML = text;
        } else
            newItemRow.cells[0].innerHTML = text;
    },
    ClearListTableContent: function(){
        var tBody = this.GetTableRowParent(this.GetListTable());
        if(__aspxIE)
            tBody.innerText = "";
        else
            tBody.innerHTML = "";
    },

    CreateItemId: function(index){
        return __aspxLBIIdSuffix + index;
    },
    CreateItemClientId: function(index){
        return this.name + "_" + __aspxLBIIdSuffix + index;
    },
    CreateNewItem: function(){
        var newItemRow = this.GetSampleItem();
        if (_aspxIsExistsElement(newItemRow)) 
            newItemRow = newItemRow.cloneNode(true);
        return newItemRow;
    },
    CreateStyleClasses: function(sampleElement, id, postfixes, isHover){
        var styleController = aspxGetStateController();
        var item = isHover ? styleController.GetHoverElement(sampleElement) : 
            styleController.GetSelectedElement(sampleElement);
        var kind = isHover ? __aspxHoverItemKind : __aspxSelectedItemKind;
        
        var classes = [];
        if(_aspxIsExists(item) && _aspxIsExists(item[kind])){
            classes[0] = [];
            classes[0][0] = item[kind].className;
            classes[0][1] = item[kind].cssText;
            classes[0][2] = [];
            classes[0][2][0] = id;
            classes[0][3] = postfixes;
        }
        return classes;
    },
    CorrectSizeByTimer: function(){
        if(this.APILockCount == 0 && this.IsDisplayed())
            _aspxSetTimeout("aspxLBCorrectSizeByTimer(\""+this.name+"\");", 0);
    },
    FindFreeIndex: function(){
        return this.freeUniqIndex ++;
    },
    GetSampleItemID: function(){
        return this.name + "_" + __aspxLBSIIdSuffix;
    },
    GetSampleItem: function(){
        if(this.SampleItem == null)
            this.SampleItem = _aspxGetElementById(this.GetSampleItemID());
        return this.SampleItem;
    },
    GetSampleItemTextCell: function(){
        if(!_aspxIsExistsElement(this.sampleItemTextCell))
            this.sampleItemTextCell = _aspxGetElementById(this.GetSampleItemID() + __aspxLBIPostfixes[1]);
        return this.sampleItemTextCell;
    },
    ChangeEnabledAttributes: function(enabled){
        this.ChangeListTableEvents(this.GetListTable(), _aspxChangeEventsMethod(enabled));
        var inputElement = this.GetInputElement();
        if(_aspxIsExists(inputElement)) 
            this.ChangeSpecialInputEnabledAttributes(inputElement, _aspxChangeEventsMethod(enabled));
    },
    ChangeEnabledStateItems: function(enabled){
        var controller = aspxGetStateController();
        controller.SetElementEnabled(this.GetMainElement(), enabled);

        var count = this.GetItemCount();
        var i = this.hasSampleItem ? -1 : 0 ;
        for(; i < count; i ++){
            var element = this.GetItemTextCell(i);
            if(_aspxIsExists(element))
                controller.SetElementEnabled(element, enabled);
        }
    },
    ChangeListTableEvents: function(listTable, method){
        if(this.isComboBoxList){
            method(listTable, "mouseup", aspxLBIClick);
            if(__aspxFirefox)// FIX prevent to wront continues selection by item click
                method(listTable, "mousedown", _aspxPreventEvent); 
        }
        else{
            method(listTable, "click", aspxLBIClick);   
            method(listTable, "dblclick", aspxLBIClick);    
        }
    }
});

ASPxClientNativeListBox = _aspxCreateClass(ASPxClientListBoxBase, {
    constructor: function(name) {
        this.constructor.prototype.constructor.call(this, name);
    },
    
    SetMainElement: function(mainElement){
        this.mainElement = mainElement;
    },
    FindInputElement: function(){
        return this.GetMainElement();
    },    

    GetOptionCount: function(){
        return this.GetMainElement().options.length;
    },
    GetOption: function(index){
        return this.GetMainElement().options[index];
    },
    
    GetItemCount: function(){
        return this.GetOptionCount();
    },
    SelectIndexSilent: function(index, initialize){
        var selectedIndex = this.GetSelectedIndexInternal();
        var isValidIndex = (-1 <= index && index < this.GetItemCount());
        if((selectedIndex != index && isValidIndex) || initialize){
            this.SetSelectedIndexInternal(index);
            return true;
        }
        return false;
    },
    GetSelectedIndexInternal: function(){
        return this.GetMainElement().selectedIndex; 
    },
    SetSelectedIndexInternal: function(index){
        this.GetMainElement().selectedIndex = index; 
    },
    ClearItemsCore: function(){
        this.GetMainElement().innerHTML = "";
    },
    RemoveItem: function(index){
        if(0 <= index && index < this.GetItemCount()){
            var oldSelectedIndex = this.GetSelectedIndexInternal();
            this.UpdateSyncArraysItemDeleted(this.GetItem(index), true);
            
            var option = this.GetOption(index);
            this.GetMainElement().removeChild(option);
            
            this.UpdateOptionValues();
            if(index == oldSelectedIndex)
                this.SetSelectedIndexInternal(-1);
        }
    },
    GetItem: function(index){
        if(0 <= index && index < this.GetOptionCount()) {
            var text = this.GetOption(index).text;
            if(_aspxIsExists(text))
                return new ASPxClientListEditItem(this, index, text, this.itemsValue[index], "");
        }
        return null;
    },
    PerformCallback: function(arg) {
        this.ClearItemsForPerformCallback();
        this.FormatAndSetCustomCallbackArg(arg);
        this.SendCallback();
    },
    SendCallback: function(){
        if(!this.InCallback()){
            var callbackOwner = this.GetCallbackOwnerControl();
            if(callbackOwner != null)
                callbackOwner.SendCallback();
             else {
                var argument = this.GetCallbackArguments();
                this.CreateCallback(argument);
            }
        }
    },
    ParseCallbackResult: function(result){
        var itemStrings = result.split(__aspxItemsSeparator);
        this.LoadItemsFromCallback(true, itemStrings);
    },
    
    InsertItemInternal: function(index, text, value, imageUrl){
        if(!_aspxIsExists(value))     
            value = text;
        var oldSelectedIndex = this.GetSelectedIndexInternal();
            
        var isAdd = this.GetOptionCount() <= index;
        var newOption = document.createElement("OPTION");
        if(isAdd)
            this.GetMainElement().appendChild(newOption);
        else
            this.GetMainElement().insertBefore(newOption, this.GetOption(index));
        newOption.innerHTML = text;
        this.UpdateOptionValues();
        
        this.AddItemClass(index, text, value, imageUrl); // TODO make possible to remove
        if(index == oldSelectedIndex && index != -1)
            this.SetSelectedIndex(index + 1);
    },
    UpdateOptionValues: function() {
        for(var i = 0; i < this.GetOptionCount(); i++)
            this.GetOption(i).value = i;
    },
    ChangeEnabledAttributes: function(enabled){
        if(!this.isComboBoxList)
            this.GetMainElement().disabled = !enabled;
    },
    OnCallback: function(result) {
        this.ParseCallbackResult(result);
    },
    LoadItemsFromCallback: function(isToTop, itemStrings){
        this.BeginUpdate();
        for(var i = itemStrings.length - 1; i >= 0; i --){
            var itemStringAttrs = itemStrings[i].split(__aspxItemAttrsSeparator);
            this.InsertItem(0, itemStringAttrs[1], itemStringAttrs[0], itemStringAttrs[2]);
        } 
        this.EndUpdate();
    }
});
ASPxClientRadioButtonList = _aspxCreateClass(ASPxClientListEdit, {
    constructor: function(name) {
        this.constructor.prototype.constructor.call(this, name);                                        
        
        this.items = [];
        this.itemCount = 0;
	},
	InlineInitialize: function() {
	    var selectedIndex = this.GetSelectedIndex();
	    this.UpdateHiddenInputs(selectedIndex);
	},
    SetFocus: function() {
        var index = this.GetSelectedIndexInternal();
        if(index == -1)
            index = 0;
        var itemElement = this.GetItemElement(index);
        if (itemElement != null && _aspxGetActiveElement() != itemElement && _aspxIsEditorFocusable(itemElement)) 
            _aspxSetFocus(itemElement);
    },
    GetInputElement: function() {
        var index = this.GetSelectedIndexInternal();
        return this.GetItemElement(index);
    },
    GetValueInputElement: function() {
        if(this.valueInput == null) {
            this.valueInput = _aspxCreateHiddenField(null, this.name + "_ValueInput");
            var stateInput = this.FindStateInputElement();
            stateInput.parentNode.insertBefore(this.valueInput, stateInput);
        }
        return this.valueInput;
    },
    GetValueInputToValidate: function() {
        return this.GetValueInputElement();
    },
    GetItemElement: function(index) {
        return this.GetChild("_RB" + index + "_I");
    },
    GetItemMainElement: function(index) {
        return this.GetChild("_RB" + index);
    },
    GetItemCount: function() {
        return this.items.length;
    },
    OnItemClick: function(index) {
        if(this.GetSelectedIndexInternal() != index) {
            this.SelectIndexSilent(index);
            this.RaisePersonalStandardValidation();
            this.OnValueChanged();
        }
    },
    OnItemClickReadonly: function() {
        var index = this.GetSelectedIndexInternal();
        this.SelectIndexSilent(index);
    },
    UpdateHiddenInputs: function(index) {
        var stateInput = this.FindStateInputElement();
        if(_aspxIsExistsElement(stateInput))
            stateInput.value = index;
        
        // Standard validation support
        var valueInput = this.GetValueInputElement();
        if(_aspxIsExistsElement(valueInput)) {
            // [Victor] Standard validation mechanism trying to receive a value of an editor doens't
            // treat empty value string as a value at all and continue searching. So, we must store
            // at least one whitespace character to force validators to use our value input.
            var value = this.GetValue();
            valueInput.value = _aspxIsExists(value) ? value : " ";
        }
    },
    SelectIndexSilent: function(index) {
        var itemCount = (this.items.length > 0) ? this.items.length : this.itemCount;
        var isValidIndex = (-1 <= index && index < itemCount);
        if(isValidIndex) {
            for(var i = 0; i < itemCount; i++) {
                if(_aspxIsExists(this.GetItemElement(i)))
                    this.GetItemElement(i).checked = (i == index);
            }
            this.SetSelectedIndexInternal(index);
            this.UpdateHiddenInputs(index);
        }
    },
        
    GetItemValue: function(index){
        if (index > -1 && index < this.items.length) {
            if (typeof(this.items[index].value) && this.items[index].value == "" && this.convertEmptyStringToNull)
                return null;
            else
                return this.items[index].value;
        }
        return null;
    },
    // value
    SetValue: function(value) {
        for (var i = 0; i < this.items.length; i++) {
            if(this.GetItemValue(i) == value) {            
                this.SelectIndexSilent(i);
                return;
            }
        } 
        this.SelectIndexSilent(-1);       
    },
    // API
    CreateItems: function(itemsProperties){
        for(var i = 0; i < itemsProperties.length; i ++)
            this.CreateItem(i, itemsProperties[i][0], itemsProperties[i][1], itemsProperties[i][2]);
    },
    CreateItem: function(index, text, value, imageUrl){
        var item = new ASPxClientListEditItem(this, index, text, value, imageUrl);
        _aspxArrayPush(this.items, item);
    },
    GetItem: function(index){
        return (0 <= index && index < this.items.length) ? this.items[index] : null;
    },
    
    ChangeEnabledAttributes: function(enabled){
        for(var i = 0; i < this.GetItemCount(); i++){        
            var element = this.GetItemElement(i);
            if(_aspxIsExists(element)){
                this.ChangeItemEnabledAttributes(element, _aspxChangeAttributesMethod(enabled));
                element.disabled = !enabled;
            }
        }
    },
    ChangeEnabledStateItems: function(enabled){
        aspxGetStateController().SetElementEnabled(this.GetMainElement(), enabled);
        for(var i = 0; i < this.GetItemCount(); i++){        
            var element = this.GetItemMainElement(i);
            if(_aspxIsExists(element))
                aspxGetStateController().SetElementEnabled(element, enabled);
        }
    },
	ChangeItemEnabledAttributes: function(element, method){
        method(element, "onclick");
	}
});


function aspxLBIClick(evt){
    var element = _aspxGetEventSource(evt);
    while(element != null && element.tagName != "BODY"){
        if(element.tagName == "TR"){
		    var table = element.offsetParent;
		    if(_aspxIsExists(table) && _aspxIsExists(table.ListBoxId)){
		        var lb = aspxGetControlCollection().Get(table.ListBoxId);
		        if(lb != null) {
		            if(evt.type == "dblclick") lb.OnItemDblClick();
		            else if(!lb.isComboBoxList || _aspxGetIsLeftButtonPressed(evt)) 
		                lb.OnItemClick(element.rowIndex);
		        }
        		break;
		    }
		}
        element = element.parentNode;
	}
}
function aspxLBScroll(evt){
    var sourceId = _aspxGetEventSource(evt).id;
    if(sourceId.slice(-__aspxLBDSuffix.length) == __aspxLBDSuffix){
        var name = sourceId.slice(0, -2);
        var lb = aspxGetControlCollection().Get(name);
        if(lb != null) 
            lb.OnScroll();
    }
}
function aspxLBCorrectSizeByTimer(name){
    var lb = aspxGetControlCollection().Get(name);
    if(lb != null)
        lb.CorrectSizeInternalByTimer();
}

function aspxERBLIClick(name, index) {
    var list = aspxGetControlCollection().Get(name);
    if(list != null)
        list.OnItemClick(index);
}
function aspxERBLICancel(name) {
    var list = aspxGetControlCollection().Get(name);
    if(list != null)
        list.OnItemClickReadonly();
}