/*
 * Copyright (c) 2001-2014,FineReport Inc, All Rights Reserved.
 */

;
(function ($) {
    /**
     * 下拉框控件
     *
     *     @example
     *     var $el = $('<div>').css({position : 'absolute', top : 5, left : 40}).appendTo('body');
     *     var editor = new FR.ComboBoxEditor({
     *           renderEl : $el,
     *           directEdit : true,        //是否允许直接编辑
     *           allowBlank : false,      //是否允许为空
     *           widgetUrl : null,         //支持模糊搜索,异步取数请求url
     *           fontSize : 14,             //显示的字体大小
     *           width : 120,
     *           height : 24,
     *           maxCount : 3,            //一页显示的记录数
     *           sonHeight : 24,           //子项元素高度
     *           items : [            //本地取数方式,优先于widgetUrl
     *                 {text : "一一", value : "aa"},
     *                 {text : "二二", value : "bb"},
     *                 {text : "三三", value : "cc"},
     *                 {text : "四四", value : "dd"}
     *          ]
     *     });
     *
     * @class FR.ComboBoxEditor
     * @extends FR.BaseComboBoxEditor
     *
     * @cfg {JSON} options 属性配置
     * @cfg {Number} [options.maxCount=10] 一页显示的记录个数
     * @cfg {Number} [options.sonHeight=18] 下拉框单项高度
     * @cfg {Object} [options.value=''] 默认值
     * @cfg {Number} [options.limitData=500] 单次加载的数据量
     * @cfg {Boolean} [options.autoFixWidth=true] 自动调整列表宽度
     * @cfg {Boolean} [options.allowBlank=true] 允许为空
     * @cfg {Number} options.fontSize 字体大小
     * @cfg {String} options.widgetUrl 下拉列表数据
     * @cfg {Number} options.width 控件宽度
     * @cfg {Number} options.height 控件高度
     * @cfg {Array} options.items 下拉列表数据,这一项优先于widgetUrl
     */
    FR.ComboBoxEditor = FR.extend(FR.BaseComboBoxEditor, /**@class FR.ComboBoxEditor*/{
        /**
         * @private
         */
        _defaultConfig: function () {
            return $.extend(FR.ComboBoxEditor.superclass._defaultConfig.apply(), {
                name4Empty: FR.i18nText("FR-Basic_Choose_None"),
                maxCount: 10,
                sonHeight: 18,
                value: '',
                limitData: 500,
                autoFixWidth: true

            });
        },

        /**
         * @private
         */
        _init: function () {
            FR.ComboBoxEditor.superclass._init.apply(this, arguments);
            this._dealSearch();
            var o = this.options;
            //滚动条宽度
            this.scrollBarWidth = 20;
            /*每个Combo对应在一个div -> $view*/
            if (!this.$view) {
                this.$view = $('<div/>').height(20).appendTo(FR.$view_container);
            }
            this.$view.hide();
            this.shouldReBuildList();
            if (this.options.data && this.options.data.isLocalSource()) {
                if (this.options.dependence) {
                    this.options.data.resetStatus(this.allPara.apply(this, arguments));
                }
                var data = this.options.data.getRecords();
                this._setItems(data);
                this.checkViewScroll(data);
                this.options.need2BuildList = false;
                this.options.need2FixWidth = true;
            }
            FR.applyStyles(this.editComp, o.style);
        },

        /**
         * 绑定模糊搜索功能
         * @private
         */
        _dealSearch: function () {
            var self = this, o = this.options;
            if (this.options.widgetUrl) {
                this.options.searchData = new FR.AjaxSearchData({
                    url: this.options.widgetUrl
                });
                this.editComp.keyup(function (event) {
                    // 不允许直接编辑
                    if (!self.options.directEdit) {
                        return;
                    }
                    /* 如果在0.5秒内焦点离开了 文本框没有了 这时候取editComp的offset进行位置校正就不对了*/
                    /* 如果在0.5秒内焦点离开并且不能自定义值 不太好处理 设置状态位 self.searchCancel*/
                    if (self.options.offset == undefined) {
                        self.options.offset = {'left': self.editComp.offset().left, 'top': self.editComp.offset().top};
                    }

                    /* richer:需要可直接编辑的时候才提供快速定位*/
                    if (!FR.isNavKeyPress(event)) {
                        setTimeout(function () {
                            if (self.searchText == self.editComp.val()
                                && event.keyCode != FR.keyCode.BACKSPACE) {
                                if (!self.isExpanded()) {
                                    self.expand();
                                }
                                return;
                            }
                            /* 下拉复选框改用真实值来getValue的话 需要判断是不是手输的值*/
                            self.edited = true;
                            if (self.searchCancel !== true) {
                                self.searchText = self.editComp.val();
                                self._doBeforeSearch();
                                /* ajaxSearch中加载数据可能要好久 如果在中间切到其他控件了就可能出问题*/
                                /* editComp.blur中用inList==fasle 如果是undefined不操作 等待数据加载完再校验输入值是否在list中*/
                                self.inList = false;
                                self._ajaxSearch();
                                self.fireEvent(FR.Events.AFTEREDIT);
                                self.searchCancel = false;
                            } else {
                                self.searchCancel = undefined;
                            }
                        }, o.searchTime);
                    }
                });
            }
        },

        /**
         * 模糊搜索,生成的下拉列表
         * @private
         */
        _ajaxSearch: function () {
            this.embellishView();
            this.$view.empty();
            this.$view.height(30);
            this.$view.__loadingMoreData__(true);
            this.modifyPosition();
            this.$view.show();
            var para = this.allPara.apply(this, arguments);
            this.options.searchData.resetStatus(para);
            var self = this;
            var searchTimes = self.lastAjaxSearchTimes ? (self.lastAjaxSearchTimes + 1) : 1;
            self.lastAjaxSearchTimes = searchTimes;
            this.options.searchData.loadObject(function (data) {
                if (searchTimes < self.lastAjaxSearchTimes) {
                    return;
                }
                self.options.data.setData(para, data);
                self.checkViewScroll(self.options.data.getData());
                self._setItems(self.options.data.getData());
                self.$view.__loadingMoreData__(false);
                self.$view.hide();
                self.options.need2BuildList = false;
                self._createVieList();
                self.__makeSureInputValueInResList();
                if (self.options.data.getData().length > 0) {
                    self.setFocusWithIndex(0);
                }
            });
        },
        /**
         * @returns {boolean}
         * @private
         */
        _canCancelSearch: function () {
            return true;
        },

        __makeSureInputValueInResList: function () {
            var self = this;
            var viewList = self._getViewList();
            if (viewList.length !== 0) {
                if (self.searchText == "") {
                    self.inList = undefined;
                } else {
                    for (var i = 0; i < viewList.length; i++) {
                        if (viewList.eq(i).text() == self.searchText) {
                            self.inList = true;
                            break;
                        }
                        self.inList = false;
                    }
                }
            } else {
                //wei : 说明这时候输入的内容不是下拉列表中的内容。
                self.inList = false;
            }
            if (self.inList === false && !self.options.customData) {
                this.errorMsg = FR.i18nText("FR-Basic_Not_In_List");
                this.invalidateCss();
            } else {
                this.validateCss();
            }
        },

        isValueInList: function (value) {
            return this._checkValueInResList(value);
        },

        /**
         * 检验输入值是否存在于下拉列表中
         * @private
         */
        _checkValueInResList: function (value) {
            var txt = value || this.editComp.val();
            var dataSource = this.options.data.options.dataSource;
            if (dataSource._findShowValue) {
                var res = dataSource._findShowValue(txt, false);
                this.inList = res != null;
            } else {
                var viewList = this._getViewList();
                this.inList = false;
                if (viewList.length !== 0) {
                    for (var i = 0; i < viewList.length; i++) {
                        if (viewList.eq(i).text() == txt) {
                            this.inList = true;
                            break;
                        }
                    }
                }
            }
            /*Sean: true和undefined都表示存在,而false表示不存在于列表中*/
            if (this.inList === false) {
                this.errorMsg = FR.i18nText("FR-Basic_Not_In_List");
                return false;
            } else {
                return true;
            }
        },

        /**
         * 按键后,模糊搜索前事件,抽象方法
         * @private
         */
        _doBeforeSearch: function () {
        },

        /**
         * 重新构建下拉列表
         * @param items 列表选项
         */
        rebuild: function (items) {
            this.options.data = null;
            this.options.widgetUrl = null;
            this.element.empty();
            this.$view.empty();
            this.options.items = items;
            this.options.need2BuildList = true;
            if (items.widgetUrl) {
                this.options.widgetUrl = items.widgetUrl;
            }
            this._init();
        },
        /**
         * 获取下拉列表的所有子项
         * @returns {jQuery} 返回所有子项dom
         * @private
         */
        _getViewList: function () {
            return this.$view.children('.fr-combo-list-item');
        },

        /**
         * 选中下拉列表中指定位置的一项
         * @param {Number} index 位置索引
         */
        setFocusWithIndex: function (index) {
            $(".fr-combo-list-item", this.$view).removeClass("fr-combo-selected");
            this.focusIndex = index;
            $(".fr-combo-list-item", this.$view).eq(index).addClass("fr-combo-selected");
        },

        /**
         * 取数方法的实现
         * @returns {*}
         */
        getData: function () {
            var dp = this.getText();
            var val = dp,
                records = this.options.data.getLoadedRecords(),
                index = this._getSelectedIndex();
            if (index > -1 && index < records.length) {
                var record = records[index].getShowValue();
                if (typeof record == 'string') {
                    record = $.trim(record);
                }
                if (record == dp) {
                    return records[index].getContent();
                }
            } else {
                for (var i = 0, len = records.length; i < len; i++) {
                    if (records[i].getShowValue() == dp) {
                        val = records[i].getContent();
                        if (this.$view) {
                            this._setSelectedIndex(i);
                        }
                        break;
                    }
                }
                return val;
            }
        },

        /**
         * @param {Event} e 鼠标事件
         * @private
         */
        _onKeyDown: function (e) {
            var self = e.data;
            switch (e.keyCode) {
                case FR.keyCode.DOWN :
                {
                    if (!self.isExpanded()) {
                        self.onTriggerClick();
                    } else {
                        if (self.focusIndex == undefined) {
                            self.focusIndex = self._getSelectedIndex() || 0;
                        }
                        if (self.focusIndex < (self.considerAllowBlankLength() - 1)) {
                            self._setItemFocus(self.focusIndex + 1, self.focusIndex);
                            self.focusIndex = self.focusIndex + 1;
                        } else {
                            self._setItemFocus(0, self.focusIndex);
                            self.focusIndex = 0;
                        }
                    }
                    e.stopEvent();
                    break;
                }
                case FR.keyCode.UP :
                {
                    if (self.isExpanded()) {
                        if (self.focusIndex == undefined) {
                            self.focusIndex = self._getSelectedIndex();
                        }
                        if (self.focusIndex - 1 >= 0) {
                            self._setItemFocus(self.focusIndex - 1, self.focusIndex);
                            self.focusIndex = self.focusIndex - 1;
                        } else {
                            self._setItemFocus(self.considerAllowBlankLength() - 1, self.focusIndex);
                            self.focusIndex = self.considerAllowBlankLength() - 1;
                        }
                        e.stopEvent();
                    }
                    break;
                }
                case FR.keyCode.ENTER:
                {
                    self.collapse();
                    break;
                }
                case FR.keyCode.TAB :
                {
                    if (self.isExpanded()) {
                        if (self.focusIndex != undefined) {
                            self._setSelectedIndex(self.focusIndex);
                        } else {
                            self.collapse();
                            self.editComp.blur();
                            e.stopEvent();
                            break;
                        }
                        self._onEnterPressed();
                        if (self.editComp.val() == '' && self.options.allowBlank !== false) {
                            self.inList = true;
                        }
                        e.stopEvent();
                    }
                    break;
                }
            }
        },

        /**
         * 点击下拉框右侧小按钮事触发的函数
         */
        onTriggerClick: function () {
            /* 705改成点击下拉列表的选项才出发点击事*/
            if (!this.isEnabled()) {
                return;
            }

            if (this.isExpanded()) {
                this.collapse();
            } else {
                this._createVieList();
            }
        },

        /**
         * 生成下拉列表,并加载数据
         * @param needExpand 是否需要展开下拉列表
         * @private
         */
        _createVieList: function (needExpand) {
            this.embellishView();
            /*wei:记录下一开始选中的项*/
            if (this.options.need2BuildList) {
                this.$view.empty();
                if (needExpand !== false) {
                    this.$view.height(30);
                    /*重设高度,用于显示loading图标啊*/
                    this.tH = 30;
                    this.tW = this.$view.width();
                    this.modifyPosition();
                    this.$view.show();
                }
                this.$view.__loadingMoreData__(true);
                if (this.options.data) {
                    this.options.data.resetStatus(this.allPara.apply(this, arguments));
                    var data = this.options.data.getData();
                    this.checkViewScroll(data);
                    this._setItems(data);
                }
                this.$view.hide();
                this.$view.__loadingMoreData__(false);
                this.options.need2BuildList = false;
                this.options.need2FixWidth = true;
            }
            if (this.options.need2FixWidth !== false) {
                this.fixViewWidth();
                this.options.need2FixWidth = false;
            }

            if (needExpand !== false) {
                this.expand();
                this.modifyPosition();
            }
        },

        /**
         * 滚动加载下拉列表数据
         * @private
         */
        scrollLoadMoreData: function () {
            if (this.isLoadingData) {
                return;
            }
            this.isLoadingData = true;
            this.$view.__loadingMoreData__(true);
            this.options.data.resetStatusKeepData(this.allPara(this.options.data.getLength()));
            var data = this.data2Add();
            this.checkViewScroll(data);
            this.addData2View(data);
            this.isLoadingData = false;
        },

        /**
         * 添加值
         * @returns {*}
         */
        data2Add: function () {
            return this.options.data.appendData();
        },

        /**
         * 将数据生成为子项元素,添加到下拉列表中
         * @param {Array} data 数据
         */
        addData2View: function (data) {
            var txt = this.editComp.val();
            var defaultIdx = -1;
            if (this.$view) {
                if (!this.emptyContent) {
                    var emptyContent = this._checkAndAddEmptyContent();
                } else {
                    this.initContent(this.emptyContent, this.options.name4Empty, -1);
                }
                var frag = document.createDocumentFragment();
                var len = this.options.data.getLength();
                for (var i = len - data.length; i < len; i++) {
                    var ri = i + data.length - len;
                    var sondi = $('<div/>');
                    frag.appendChild(sondi[0]);
                    var showValue = data[ri].getShowValue();
                    this.initContent(sondi, showValue, i);
                    if (defaultIdx < 0 && showValue == txt) {
                        defaultIdx = ri;
                    }
                }

                //这个宽度要自动调整, 不然控件联动下拉框时, 上一次联动选项的宽度会影响到下一个
                $(this.$view[0]).css('width', 'auto');
                this.$view[0].appendChild(frag);
                this.$view.append(emptyContent || this.emptyContent);
                this.$view.__loadingMoreData__(false);
                this._setSelectedIndex(defaultIdx);

                //因为上面是auto的, 如果小于下拉框宽度就不好看了.
                if (this.$view.width() < this.element.width()) {
                    var ew = this.element.width();
                    //zack:这边如果有滚动条的话要加上滚动条的宽度20
                    if (this.addedScrollWidth) {
                        ew += this.scrollBarWidth;
                    }
                    this.$view.width(ew - 2);
                }
            }
        },

        /**
         * 初始化一个子项元素
         * @param {jQuery} $dom DOM对象
         * @param {String} showValue 显示值
         * @param {Number} index 位置索引
         */
        initContent: function ($dom, showValue, index) {
            if (showValue == null) {
                showValue = '';
            }
            var self = this;
            $dom.height(this.options.sonHeight).attr("title", showValue).text(showValue)
                .addClass(index > -1 ? 'fr-combo-list-item' : 'fr-combo-list-item fr-combo-list-item-noselect')
                .hover(function (e) {
                    self.setFocusWithIndex(index);
                    setTimeout(function (e) {
                        if (!e) {
                            return;
                        }
                        var target = $(e.target);
                        if (self.$view[0].style.display != "none" && target.isChildAndSelfOf($(this).parent().children())) {
                            $(this).removeClass("fr-combo-selected");
                        }
                    }, 10);
                })
                .click(function (e) {
                    self.inList = true;
                    self.fireEvent(FR.Events.CLICK);
                    self._setSelectedIndex(index > -1 ? index : self.getItemsLength());
                    self._onEnterPressed();
                });
        },

        /**
         * 如果允许为空,则生成'不选'一项选择项
         * @returns {jQuery} 返回生成的dom对象
         * @private
         */
        _checkAndAddEmptyContent: function () {
            if (this.options.allowBlank === false) {
                return;
            }
            this.emptyContent = $('<div/>');
            this.initContent(this.emptyContent, this.options.name4Empty, -1);
            return this.emptyContent;
        },

        /**
         * 判断是否需要滚动加载
         * @param {Array} data 一次加载的数据限制个数
         */
        checkViewScroll: function (data) {
            this.$view.need2Scroll = this.options.limitData <= data.length;
        },

        /**
         * 渲染绘制下拉列表
         * @private
         */
        embellishView: function () {
            if (this.viewEmbellished) {
                return;
            }

            $(".fr-combo-list").hide();
            var self = this;
            if (!this.$view) {
                this.$view = $('<div/>').appendTo(FR.$view_container).height(20);
            }
            this.$view.addClass('fr-combo-list')
                .css({
                    position: 'absolute',
                    width: 'auto',
                    'z-index': '999'
                })
                .scroll(function () {
                    /*wei : ==的时候ie不会执行,改成>=*/
                    if (self.$view.need2Scroll && $(this).scrollTop() + $(this).height() >= this.scrollHeight) {
                        self.scrollLoadMoreData();
                    }
                });
            this.viewEmbellished = true;
        },

        /**
         * 设置下拉框的内容
         * @private
         */
        _setItems: function (records) {
            var sH = this.options.sonHeight, rl = this.considerAllowBlankLength();
            var count = this.options.maxCount || 10;
            this.tH = rl > count ? (sH + 2) * count : (sH + 2) * rl;
            this.$view.height(this.tH);
            this.addData2View(records);
            this.tW = this.$view.width();
        },


        /**
         * 展开下拉列表
         */
        expand: function () {
            if (this.isExpanded()) {
                return;
            }
            this._showView();
            $(document).bind('mousedown', this, this.collapseIf).bind('mousewheel', this, this.collapseIf);
            if (this.options.write && this.options.write.lgp) {
                this.options.write.lgp.$container.bind('scroll', this, this.collapseIf);
            }
            if (document.activeElement != this.editComp[0]) {
                this.editComp.focus();
            }
            this.fireEvent(FR.Events.EXPAND);
        },

        /**
         * 显示下拉列表
         * @private
         */
        _showView: function () {
            this.$view.show();
        },

        /**
         * 滚动切换选中的子项元素(仅仅样式改变)
         * @param {Number} idx 新位置索引
         * @param {Number} lastidx 旧位置索引
         * @private
         */
        _setItemFocus: function (idx, lastidx) {
            var viewList = this.$view.children('.fr-combo-list-item');
            $(viewList[lastidx]).removeClass('fr-combo-selected');
            $(viewList[idx]).addClass('fr-combo-selected').__scroll2View__(this.$view, false);
        },

        setEnable: function (arg) {
            FR.ComboBoxEditor.superclass.setEnable.apply(this, arguments);
            if (arg === false) {
                this.collapse();
            }
        },

        setVisible: function (arg) {
            FR.ComboBoxEditor.superclass.setVisible.apply(this, arguments);
            if (arg === false) {
                this.collapse();
            }
        },

        /**
         * 判断是否正在过滤字段
         * @returns {Boolean} 返回是否正在过滤
         */
        isFiltering: function () {
            return !FR.isEmpty(this.searchText);
        },

        /**
         * 调整下拉列表宽度(处理兼容问题)
         * @private
         */
        fixViewWidth: function () {
            /* TODO Sean: 代码质量问题,兼容最好重做*/
            /* shoc:IE6和IE7中框子的宽度有问题,调整下,自适应有问题,按字符计算了*/
            if ($.browser.msie && $.browser.version < '8.0') {
                var width2 = 0;

                var listItems = $(".fr-combo-list-item", this.$view);
                for (var i = 0; i < listItems.length; i++) {
                    var len = FR.byteLength(listItems.eq(i).text()) * 6 + 30;
                    width2 = Math.max(width2, len);
                }
                this.$view.width(this.options.mutiSelection ? width2 + 30 : width2 + 10);
            }

            if (!$.browser.msie && this.$view.children().length > this.options.maxCount && !this.addedScrollWidth) {
                this.$view.width(this.$view.width() + this.scrollBarWidth);
                this.addedScrollWidth = true;
            }

            if (this.$view.width() < this.element.width()) {
                var ew = this.element.width();
                //jim:表单下,下拉列表宽度比控件宽度大2,导致下拉框控件在边界时会时body出现滚动条
                this.$view.width(this.element.width() - 2);
            }
            if ($.browser.msie && $.browser.version < '8.0' && this.$view.width() < 120) {
                this.$view.width(120);
            }

            if ($.browser.msie) {
                this.$view.css('overflow-x', 'visible');
            }
        }
    });
    $.shortcut("combo", FR.ComboBoxEditor);
})(jQuery);