$package('ejs.events',
    $class('ComboBoxEvent').$extends(ejs.events.Event).$define(
        $static({
            CHANGE:'change-event',
            UNFOLD:'unfold-event',
            FOLD:'fold-event',
            CLICK:'click-event'
        })
    )
);

$package('ejs.controls',
    $class('ComboBoxItem').$implements(ejs.events.IEventDispatcher).$define(
        $public({
            $self:null,
            $owner:null,
            skinClass:'',
            construct:function(){
                var arg = arguments[0];
                if(ejs.isObject(arg)){
                    this._text = arg.text || '';
                    this._value = arg.value || '';
                    this.skinClass = arg.skinClass;
                    this.$self = arg.item?arg.item:document.createElement('li');
                    this.$self.className = [this.skinClass, '-option-out'].join('');
                    this.$self.owner = this;
                    this.setText(this._text);
                    this.setValue(this._value);
                    this.$self.onmousedown = this._onClickHandler;
                    this.$self.onmouseover = this._onOverHandler;
                    this.$self.onmouseout = this._onOutHandler;
                }
            },
            setText:function(value){
                this._text = value || '';
                this.$self.innerHTML = this._text;
            },
            getText:function(){
                return this._text;
            },
            setValue:function(value){
                this._value = value || '';
                this.$self.value = this._value;
            },
            getValue:function(){
                return this._value;
            },
            setSelected:function(){
                this._selected = true;
                this.$self.className = [this.skinClass, '-option-active'].join('');
            },
            setUnselected:function(){
                this._selected = false;
                this.$self.className = [this.skinClass, '-option-out'].join('');
            },
            toComponent:function(){
                return this.$self;
            }
        }),
        $protected({
            text:'',
            value:'',
            selected:false,
            onClickHandler:function(event){
                this.owner.dispatchEvent(new ejs.events.ComboBoxEvent(ejs.events.ComboBoxEvent.CLICK));
                this.owner.setSelected();
            },
            onOverHandler:function(){
                if(!this.owner._selected)
                    this.className = [this.owner.skinClass, '-option-over'].join('');
            },
            onOutHandler:function(){
                if(!this.owner._selected)
                    this.className = [this.owner.skinClass, '-option-out'].join('');
            }
        })
    )
);
$package('ejs.controls',
    $class('ComboBox').$extends(ejs.controls.Component).$define(
        $protected({
            dataProvider:[],
            selectedItem:null,
            expanded:false,
            optionHeight:0,
            isScroll:false,
            createComponent:function(){
                if(!this.renderTo){
                    return false;
                }
                this.addEventListener(ejs.events.ComboBoxEvent.UNFOLD, this._onUnfoldHandler);
                this.addEventListener(ejs.events.ComboBoxEvent.FOLD, this._onFoldHandler);

                this.$self = document.createElement('span');
                this.$self.className = this.skinClass;
//                this.renderTo.appendChild(this.$self);
                $(this.renderTo).append(this.$self);

                this.$self.text = document.createElement('span');
                this.$self.text.className = [this.skinClass, '-text'].join('');
                this.$self.text.owner = this;
//                this.$self.appendChild(this.$self.text);
                $(this.$self).append(this.$self.text);
                this.$self.text.onselectstart = function(){ return false; };
                this.$self.text.onmousedown = this._onExpandHandler;

                this.$self.arrow = document.createElement('span');
                this.$self.arrow.className = [this.skinClass, '-arrow',' ', this.skinClass, '-arrow-out'].join('');
                this.$self.arrow.owner = this;
//                this.$self.appendChild(this.$self.arrow);
                $(this.$self).append(this.$self.arrow);
                this.$self.arrow.onmousedown = this._onExpandHandler;
                this.$self.arrow.onmouseover = this._onArrowOverHandler;
                this.$self.arrow.onmouseout = this._onArrowOutHandler;

                this.$option = document.createElement('ul');
//                document.body.appendChild(this.$option);
                $(document.body).append(this.$option);

                this.$option.owner = this;
                this.$option.className = [this.skinClass, '-options'].join('');
                var _optionWidth = 0;
                for(var i=0;i<this._dataProvider.length;++i){
//                    this.$option.appendChild(this._dataProvider[i].toComponent());
                    $(this.$option).append(this._dataProvider[i].toComponent());
                    this._dataProvider[i].toComponent().offsetWidth>_optionWidth && (_optionWidth = this._dataProvider[i].toComponent().offsetWidth);
                }
                this._resizeComponent(_optionWidth);
                this.dispatchEvent(new ejs.events.ComboBoxEvent(ejs.events.ComboBoxEvent.FOLD));
                this.setSelectedIndex(0);
                return true;
            },
            onUnfoldHandler:function(event){
                this.$option.className = [this.skinClass, '-options', ' ', this.skinClass,'-options-visible'].join('');
                this.$self.arrow.className = [this.skinClass, '-arrow',' ', this.skinClass, '-arrow-active'].join('');
                var coordinate = this.$self.getBoundingClientRect(),_scrollLeft = ejs.isStandardMode?document.documentElement.scrollLeft:document.body.scrollLeft, _scrollTop = document.documentElement.scrollTop?document.documentElement.scrollTop:document.body.scrollTop;
                this.$option.style.left = [_scrollLeft + coordinate.left, 'px'].join('');
                this.$option.style.top = [_scrollTop + coordinate.top + this.$self.offsetHeight, 'px'].join('');
                this._dataProvider[0] && this._validateScroll(this._dataProvider[0].toComponent());
                if((this.$option.offsetTop+this.$option.offsetHeight)>document.body.clientHeight){
                    this.$option.style.top = [_scrollTop + coordinate.top - this.$option.offsetHeight, 'px'].join('');
                }
                this._locateOption(this.selectedItem);
            },
            onFoldHandler:function(event){
                this.$option.className = [this.skinClass, '-options', ' ', this.skinClass,'-options-hidden'].join('');
                this.$self.arrow.className = [this.skinClass, '-arrow',' ', this.skinClass, '-arrow-out'].join('');
            },
            onExpandHandler:function(){
                this.owner._expanded = !this.owner._expanded;
                if(this.owner._expanded){
                    this.owner.dispatchEvent(new ejs.events.ComboBoxEvent(ejs.events.ComboBoxEvent.UNFOLD));
                }
                else{
                    this.owner.dispatchEvent(new ejs.events.ComboBoxEvent(ejs.events.ComboBoxEvent.FOLD));
                }
            },
            onClickHandler:function(event){
                this.$owner._expanded = !this.$owner._expanded;
                if(this.$owner._expanded)
                    this.$owner.dispatchEvent(new ejs.events.ComboBoxEvent(ejs.events.ComboBoxEvent.UNFOLD));
                else{
                    this.$owner.dispatchEvent(new ejs.events.ComboBoxEvent(ejs.events.ComboBoxEvent.CLICK));
                    this.$owner.dispatchEvent(new ejs.events.ComboBoxEvent(ejs.events.ComboBoxEvent.FOLD));
                    if(this.$owner.selectedItem != this){
                        this.$owner.selectedItem && this.$owner.selectedItem.setUnselected();
                        this.$owner.selectedItem = this;
                        this.$owner.dispatchEvent(new ejs.events.ComboBoxEvent(ejs.events.ComboBoxEvent.CHANGE));
                    }
                    this.$owner.$self.text.innerHTML = this.getText();
                }
            },
            validateScroll:function(item){
                if(this.$option && item && this.$option.offsetHeight > (item.offsetHeight*8)){
                    this.$option.style.height = [item.offsetHeight*8, 'px'].join('');
                    this.$option.style.overflowY = 'scroll';
                    this._isScroll = true;
                }
            },
            onArrowOverHandler:function(){
                if(!/\-arrow\-active$/.test(this.className))
                    this.className = [this.owner.skinClass, '-arrow',' ', this.owner.skinClass, '-arrow-over'].join('');
            },
            onArrowOutHandler:function(){
                if(!/\-arrow\-active$/.test(this.className))
                    this.className = [this.owner.skinClass, '-arrow',' ', this.owner.skinClass, '-arrow-out'].join('');
            },
            resizeComponent:function(){
                var _offset = (ejs.browser.msie && !ejs.isStandardMode)?0:4;
                if(this._isScroll){
                    _offset = (ejs.browser.msie && !ejs.isStandardMode)?2:4;
                }
                if(this._width!='auto'){
                    this.$self.style.width = [this._width, 'px'].join('');
                    this.$self.text.style.width = [this._width-_offset-this.$self.arrow.offsetWidth, 'px'].join('');
                }
                else{
                    this.$self.text.style.width = [this.$option.offsetWidth-_offset, 'px'].join('');
                }
//                else{
//                    this.$self.text.style.width = [this.$option.offsetWidth-_offset-this.$self.arrow.offsetWidth, 'px'].join('');
//                }
                if(this.$self.offsetWidth>this.$option.offsetWidth){
                    this.$option.style.width = [this.$self.offsetWidth, 'px'].join('');
                }
                if(this._height!='auto'){
                    this.$self.style.height = [this._height, 'px'].join('');
                }
                this._resizeOptions.apply(this, this._isScroll?arguments:[this.$option.offsetWidth]);
            },
            resizeOptions:function(_optionWidth){
                for(var i=0;i<this._dataProvider.length;++i){
                    this._dataProvider[i].toComponent().style.width = [_optionWidth, 'px'].join('');
                }
            },
            getParentByBubble:function(self, instance){
                if(instance){
                    if(!instance.owner){
                        return self._getParentByBubble(self, instance.parentNode);
                    }
                    else if((instance.owner instanceof ejs.controls.ComboBoxItem && instance.owner.$owner!=self) || (instance.owner instanceof ejs.controls.ComboBox && instance.owner!=self)){
                        return false;
                    }
                    else
                        return true;
                }
                else
                    return false;
            },
            locateOption:function(/*ComboBoxItem*/item){
                if(item)
                    this.$option.scrollTop = item.$self.offsetTop;
            }
        }),
        $public({
            isRenderDom:false,
            optionDomObject:null,
            $option:null,
            construct:function(){
                this.dispatchEvent(new ejs.events.ComboBoxEvent(ejs.events.ComboBoxEvent.INITIALIZE));
                this.$super.construct.apply(this, arguments);
                this.$option = null;
                this._dataProvider = [];
                ejs.addEventListener(document, 'mousedown', function(self){
                    return function(event){
                        var _target = (event.target || event.srcElement);
                        if(!self._getParentByBubble(self, _target)){
                            self._expanded = false;
                            self.dispatchEvent(new ejs.events.ComboBoxEvent(ejs.events.ComboBoxEvent.FOLD));
                        }
                    };
                }(this));
            },
            render:function(){
                if(this._createComponent())
                    this.dispatchEvent(new ejs.events.ComboBoxEvent(ejs.events.ComboBoxEvent.COMPLETE));
            },
            setDataProvider:function(){
                if(ejs.isArray(arguments[0])){
                    var items = arguments[0];
                    for(var i=0;i<items.length;++i){
                        items[i].skinClass = this.skinClass;
                        var item = new ejs.controls.ComboBoxItem(items[i]);
                        item.skinClass = this.skinClass;
                        this.addItem(item);
                    }
                }
                else if(this.isRenderDom && this.optionDomObject){
                    if(this.optionDomObject){
                        var items = this.optionDomObject.getElementsByTagName('li');
                        for(var i=0;i<items.length;++i){
                            var itembase = {
                                skinClass:this.skinClass,
                                text:(items[i].getElementsByTagName('a') || [items[i]])[0].innerHTML,
                                value:(items[i].getElementsByTagName('a') || [{getAttribute:function(){ return ''; }}])[0].getAttribute('href',2)
                            };
                            var item = new ejs.controls.ComboBoxItem(itembase);
                            item.skinClass = this.skinClass;
                            this.addItem(item);
                        }
                        this.optionDomObject.innerHTML = '';
                        this.optionDomObject.parentNode.removeChild(this.optionDomObject);
                    }
                }
            },
            getItemsLength:function(){
                return this._dataProvider.length;
            },
            setSelectedIndex:function(index){
                if(this._dataProvider[index]){
                    if(this.selectedItem)
                        this.selectedItem.setUnselected();
                    this.selectedItem = this._dataProvider[index];
                    this._expanded = true;
                    if(this.selectedItem){
//                    ejs.dispatchEvent(this.selectedItem.$self, 'mousedown');
                        this.selectedItem.setSelected();
                        this.selectedItem.dispatchEvent(new ejs.events.ComboBoxEvent(ejs.events.ComboBoxEvent.CLICK));
                        this.dispatchEvent(new ejs.events.ComboBoxEvent(ejs.events.ComboBoxEvent.CHANGE));
                    }
                }
            },
            setSelectedValue:function(value){
                for(var i=0;i<this._dataProvider.length;++i){
                    if(this._dataProvider[i].getValue()==value){
                        this.setSelectedIndex(i);
                        return;
                    }
                }
                this.selectedItem = null;
            },
            getSelectedIndex:function(){
                if(this.selectedItem){
                    for(var i=this._dataProvider.length-1;i>=0;--i){
                        if(this.selectedItem==this._dataProvider[i]){
                            return i;
                        }
                    }
                }
                else
                    return -1;
            },
            getSelectedValue:function(){
                if(this.selectedItem)
                    return this.selectedItem.getValue();
                else
                    return null;
            },
            getValue:function(){
                return this.getSelectedValue();
            },
            getItem:function(index){
                return this._dataProvider[index];
            },
            addItem:function(item){
                if(item instanceof ejs.controls.ComboBoxItem){
                    this._dataProvider.push(item);
                    item.$owner = this;
                    item.addEventListener(ejs.events.ComboBoxEvent.CLICK, this._onClickHandler);
                    if(this.$option){
//                        this.$option.appendChild(item.toComponent());
                        $(this.$option).append(item.toComponent());
                        this._validateScroll(item.toComponent());
                    }
                }
            },
            removeItem:function(item){
                if(item instanceof ejs.controls.ComboBoxItem){
                    for(var i=this._dataProvider.length-1;i>=0;--i){
                        if(item==this._dataProvider[i]){
                            this.$option && this.$option.removeChild(item.toComponent());
                            this._dataProvider.splice(i, 1);
                            this.$option && this._resizeComponent(this.$option.offsetWidth);
                            return true;
                        }
                    }
                }
                return false;
            },
            removeAllItems:function(){
                this._dataProvider = [];
                this.$option.innerHTML = '';
            }
        })
    ));

