

var __aspxItemAttrsSeparator = "::";
var __aspxItemsSeparator = ";;";
var __aspxLoadRangeItemsCallbackPrefix = "LBCRI";
var __aspxLBIPostfixes = ['I', 'T'];
var __aspxLBIIdSuffix = "LBI";
var __aspxLBSIIdSuffix = __aspxLBIIdSuffix + "-1";
var __aspxLBBSIdSuffix = "_BS";
var __aspxLTableIdSuffix = "_LBT";
var __aspxLEVISuffix = "_VI";
var __aspxLBDSuffix = "_D";

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;
	    this.readOnly = false;
	},
    RaiseValueChangedEvent: function() {
        var processOnServer = ASPxClientEdit.prototype.RaiseValueChangedEvent.call(this);
        if(_aspxIsExists(this.RaiseSelectedIndexChanged))
            processOnServer = this.RaiseSelectedIndexChanged(processOnServer);
        return processOnServer;
    },
    FindInputElement: function() {
        return document.getElementById(this.name + __aspxLEVISuffix);
    },
    GetValue: function(){
        return this.GetItemValue(this.GetSelectedIndexInternal());
    },    
    GetSelectedIndexInternal: function(){
        return this.savedSelectedIndex;
    }, 
    SetSelectedIndexInternal: function(index){
        this.savedSelectedIndex = index;
    },
    OnSelectedIndexChanged: function(index) {
        var selectedIndex = this.GetSelectedIndexInternal();
        if (!this.readOnly && (index != selectedIndex)) {
            this.SetSelectedIndexInternal(index);
            this.OnValueChanged();
        }
    },
    // 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;
    },
    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.SelectIndex(index);
    },
    SetSelectedIndex: function(index){
        this.SelectIndex(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;
    }
});
ASPxClientListBox = _aspxCreateClass(ASPxClientListEdit, {
    constructor: function(name) {
        this.constructor.prototype.constructor.call(this, name);
        
        this.APILockCount = 0;
        this.freeUniqIndex = -1;
        this.isComboBoxList = false;
        this.isHasFakeRow = false;
        this.isSyncEnabled = true;
        this.ownerName = "";
        this.listTable = null;
        this.sampleItemTextCell = null;
        this.width = "";
        this.hasSampleItem = false;
        this.hoverClass = "";
        this.hoverCss = "";
        this.selectedClass = "";
        this.selectedCss = "";
        // Callback
        this.allowMultipleCallbacks = false;
        this.isCallbackMode = false;
        this.callbackPageSize = -1;
        this.bottomSpace = 0;
        // Cashe
        this.ownerControl = null;
        this.SampleItem = null;
        this.scrollDivElement = null;
        this.scrollPageSize = 4;
        this.deletedItems = [];
        this.insertedItems = [];
        this.itemsValue = [];    
        this.ItemDoubleClick = new ASPxClientEvent();
    },
    Initialize: function() {   
        var listTable = this.GetListTable();
        this.freeUniqIndex = this.GetItemCount();
        
        this.InitKeyboardInput();
        this.InitListTable(listTable);
        this.InitializeItemsAttributes(listTable);
        this.GenerateHoverSelected();
        this.SelectIndex(this.GetSelectedIndexInternal(), true);
        this.CorrectSize(false);
        ASPxClientEdit.prototype.Initialize.call(this);
    },
    CallbackSpaceInit: function(){
        if(this.isCallbackMode){
            if(this.GetItemCount() == this.callbackPageSize)
                this.SetBottomScrollSpacingVisibility(true);
            var divElement = this.GetScrollDivElement();
            _aspxAttachEventToElement(divElement, "scroll", aspxLBScroll);
        }
    },
    InitListTable: function(listTable){
        if(this.isComboBoxList){
            _aspxAttachEventToElement(listTable, "mouseup", aspxLBIClick);
            if(__aspxFirefox)// FIX prevent to wront continues selection by item click
                _aspxAttachEventToElement(listTable, "mousedown", _aspxPreventEvent); 
        }
        else{
            _aspxAttachEventToElement(listTable, "click", aspxLBIClick);   
            _aspxAttachEventToElement(listTable, "dblclick", aspxLBIClick);    
        }
    },
    InitializeItemsAttributes: function() { 
        var listTable = this.GetListTable();
        if(this.isHasFakeRow && _aspxIsExists(this.ClearItems))
            this.ClearItems();
        
        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;
    },
    InitKeyboardInput: function(){
        var kbInput = this.FindInputElement();        
        if (_aspxIsExistsElement(kbInput)) {
            kbInput.autocomplete = "off";
            _aspxAttachKBSupportEventsToElement(kbInput, this.name);
        }
    },
    GenerateHoverSelected: 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);
        }
    },
    IsVisibleWhenCorrectingSize: function() {
        return this.IsDisplayed();
    },
    CorrectSizeCore: function(){
        ASPxClientEdit.prototype.CorrectSizeCore.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();
    },
    CorrectHeight: function(){
        //if(this.GetItemCount() == 0) return;

        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){
            topVisible = itemElement.offsetTop > scrollDiv.scrollTop;
            bottomVisible = itemElement.offsetTop + itemElement.offsetHeight < scrollDiv.scrollTop + scrollDiv.clientHeight;
        }
        return (topVisible && bottomVisible);
    },
    ScrollItemToTop: function(index){
        var scrollDiv = this.GetScrollDivElement();
        if(_aspxIsExists(scrollDiv)) // Render may be removed when callback processing
            scrollDiv.scrollTop = this.GetItemTopOffset(index);
    },
    ScrollToItemVisible: function(index){
        if(!this.IsItemVisible(index)){
            var scrollDiv = this.GetScrollDivElement();
            var scrollTop = scrollDiv.scrollTop;
            var scrollDivHeight = scrollDiv.clientHeight;
            var itemOffetTop = this.GetItemTopOffset(index);
            var itemHeight = this.GetItemHeight(index);
            
            var itemAbove = scrollTop > itemOffetTop;
            var itemBelow = scrollTop  + scrollDivHeight < itemOffetTop + itemHeight;
            if(itemAbove)
                scrollDiv.scrollTop = itemOffetTop;
            else if(itemBelow){
                var scrollPaddings = scrollDiv.scrollHeight - this.GetListTable().offsetHeight - this.bottomSpace;
                scrollDiv.scrollTop = itemOffetTop + 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 : 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;
    },
    GetItemIndexByValue: function(value){
        for(var i = this.GetItemCount() - 1; i >= 0 ; i--){
            if(this.GetItemValue(i) == value)
                break;
        }
        return i;
    },
    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];
    },
    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;
    },
    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.SelectIndex(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)
            return element.style.overflowY;
        return element.style.overflow;
    },
    SetVerticalOverflow: function(element, value){
        if(__aspxIE)
            element.style.overflowY = value;
        else
            element.style.overflow = value;
    },
            
    OnItemClick: function(index){
        this.SelectIndexInternal(index);
        this.EnsureSelectedItemVisible();
        this.SetFocus();
    },
    OnItemDblClick: function(){
        this.RaiseItemDoubleClick();
    },
    SelectIndex: 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;
    },
    SelectIndexInternal: function (index){
        if(this.SelectIndex(index, false)){
            this.RaisePersonalStandardValidation();
            this.OnValueChanged();
        }
    },
    // LoadingPanel
    ShowLoadingPanel: function() {    
        if(!this.isComboBoxList){
            var loadingParentElement = this.GetScrollDivElement().parentNode;
            this.loadingDivElement = this.CreateLoadingDiv(loadingParentElement);
            this.loadingPanelElement = this.CreateLoadingPanelWithAbsolutePosition(loadingParentElement);
        }
    },
    HideLoadingPanel: function() {
        if(!this.isComboBoxList){
            if(_aspxIsExistsElement(this.loadingPanelElement)) {
                this.loadingPanelElement.parentNode.removeChild(this.loadingPanelElement);                        
                this.loadingPanelElement = null;
            }
            if(_aspxIsExistsElement(this.loadingDivElement)){
                this.loadingDivElement.parentNode.removeChild(this.loadingDivElement);
                this.loadingDivElement = null;
            }
        }
    },  
    // CallbackMode
    AddItemsFromCallbackResult: function(result){
        var isBottomScrollSpacerVisible = false;
        if(result != ""){
            this.BeginUpdate();
            var itemStrings = result.split(__aspxItemsSeparator);
            for(var i = 0; i < itemStrings.length; i ++){
                var itemStringAttrs = itemStrings[i].split(__aspxItemAttrsSeparator);
                this.AddItem(itemStringAttrs[1], itemStringAttrs[0], itemStringAttrs[2]);
            } 
            this.EndUpdate();
            isBottomScrollSpacerVisible = (itemStrings.length == this.callbackPageSize);
        }
        this.SetBottomScrollSpacingVisibility(isBottomScrollSpacerVisible);
    },
    FormatCallbackArg: function(prefix, arg) { // REFACTOR with ASPxGrigView, replace to Callback.js
        if(arg == null) return "";
        if(!_aspxIsExists(arg.length) && _aspxIsExists(arg.value)) {
            arg = arg.value;
        }
        if(arg == null || arg == "") return "";
        return prefix + "|" + arg.length + ';' + arg + ';';
    },
    InCallback: function(){
        var callbackOwner = this.GetCallbackOwnerControl();
        if(callbackOwner != null)
            return callbackOwner.InCallback();
        return ASPxClientListEdit.prototype.InCallback.call(this);
    },
    GetCallbackOwnerControl: function(){
        if(this.ownerName != "" && !_aspxIsExists(this.ownerControl))
            this.ownerControl = aspxGetControlCollection().Get(this.ownerName);
        return this.ownerControl;
    },
    GetCallbackArguments: function(){
        var args = _aspxIsExists(this.GetCustomCallbackArg) ? this.GetCustomCallbackArg() : "";
        var beginIndex = this.isCallbackMode ? this.GetItemCount() : 0;
        var endIndex = this.isCallbackMode ? (beginIndex + this.callbackPageSize - 1) : -1;
        args += this.FormatCallbackArg(__aspxLoadRangeItemsCallbackPrefix, beginIndex + ":" + endIndex); 
        return args;
    },
    LoadNextItemsOnCallback: function(){
        this.SendCallback();
    },
    GetBottomScrollSpacingElement: function(){
        return document.getElementById(this.name + __aspxLBBSIdSuffix);
    },
    IsScrollSpacerVisible: function(){
        var bottomSpaser = this.GetBottomScrollSpacingElement();
        if(_aspxIsExists(bottomSpaser))
            return _aspxGetElementDisplay(bottomSpaser);
        return false;
    },
    SetBottomScrollSpacingVisibility: function(visibility){
        var bottomSpaser = this.GetBottomScrollSpacingElement();
        if(_aspxIsExists(bottomSpaser)){
            var isVisible = _aspxGetElementDisplay(bottomSpaser);
            if(visibility){
                var divElement = this.GetScrollDivElement();
                this.bottomSpace = divElement.clientHeight;
                bottomSpaser.style.height = this.bottomSpace + "px";
            } else 
                this.bottomSpace = 0;
            
            if(isVisible != visibility){
                _aspxSetElementDisplay(bottomSpaser, visibility);
                _aspxGetElementVisibility(bottomSpaser, visibility);
            }
        }
    },
    SendCallback: function(){
        if(!this.InCallback()){
            this.ShowLoadingPanel();
            var callbackOwner = this.GetCallbackOwnerControl();
            if(callbackOwner != null)
                callbackOwner.SendCallback();
             else {
                var argument = this.GetCallbackArguments();
                this.CreateCallback(argument);
            }
        }
    },
    OnAfterCallback: function(){
        this.HideLoadingPanel();
    },
    OnCallback: function(result) {
        this.AddItemsFromCallbackResult(result);
        this.OnAfterCallback();
    },
    OnCallbackError: function(result){
//        if(_aspxIsExists(this.AddItem))
//            this.AddItem(result);
        this.OnAfterCallback();
    },

    OnScroll: function(){
        if(this.InCallback() || !this.IsScrollSpacerVisible()) 
            return;

        var divElement = this.GetScrollDivElement();
        var listTable = this.GetListTable();
        var scrollBottom = divElement.scrollTop + divElement.clientHeight;
        var isBottomSpaceVisible = (scrollBottom > listTable.clientHeight);
        if(isBottomSpaceVisible)
            this.LoadNextItemsOnCallback();
    },
    // Key Board support
    OnArrowUp: function(){
        this.SelectNeighbour(-1);
        return true;
    },
    OnArrowDown: function(){
        this.SelectNeighbour(1);
        return true;
    },
    OnPageUp: function(){
        this.SelectNeighbour(-this.scrollPageSize);
        return true;
    },
    OnPageDown: function(){
        this.SelectNeighbour(this.scrollPageSize);
        return true;
    },
    OnHomeKeyDown: function(){
        this.SelectNeighbour(-this.GetItemCount());
        return true;
    },
    OnEndKeyDown: function(){
        this.SelectNeighbour(this.GetItemCount());
        return true;
    },
    SelectNeighbour: function (step){
        var itemCount = this.GetItemCount();
        if(itemCount > 0){
            var index = this.GetSelectedIndexInternal();
            var isFirstPageDown = index == -1 && step == this.scrollPageSize;
            index = isFirstPageDown ? step : index + step;
            
            if((step < 0 && index < 0) || step <= -itemCount)
                index = 0;
            if((step > 0 && index >= itemCount) || step >= itemCount){
                index = itemCount - 1;
                if(this.isCallbackMode && this.IsScrollSpacerVisible())
                    this.LoadNextItemsOnCallback();
            }
            this.SelectIndexInternal(index);
            this.ScrollToItemVisible(index);
        }
    },
    FindInputElement: function(){
        return document.getElementById(this.name + "_KBS");
    },
    FindStateInputElement: function(){
        return document.getElementById(this.name + __aspxLEVISuffix);
    },
    
    // TODO Refactor this function - coincide with ASPxMenu and ASPxNavBar
    SetHoverElement: function(element){
        aspxGetStateController().SetCurrentHoverElementBySrcElement(element);
    },
    UpdateHiddenInputs: function(index){
        var element = this.FindStateInputElement();
        if(_aspxIsExistsElement(element)) {
            var value = this.GetItemValue(index);
            if (value == null)
                value = "";
            element.value = value;
        }
    },
    // API
    InitOnContainerMadeVisible: function(){
        this.CorrectSize(false);
    },
    SetSelectedIndex: function(index){
        if(index != this.GetSelectedIndexInternal())
            this.SelectIndex(index, false);
    },
    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);
    },
    BeginUpdate: function(){
        this.APILockCount ++;
    },
    EndUpdate: function(){
        this.APILockCount --;
        this.Synchronize();
    },
    ClearItems: function(){
        this.BeginUpdate();
        this.RemoveItemsClasses();
        this.ClearItemsInternal();

        this.SetSelectedIndexInternal(-1);
        this.SetValue(null);
        this.EndUpdate();
    },
    RemoveItem: function(index){
        if(0 <= index && index < this.GetItemCount()){
            this.RemoveItemClass(this.GetItem(index));
            var row = this.GetItemRow(index);
            if(_aspxIsExistsElement(row)){
                if(index == this.GetSelectedIndexInternal())
                    this.SetSelectedIndexInternal(-1);
                row.parentNode.removeChild(row);
            }
        }
    },
    GetItem: function(index){
        var item = null;
        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);
                if(text == "&nbsp;" || text.charCodeAt(0) == 160)
                    text = " ";
                // TODO: __aspxSafari OnlyReplase &amp; with &
                
                item = new ASPxClientListEditItem(this, index, text, this.itemsValue[index], image == null ? "" : image.src);
            }
        }
        return item;
    },
    PerformCallback: function(arg) {
        this.ClearItems();
        this.SetCustomCallbackArg(this.FormatCallbackArg("LECC", arg));
        this.SendCallback();
    },

    GetCustomCallbackArg: function(){
        return this.GetSyncroHiddenInput("CustomCallback").value;
    },
    SetCustomCallbackArg: function(arg){
        this.GetSyncroHiddenInput("CustomCallback").value = arg;
    },
    GetTableRowParent: function(table){
        if(table.tBodies.length > 0)
            return table.tBodies[0];
        return table;
    },
    InsertItemInternal: function(index, text, value, imageUrl){
        if(!_aspxIsExists(imageUrl)) 
            imageUrl = "";
        if(!_aspxIsExists(value))     
            value = text;
        if(typeof(text) == "string" && (text == "" || text == " "))
            text = "&nbsp;";

        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.AddItemClass(index, text, value, imageUrl); // TODO make possible to remove
        this.PrepareItem(newItemRow, text, imageUrl);
        if(index == this.GetSelectedIndexInternal() && index != -1)
            this.SetSelectedIndex(index + 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);
            }
            this.SetImageSrc(image, imageUrl);
            
            newItemRow.cells[1].innerHTML = text;
        } else
            newItemRow.cells[0].innerHTML = text;
    },
    SetImageSrc: function(image, src){
        var isFilterNeed = this.IsAlphaFilterNeed(src);
        image.src = isFilterNeed ? __dxSpaceImageUrl : src;
        if(__aspxIE && !__aspxIE7)
            image.style.filter = isFilterNeed ? this.CreateImageFilterStyle(src) : "";
    },
    CreateImageFilterStyle: function(src){
        return "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + src + ", sizingMethod=scale)"
    },
    IsAlphaFilterNeed: function(src){
        return (__aspxIE && !__aspxIE7 && src.slice(-3).toLowerCase() === "png");
    },
    ClearItemsInternal: function(){
        var tBody = this.GetTableRowParent(this.GetListTable());
        if(__aspxIE)
            tBody.innerText = "";
        else
            tBody.innerHTML = "";
    },

    AddItemClass: function(index, text, value, imageUrl){
        _aspxArrayInsert(this.itemsValue, value, index);
        if(this.isSyncEnabled){
            var item = new ASPxClientListEditItem(this, index, text, value, imageUrl);
            _aspxArrayPush(this.insertedItems, item);
            this.Synchronize();
        }
    },
    RemoveItemClass: function(item){
        _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)
                _aspxArrayPush(this.deletedItems, item);
            else
                _aspxArrayRemoveAt(this.insertedItems, index);
            this.Synchronize();
        }
    },
    RemoveItemsClasses: function(){
        for(var i = this.GetItemCount() - 1; i >= 0; i --)
            this.RemoveItemClass(this.GetItem(i));
    },
    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;
    },

    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 ++;
    },
    GetCorrectString: function(string){
        return _aspxIsExists(string) ? string : "";
    },
    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;
    },
    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();
        }
    },
    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 "";
    }
});
ASPxClientRadioButtonList = _aspxCreateClass(ASPxClientListEdit, {
    constructor: function(name) {
        this.constructor.prototype.constructor.call(this, name);                                        
        this.items = [];        
	},
    InvalidateInputElement: function() {
        this.inputElement = null;
    },
    FindInputElement: function() {
        var index = this.GetSelectedIndexInternal();
        return this.GetItemElement(index);
    },
    GetItemElement: function(index) {
        return _aspxGetElementById(this.name + "_RB" + index + "_I");
    },
    GetItemCount: function() {
        return this.items.length;
    },
    OnItemClick: function(index) {
        if(this.GetSelectedIndexInternal() != index) {
            this.SelectIndex(index);
            this.OnValueChanged();
        }
    },
    OnItemClickReadonly: function() {
        var index = this.GetSelectedIndexInternal();
        if(index < 0) {
            // tricky
            var item = this.GetItemElement(0);
            item.checked = true;
            item.checked = false;
        } else {
            this.SelectIndex(index, true);
        }
    },
    SelectIndex: function(index, readonlyClick) {
        var selectedIndex = this.GetSelectedIndexInternal();
        var isValidIndex = (-1 <= index && index < this.GetItemCount());
        if(isValidIndex && (readonlyClick || selectedIndex != index && !this.readOnly)) {
            if(index > -1) {
                if(_aspxIsExists(this.GetItemElement(index)))
                    this.GetItemElement(index).checked = true;
                else
                    return false;
            } else {
                for(var i = 0; i < this.items.length; i++) {
                    var itemIndex = this.items[i].index;
                    if(_aspxIsExists(this.GetItemElement(itemIndex)))
                        this.GetItemElement(itemIndex).checked = false;
                    else
                        return false;
                }
            }
            this.SetSelectedIndexInternal(index);

            return true;
        }
        return false;
    },
        
    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.SelectIndex(i);
                return;
            }
        } 
        this.SelectIndex(-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]);
    },
    GetItem: function(index){
        return (0 <= index && index < this.items.length) ? this.items[index] : null;
    },
    CreateItem: function(index, text, value, imageUrl){
        var item = new ASPxClientListEditItem(this, index, text, value, imageUrl);
        _aspxArrayPush(this.items, item);
    }
});


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 lb.OnItemClick(element.rowIndex);
		        }
        		break;
		    }
		}
        element = _aspxGetParentNode(element);
	}
}
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.CorrectSizeInternal();
}

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();
}