jOmnis.callbackObject = {
    fieldData: null, // Field data is an object that stores the IDs, Tables, and Descriptions of fields in a list of search fields
    fields: null,
    findDiv: null,
    categoryList: null,
    categoryNumber: null,
    fieldInput: null,
    clearButton: null,
    fieldList: null,
    //selectedFieldDisplay: null,
    enterKey: null,
    upKey: null,
    downKey: null,
    leftKey: null,
    rightKey: null,
    tabKey: null,
    escKey: null,
    shiftKey: null,
    navKeys: null,
    showAll: null,
    totalWidth: null,
    addCategories: function(){
        let all = document.createElement("option");
        all.value = "All";
        all.text = "All";
        this.categoryList.add(all);

        let categories = Object.keys(this.fieldData);
        categories.forEach(element => {
            let category = document.createElement("option");
            category.value = element;
            category.text = element;
            this.categoryList.add(category);
        });
        this.categoryNumber = categories.length + 1;
        this.categoryList.size = this.categoryNumber;
    },
    clearCategories: function() {
        while(this.categoryList.firstChild) {
            this.categoryList.removeChild(this.categoryList.firstChild);
        }
    },
    prepareFields: function(category){
        if(category == "All"){
            this.showAll = true;
            for (var category in this.fieldData) {
                this.fieldData[category].forEach(element => {
                    element.category = category;
                    this.fields.push(element);
                })
            }
        } else {
            this.showAll = false;
            this.fieldData[category].forEach(element => {
                this.fields.push(element);
            })
        }
        this.fields.sort(function(a,b){
            if (a.description > b.description){
                return 1;
            } else if (a.description < b.description){
                return -1;
            } else {
                if (a.category > b.category){
                    return 1;
                } else if (a.category < b.category){
                    return -1;
                } else {
                    return 0;
                }
            }
        });
        this.addFields(this.fields);
    },
    addFields: function(fieldsToAdd){
        let fieldNames = fieldsToAdd.map(field => field.description);
        let numberOfFields = fieldsToAdd.length;
        fieldsToAdd.forEach((element, index) => {
            if(fieldNames.indexOf(element.description) != fieldNames.lastIndexOf(element.description)){
                element.duplicate = true;
            };
            let field = document.createElement("option");
            field.value = element.colname;
            field.id = element.omnisLine;
            field.text = element.description + (element.duplicate && this.showAll ? ` (${element.category})` : '');
            this.fieldList.add(field);
            if(index == 0){
                field.selected = true;
            }
        });
        this.fieldList.size = numberOfFields;
        if (numberOfFields == 0 && this.fieldInput.value){
            let field = document.createElement("option");
            field.value = "No Results";
            field.text = "No Results";
            field.disabled = true;
            this.fieldList.add(field);
        }
        if(numberOfFields < this.categoryNumber){
            this.fieldList.size = this.categoryNumber;
        }
    },
    filterFields: function(searchInput){
        let searchTerm = searchInput.toLowerCase();
        let filteredFields = this.fields.filter(element => {
                return element['description'].toLowerCase().includes(searchTerm)
        });
        this.clearFields();
        this.addFields(filteredFields);
        
        jOmnis.sendControlEvent({
            "description": "setDimensions",
            "width": jOmnis.callbackObject.getWidth(),
            "height": jOmnis.callbackObject.getHeight()
        });
    },
    handleClearBtn: function(key){
        let value = jOmnis.callbackObject.fieldInput.value;
        let result;
        if(key == "Backspace"){
            if(value){
            result = value.slice(0,-1);
            }
        } else {
            result = value + key  //have to handle the result this way since we are using keydown instead of keyup
        }
        if (result) {
            this.clearButton.style.visibility = 'visible';
        } else {
            this.clearButton.style.visibility = 'hidden';
        }
    },
    getWidth: function(){
        let categoryListWidth = this.categoryList.offsetWidth;
        let fieldListWidth = this.fieldList.offsetWidth;
        this.fieldList.style = `min-width: ${fieldListWidth}px; margin-left: ${categoryListWidth+5}px;`;
        return categoryListWidth + fieldListWidth + 8;
    },
    getHeight: function(){
        let fieldListHeight = this.fieldList.offsetHeight;
        let categoryListHeight = this.categoryList.offsetHeight;
        let totalHeightNeeded;
        if (categoryListHeight > fieldListHeight){
            totalHeightNeeded = categoryListHeight;
        } else {
            totalHeightNeeded = fieldListHeight;
        }

        return totalHeightNeeded;
    },
    keepOnScreen: function(){
        let newSelection = document.querySelector('#fields-list option:checked');
        if(newSelection){
            var bounding = newSelection.getBoundingClientRect();
            let tooHigh = bounding.top < 20
            let tooLow = bounding.bottom > window.innerHeight;
            let height = bounding.bottom - bounding.top;
            if(tooHigh){
                window.scrollBy(0,-(height));
            } else if (tooLow) {
                window.scrollBy(0,height);
            }
        }
    },
    resetFieldsArray: function(){
        this.fields = [];
    },
    resetFieldInput: function() {
        var oldFieldInput = document.getElementById("field-input");
        var newFieldInput = oldFieldInput.cloneNode(true);
        oldFieldInput.parentNode.replaceChild(newFieldInput, oldFieldInput);
        this.fieldInput = document.getElementById('field-input');
    },
    clearFields: function(){
        while(this.fieldList.firstChild) {
            this.fieldList.removeChild(this.fieldList.firstChild);
        }
    },
    clearInput: function(){
        this.fieldInput.value = '';
        this.clearButton.style.visibility = 'hidden';
        this.filterFields(this.fieldInput.value);
    },
    loadFieldChoice: function(){
        jOmnis.sendClickEvent(this.omnisGetCurrentLine());
    },
    submitFieldChoice: function() {
        jOmnis.sendDoubleClickEvent(this.omnisGetCurrentLine());
    },
    keyPressed: function(key) {
        this.fieldInput.value = key;
        this.filterFields(key);
        this.handleClearBtn(key);
        this.loadFieldChoice();
    },
    // Required for "single"! This needs to be updated to return the currently selected field's OmnisLine Property (see line 179)
    omnisGetCurrentLine: function() {
        let selectedColname = document.querySelector('#fields-list').value;
        let selectedOmnisLine = document.querySelector(`option[value='${selectedColname}']`);
        if (selectedOmnisLine){
            selectedOmnisLine = Number(selectedOmnisLine.id);
            return selectedOmnisLine;
        }
        return false;
    },
    startup: function() {
        this.addCategories();
        this.categoryList.value = "All";
        this.prepareFields("All");
        jOmnis.sendControlEvent({
            "description": "setDimensions",
            "width": jOmnis.callbackObject.getWidth(),
            "height": jOmnis.callbackObject.getHeight()
        });
        this.fieldInput.focus();
    },
    // Required!
    omnisOnLoad: function() {
        this.fieldData = {};
        this.fields = [];
        this.categoryList = [];
        this.findDiv = document.getElementById('find-div');
        this.categoryList = document.getElementById('field-categories');
        this.fieldInput = document.getElementById('field-input');
        this.clearButton = document.getElementById('clear-btn');
        this.fieldList = document.getElementById('fields-list');
        this.enterKey = 13;
        this.upKey = 38;
        this.downKey = 40;
        this.leftKey = 37;
        this.rightKey = 39;
        this.tabKey = 9;
        this.shiftKey = 16;
        this.escKey = 27;
        this.navKeys = [this.enterKey, this.upKey, this.downKey, this.leftKey, this.rightKey, this.tabKey, this.shiftKey, this.escKey];
        this.fieldInput.focus();
    },
    // Required!
    omnisSetData: function(fieldData) {
        if (fieldData instanceof omnis_list && fieldData.getRowCount()>0) {
            // Clear all fields and lists.
            this.resetFieldsArray();
            this.resetFieldInput();
            this.clearFields();
            this.clearCategories();
            this.fieldData = {};
            this.fieldInput.value = '';
            this.clearButton.style.visibility = 'hidden';

            for (var i = 0; i < fieldData.getRowCount(); i++) {
                // Check to see if the current table has been added to the field data object
                if (!(fieldData.getData(1, i + 1) in this.fieldData)) { // getData(column #, row #) it's important to note the omnis lists have a starting index of 1 which is why we do i + 1 in javascript
                    this.fieldData[fieldData.getData(1, i + 1)] = [];
                }

                this.fieldData[fieldData.getData(1, i + 1)].push({
                    "id": fieldData.getData(2, i + 1),
                    "description": fieldData.getData(3, i + 1),
                    "omnisLine": i + 1,
                    "colname": fieldData.getData(4, i + 1)
                });
                
            }
            
            //Typing in input updates field list
            this.fieldInput.addEventListener('keydown', function(e){
                let keycode = e.keyCode;
                let key = e.key;
                let value = e.target.value;
                
                if (jOmnis.callbackObject.navKeys.includes(keycode)){
                    return;
                } else {
                    let result;
                    if(key == "Backspace"){
                        if(value){
                        result = value.slice(0,-1);
                        }
                    } else {
                        result = value + key
                    }
                    jOmnis.callbackObject.filterFields(result);
                    jOmnis.callbackObject.handleClearBtn(key);
                    jOmnis.callbackObject.loadFieldChoice();
                }
            });

            //Changing the category updates field list
            this.categoryList.addEventListener('change', function(e){
                let selectedCategory = e.target.value;
                jOmnis.callbackObject.clearFields();
                jOmnis.callbackObject.resetFieldsArray();
                jOmnis.callbackObject.fieldInput.value = '';
                jOmnis.callbackObject.clearButton.style.visibility = 'hidden';
                jOmnis.callbackObject.prepareFields(selectedCategory);
                jOmnis.callbackObject.fieldInput.placeholder = `Search ${selectedCategory} Fields`
                jOmnis.sendControlEvent({
                    "description": "setDimensions",
                    "width": jOmnis.callbackObject.getWidth(),
                    "height": jOmnis.callbackObject.getHeight()
                });
            });

            // Right arrow moves from category list to field list
            this.categoryList.addEventListener('keydown', function(e){
                if(!e.shiftKey && (e.keyCode == jOmnis.callbackObject.rightKey || e.keyCode == jOmnis.callbackObject.tabKey)){
                    e.preventDefault();
                    if (!document.querySelector('#fields-list option:checked')){
                        document.querySelector('#fields-list option').selected = true;
                        jOmnis.callbackObject.loadFieldChoice();
                    }
                    jOmnis.callbackObject.fieldList.focus();
                }
            });

            //Clicking on a field gets the field ID
            this.fieldList.addEventListener('change', function(){
                jOmnis.callbackObject.keepOnScreen();
                jOmnis.callbackObject.loadFieldChoice();
            });

            // These vars are used to check for double clicks vs single clicks.
            // dblclick event wasn't working in testing
            var clicks = 0;
            var clickTimer;

            this.fieldList.addEventListener('click', function(){
                clicks++;
                if (clicks == 1) {
                    clickTimer = setTimeout(function() {
                        clicks = 0;
                        jOmnis.callbackObject.loadFieldChoice();
                    }, 400);
                } else {
                    clearTimeout(clickTimer);
                    clicks = 0;
                    jOmnis.callbackObject.submitFieldChoice();
                }
            });

            //Enter key also gets the field ID
            this.fieldList.addEventListener('keydown', function(e){
                let keycode = e.keyCode;
                if (keycode == jOmnis.callbackObject.enterKey || (keycode == jOmnis.callbackObject.tabKey && !e.shiftKey)){ // shift-tab should not change focus
                    jOmnis.callbackObject.submitFieldChoice();
                } else if (keycode == jOmnis.callbackObject.leftKey){
                    jOmnis.callbackObject.categoryList.focus();
                }
            });

            //Enter key from search field submits selected field choice
            this.fieldInput.addEventListener('keydown', function(e){
                let keycode = e.keyCode;
                if (keycode == jOmnis.callbackObject.enterKey){
                    jOmnis.callbackObject.submitFieldChoice();
                }

                if (keyCode == jOmnis.callbackObject.tabKey) jOmnis.callbackObject.categoryList.focus();
            });

            //Most keys will bring focus to search input
            window.addEventListener('keydown', function(e){
                let keycode = e.keyCode;
                if (keycode == jOmnis.callbackObject.escKey) {
                    jOmnis.sendControlEvent({"description": "escape"});
                } else if (jOmnis.callbackObject.navKeys.includes(keycode)){
                    return;
                } else {
                    jOmnis.callbackObject.fieldInput.focus();
                }
            });

            // Up arrow, Down arrow, and Enter keys control field list
            this.fieldInput.addEventListener('keydown', function(e){
                let keycode = e.keyCode;
                let selectedField = document.querySelector('#fields-list option:checked');
                if (keycode == jOmnis.callbackObject.tabKey && e.shiftKey) jOmnis.sendControlEvent({"description": "escape"});
                if (keycode == jOmnis.callbackObject.downKey){
                    e.preventDefault();
                    if(selectedField.nextSibling.tagName == 'OPTION'){
                        selectedField.selected = false;
                        selectedField.nextSibling.selected = true;
                        jOmnis.callbackObject.keepOnScreen();
                    }
                } else if (keycode == jOmnis.callbackObject.upKey){
                    e.preventDefault();
                    if(selectedField.previousSibling.tagName == 'OPTION'){
                        selectedField.selected = false;
                        selectedField.previousSibling.selected = true;
                        jOmnis.callbackObject.keepOnScreen();
                    }
                } else {
                    return;
                }
                jOmnis.callbackObject.loadFieldChoice();
            });
        }

        this.startup();
        jOmnis.sendControlEvent({"description": "fetchKeyPress"});
    }
};