﻿Ext.namespace("FinnKodeWeb");

FinnKodeWeb.SearchComboBox = function(config) {
    config = config || {};

    var filterCounter = 0, recordsCount = 0, showLimit = 10, comboValue = '', lastQuery = '', cancelExpand = false;
    var filterFunction = function(record, id) {
        if (filterCounter >= showLimit) return false;
        var s = new String(record.get('Expression'));
        if (s.indexOf(comboValue) == 0) {
            filterCounter++;
            return true;
        }
        return false;
    };
    var jsonReader = new Ext.data.JsonReader({
        root: 'd["SearchExpressions"]',
        totalProperty: 'Results',
        idProperty: 'Id',
        fields: [{ name: 'Id' }, { name: 'Expression' }, { name: 'Cnt'}]
    });
    var proxy = new Ext.data.HttpProxy({
        url: 'FinnKodeWS/StatisticsService.svc/GetTypeAheadSearchExpressions',
        headers: this.header || { 'Content-Type': 'application/json;charset=utf-8' },
        method: 'POST'
    });
    var store = new Ext.data.JsonStore({
        autoDestroy: true,
        reader: jsonReader,
        fields: [{ name: 'Id' }, { name: 'Expression' }, { name: 'Cnt'}],
        sortInfo: {
            field: 'Cnt',
            direction: 'DESC'
        }
    });
    var reset = function() {
        this.collapse();
        lastQuery = '';
        store.loadRecords({ records: [] }, {}, true);
    };
    var doSearch = function(sE) {
        cancelExpand = true;
        this.fireEvent('searchClicked', sE);
        reset.call(this);
    };
    var reload = function(sE) {
        var params = Ext.encode({
            searchExpression: sE,
            codeBookId: config.bookSectionId,
            maxEntries: 75
        });
        proxy.doRequest('read', null, params, jsonReader, function(r, options, success) {
            if (success) {
                var records = r.records;
                store.suspendEvents(false);
                store.loadRecords(r, {}, true);
                store.applySort();
                recordsCount = records.length;
                filterCounter = 0;
                store.filterBy(filterFunction);
                store.resumeEvents();
                if (!cancelExpand) {
                    store.fireEvent('datachanged', store);
                    this.restrictHeight();
                    if (filterCounter > 0) this.expand();
                    else this.collapse();
                }
                lastQuery = sE;
            }
        }, this);
    };
    Ext.apply(config, {
        store: store,
        displayField: 'Expression',
        loadingText: 'appel',
        pageSize: 0,
        minChars: 1,
        hideTrigger: false,
        autoSelect: false,
        typeAhead: false,
        typeAheadDelay: 250,
        listEmptyText: '',
        queryDelay: 250,
        queryParam: 'searchExpression',
        listeners: {
            beforequery: function(queryEvent) {
                queryEvent.cancel = true;
                comboValue = this.getValue();
                if (comboValue.length == 0) {
                    this.collapse();
                    return;
                }
                if (lastQuery.length == 0 && comboValue.length > 0) {
                    reload.call(this, comboValue);
                    return;
                }
                if (lastQuery.length > comboValue.length) {
                    // if last query is more specific - longer - than current search expression, a reload must be done since suggestions
                    // may change when a less specific search is performed
                    reload.call(this, comboValue);
                    return;
                }
                // filter store
                filterCounter = 0;
                store.filterBy(filterFunction);
                this.restrictHeight();
                if (filterCounter < showLimit) {
                    if (comboValue.indexOf(lastQuery) != 0 || recordsCount > showLimit) {
                        // if last query is part of new search and the filter removes too many records
                        // then reload to ensure that not any unfetched records could be shown
                        reload.call(this, comboValue);
                    }
                    // if last query is part of new search and last query (which is less spesific) returned less records 
                    // than showLimit, there is no need to refetch data since they will not return a greater number of suggestions
                }
                if (filterCounter > 0 && !cancelExpand) this.expand();
                else this.collapse();
            },
            expand: {
                fn: function() {
                    this.view.addListener('click', function(view, index, node, e) {
                        doSearch.call(this, view.getRecord(node).get('Expression'));
                    }, this);
                    this.view.addListener('selectionchange', function(view, selections) {
                        if (this.inKeyMode && selections.length > 0) {
                            this.setValue(view.getRecord(selections[0]).get('Expression'));
                        }
                    }, this);
                },
                single: true
            }
        },
        validationEvent: false,
        validateOnBlur: false,
        trigger1Class: 'x-form-clear-trigger',
        trigger2Class: 'x-form-search-trigger',
        hideTrigger1: true,
        width: 180,
        hasSearch: false,
        paramName: 'query',
        enableKeyEvents: true,
        initComponent: function() {
            FinnKodeWeb.SearchComboBox.superclass.initComponent.call(this);

            this.triggerConfig = {
                tag: 'span', cls: 'x-form-twin-triggers', cn: [
                { tag: "img", src: Ext.BLANK_IMAGE_URL, alt: "", cls: "x-form-trigger " + this.trigger1Class },
                { tag: "img", src: Ext.BLANK_IMAGE_URL, alt: "", cls: "x-form-trigger " + this.trigger2Class }
            ]
            };
            this.on('specialkey', function(f, e) {
                if (e.getKey() == e.ENTER) {
                    this.onTrigger2Click();
                }
            }, this);
            this.addEvents('searchClicked');
            this.on('keyup', function(f, e) {
                if (e.getKey() != e.ENTER) cancelExpand = false;
                e.stopPropagation();
                e.stopEvent();
                e.preventDefault();
            }, this);
        },

        getTrigger: function(index) {
            return this.triggers[index];
        },

        afterRender: function() {
            Ext.form.TwinTriggerField.superclass.afterRender.call(this);
            var triggers = this.triggers,
                i = 0,
                len = triggers.length;

            for (; i < len; ++i) {
                if (this['hideTrigger' + (i + 1)]) {
                    triggers[i].hide();
                }
            }
        },

        initTrigger: function() {
            var ts = this.trigger.select('.x-form-trigger', true),
                triggerField = this;

            ts.each(function(t, all, index) {
                var triggerIndex = 'Trigger' + (index + 1);
                t.hide = function() {
                    var w = triggerField.wrap.getWidth();
                    this.dom.style.display = 'none';
                    triggerField.el.setWidth(w - triggerField.trigger.getWidth());
                    triggerField['hidden' + triggerIndex] = true;
                };
                t.show = function() {
                    var w = triggerField.wrap.getWidth();
                    this.dom.style.display = '';
                    triggerField.el.setWidth(w - triggerField.trigger.getWidth());
                    triggerField['hidden' + triggerIndex] = false;
                };
                this.mon(t, 'click', this['on' + triggerIndex + 'Click'], this, { preventDefault: true });
                t.addClassOnOver('x-form-trigger-over');
                t.addClassOnClick('x-form-trigger-click');
            }, this);
            this.triggers = ts.elements;
        },

        getTriggerWidth: function() {
            var tw = 0;
            Ext.each(this.triggers, function(t, index) {
                var triggerIndex = 'Trigger' + (index + 1),
                    w = t.getWidth();
                if (w === 0 && !this['hidden' + triggerIndex]) {
                    tw += this.defaultTriggerWidth;
                } else {
                    tw += w;
                }
            }, this);
            return tw;
        },

        // private
        onDestroy: function() {
            Ext.destroy(this.triggers);
            Ext.form.TwinTriggerField.superclass.onDestroy.call(this);
        },

        onTrigger1Click: function() {
            if (this.hasSearch) {
                this.el.dom.value = '';
                this.triggers[0].hide();
                this.hasSearch = false;
                this.focus();
            }
        },

        onTrigger2Click: function() {
            var v = this.getRawValue();
            if (v.length < 1) {
                this.onTrigger1Click();
                return;
            }
            this.hasSearch = true;
            this.triggers[0].show();
            this.collapse();
            this.focus();
            doSearch.call(this, v);
        }
    });
    FinnKodeWeb.SearchComboBox.superclass.constructor.call(this, config);
};


Ext.extend(FinnKodeWeb.SearchComboBox, Ext.form.ComboBox);

