var ResultsTable = function (headers, excerptsShown, sortBy, sortDir, resultSet, container) {
    this._headers = headers;
    this._data = resultSet.results;
    //
    var data = resultSet.results;
    var resultCount = resultSet.count;
    // Build the debug message if there were more results than data
    var debugMessage = false;
    if (AdvancedSearchConfiguration.debug) {
        debugMessage = document.createElement("div");
        debugMessage.className = "debugMessage";
        debugMessage.appendChild( document.createTextNode("Query: "+ resultSet.query) );
    }
    // Build the warning message if there were more results than data
    var warningMessage = false;
    if (resultCount > data.length) {
        warningMessage = document.createElement("div");
        warningMessage.className = "warningMessage";
        warningMessage.appendChild( document.createTextNode("There were "+ resultCount + " results, but I can only show "+ data.length) );
    }
    // Build the table
    if (!this.table) {
        this.table = document.createElement("table");
        this.table.className = "confluenceTable";
        // Create the headers
        var thead = document.createElement("thead");
        var theadTr = document.createElement("tr");
        var headerFlags = {};
        for (var i=0; i<headers.length; i++) if (headers[i]) {
            var th = document.createElement("th");
            th.className = "confluenceTh";
            // Add the content & sorting/sortable functionality
            switch (headers[i].name) {
                case "title" : {
                    th.appendChild( document.createTextNode(headers[i].title ? headers[i].title : "Title") );
                    break;
                }
                case "rating" : {
                    th.appendChild( document.createTextNode(headers[i].title ? headers[i].title : "Rating") );
                    break;
                }
                case "creation" : {
                    th.appendChild( document.createTextNode(headers[i].title ? headers[i].title : "Created On") );
                    break;
                }
                case "modified" : {
                    th.appendChild( document.createTextNode(headers[i].title ? headers[i].title : "Modified On") );
                    break;
                }
                case "author" : {
                    th.appendChild( document.createTextNode(headers[i].title ? headers[i].title : "Author") );
                    break;
                }
                case "space" : {
                    th.appendChild( document.createTextNode(headers[i].title ? headers[i].title : "Space") );
                    break;
                }
                // Unknown header - skip
                default : continue;
            }
            headerFlags[headers[i].name] = true;
            headers[i]._node = th;
            theadTr.appendChild(th);
        }
        thead.appendChild(theadTr);
        this.table.appendChild(thead);
        // Populate the rows
        this.tbody = document.createElement("tbody");
        if (data.length == 0) {
            var tbodyTr = document.createElement("tr");
            var td = document.createElement("td");
            td.className = "confluenceTd";
            td.colSpan = headers.length;
            td.appendChild( document.createTextNode("There were no results for your search criteria.") );
            tbodyTr.appendChild(td);
            this.tbody.appendChild(tbodyTr);
        }
        for (var i=0; i<data.length; i++) if (data[i]) {
            var tbodyTr = document.createElement("tr");
            tbodyTr.className = data[i].type;
            // Populate the record
            switch (data[i].type) {
                case "page" : case "blogpost" : case "userinfo" : case "spacedesc" : case "attachment" : {
                    for (var j=0; j<headers.length; j++) if (headers[j]) {
                        switch (headers[j].name) {
                            case "title" : {
                                var td = document.createElement("td");
                                td.className = "confluenceTd "+ headers[j].name;
                                var titleDiv = document.createElement("div");
                                titleDiv.className = "title";
                                var titleLink = document.createElement("a");
                                titleLink.href = data[i].link;
                                titleLink.appendChild( document.createTextNode(data[i].title) );
                                titleDiv.appendChild(titleLink);
                                td.appendChild(titleDiv);
                                if (excerptsShown) {
                                    var excerptDiv = document.createElement("div");
                                    excerptDiv.className = "excerpt";
                                    excerptDiv.innerHTML = data[i].excerpt;
                                    td.appendChild(excerptDiv);
                                }
                                tbodyTr.appendChild(td);
                                break;
                            }
                            case "rating" : {
                                var td = document.createElement("td");
                                td.className = "confluenceTd "+ headers[j].name;
                                td.setAttribute("align", "center");
                                if (data[i].rating == 0) {
                                    td.innerHTML = "<em>unrated</em>";
                                } else {
                                    td.innerHTML = "<div style='background-image: url("+ document.getElementById("advancedSearch_ratingImageOff").src +"); background-repeat: no-repeat; width: 78px; text-align: left;' title='"+ data[i].rating +"'>"+
                                                   "<div style='overflow: hidden; height: 14px; width: "+ Math.round(data[i].rating * 15) +"px;'><img src='"+ document.getElementById("advancedSearch_ratingImageOn").src +"' alt='"+ data[i].rating +"'></div>"+
                                                   "</div>";
                                }
                                tbodyTr.appendChild(td);
                                break;
                            }
                            case "creation" : {
                                var td = document.createElement("td");
                                td.className = "confluenceTd "+ headers[j].name;
                                var contentDiv = document.createElement("div");
                                contentDiv.appendChild( document.createTextNode(data[i].creation.format("dd NNN yyyy")) );
                                td.appendChild(contentDiv);
                                tbodyTr.appendChild(td);
                                break;
                            }
                            case "modified" : {
                                var td = document.createElement("td");
                                td.className = "confluenceTd "+ headers[j].name;
                                var contentDiv = document.createElement("div");
                                contentDiv.appendChild( document.createTextNode(data[i].modified.format("dd NNN yyyy")) );
                                td.appendChild(contentDiv);
                                tbodyTr.appendChild(td);
                                break;
                            }
                            case "author" : {
                                var td = document.createElement("td");
                                td.className = "confluenceTd "+ headers[j].name;
                                var contentDiv = document.createElement("div");
                                var link = document.createElement("a");
                                link.href = document.getElementById("advancedSearch_contextPath").innerHTML + "/display/~"+ data[i].author.name;
                                link.appendChild( document.createTextNode(data[i].author.fullName) );
                                contentDiv.appendChild(link);
                                td.appendChild(contentDiv);
                                tbodyTr.appendChild(td);
                                break;
                            }
                            case "space" : {
                                var td = document.createElement("td");
                                td.className = "confluenceTd "+ headers[j].name;
                                var contentDiv = document.createElement("div");
                                var link = document.createElement("a");
                                link.href = document.getElementById("advancedSearch_contextPath").innerHTML + "/display/"+ data[i].space.key;
                                link.appendChild( document.createTextNode( data[i].space.name ? data[i].space.name : data[i].space.key ) );
                                contentDiv.appendChild(link);
                                td.appendChild(contentDiv);
                                tbodyTr.appendChild(td);
                                break;
                            }
                        }
                    }
                    break;
                }
                // Unknown data - skip
                default : continue;
            }
            data[i]._node = tbodyTr;
            this.tbody.appendChild(tbodyTr);
        }
        this.table.appendChild(this.tbody);
        // Sort the rows
        this.sortData(sortBy, sortDir);
    }
    // Draw the table
    container.innerHTML = "";
    if (debugMessage) {
        container.appendChild(debugMessage);
    }
    if (warningMessage) {
        container.appendChild(warningMessage);
    }
    container.appendChild( this.table );
};
ResultsTable.prototype.sortData = function (field, direction) {
    // Derive and Default the Direction of the Sort
    var ascending = !(direction == "desc");
    // Get the appropriate sort function for the field
    var ascSortFunc;
    var descSortFunc;
    switch (field) {
        case "title" : {
            ascSortFunc = descSortFunc = function (a, b) {
                return a.title == b.title ? 0 : a.title > b.title ? 1 : -1;
            }
            break;
        }
        case "rating" : {
            ascSortFunc = function (a, b) {
                if (a.rating == 0 && b.rating > 0) return 1;
                if (b.rating == 0 && a.rating > 0) return -1;
                return a.rating == b.rating ? 0 : a.rating > b.rating ? 1 : -1;
            }
            // NOTE: This will still be inverted below
            descSortFunc = function (a, b) {
                if (a.rating == 0 && b.rating > 0) return -1;
                if (b.rating == 0 && a.rating > 0) return 1;
                return a.rating == b.rating ? 0 : a.rating > b.rating ? 1 : -1;
            }
            break;
        }
        case "creation" : {
            ascSortFunc = descSortFunc = function (a, b) {
                return a.creation == b.creation ? 0 : a.creation > b.creation ? 1 : -1;
            }
            break;
        }
        case "modified" : {
            ascSortFunc = descSortFunc = function (a, b) {
                return a.modified == b.modified ? 0 : a.modified > b.modified ? 1 : -1;
            }
            break;
        }
        case "author" : {
            ascSortFunc = descSortFunc = function (a, b) {
                return a.author.fullName == b.author.fullName ? 0 : a.author.fullName > b.author.fullName ? 1 : -1;
            }
            break;
        }
        case "space" : {
            ascSortFunc = descSortFunc = function (a, b) {
                return a.space.name == b.space.name ? 0 : a.space.name > b.space.name ? 1 : -1;
            }
            break;
        }
        // Unknown field to sort on
        default : return;
    }
    // Invert the sorting if required
    var sortFunc = ascending ? ascSortFunc : descSortFunc;
    if (!ascending) {
        var originalSort = sortFunc;
        sortFunc = function (a, b) {
            return 0 - originalSort(a, b);
        };
    }
    // Sort the data array
    this._data.sort(sortFunc);
    // Reorder the table rows
    var rowCount = 0;
    for (var i=0; i<this._data.length; i++) if (this._data[i]) {
        // If this isnt at the end
        if (this.tbody.childNodes.length < rowCount) {
            this.tbody.insertBefore( this._data[i]._node, this.tbody.childNodes[rowCount] );
        } else {
            this.tbody.appendChild( this._data[i]._node );
        }
        rowCount++;
    }
    // Header Builder
    var headerBuilder = function (node, field, title, sorted, direction) {
        // Reset the contents
        node.className = "confluenceTh "+ field +" sortable";
        node.innerHTML = "";
        node.appendChild( document.createTextNode(title) );
        // Am I being sorted?
        if (sorted) {
            node.className += " sorted";
            // Am I sorting ascendingly?
            if (direction) {
                // Add the sort direction icon
                var img = document.createElement("img");
                img.src = document.getElementById('advancedSearch_sortAsc').src;
                img.style.marginLeft = "8px";
                node.appendChild(img);
                // Set the sorting func
                node.onclick = function () {
                    thisResultsTable.sortData(field, "desc");
                };
            } else {
                // Add the sort direction icon
                var img = document.createElement("img");
                img.src = document.getElementById('advancedSearch_sortDesc').src;
                img.style.marginLeft = "8px";
                node.appendChild(img);
                // Set the sorting func
                node.onclick = function () {
                    thisResultsTable.sortData(field, "asc");
                };
            }
        } else {
            // Add the invisible sort direction icon
            var img = document.createElement("img");
            img.src = document.getElementById('advancedSearch_sortNone').src;
            img.style.marginLeft = "8px";
            img.style.width = "11px";
            img.style.height = "14px";
            node.appendChild(img);
            // Set the sorting func
            node.onclick = function () {
                thisResultsTable.sortData(field, "asc");
            };
        }
    };
    // Build the headers
    var thisResultsTable = this;
    for (var i=0; i<this._headers.length; i++) if (this._headers[i]) {
        switch (this._headers[i].name) {
            case "title" : {
                headerBuilder(this._headers[i]._node, this._headers[i].name, (this._headers[i].title ? this._headers[i].title : "Title"), (field == this._headers[i].name), ascending);
                break;
            }
            case "rating" : {
                headerBuilder(this._headers[i]._node, this._headers[i].name, (this._headers[i].title ? this._headers[i].title : "Rating"), (field == this._headers[i].name), ascending);
                break;
            }
            case "creation" : {
                headerBuilder(this._headers[i]._node, this._headers[i].name, (this._headers[i].title ? this._headers[i].title : "Created On"), (field == this._headers[i].name), ascending);
                break;
            }
            case "modified" : {
                headerBuilder(this._headers[i]._node, this._headers[i].name, (this._headers[i].title ? this._headers[i].title : "Modified On"), (field == this._headers[i].name), ascending);
                break;
            }
            case "author" : {
                headerBuilder(this._headers[i]._node, this._headers[i].name, (this._headers[i].title ? this._headers[i].title : "Author"), (field == this._headers[i].name), ascending);
                break;
            }
            case "space" : {
                headerBuilder(this._headers[i]._node, this._headers[i].name, (this._headers[i].title ? this._headers[i].title : "Space"), (field == this._headers[i].name), ascending);
                break;
            }
        }
    }
};

var AdvancedSearchConfiguration = {
    fields: [{name:"title",title:"Resource"},{name:"rating"},{name:"creation"},{name:"modified"},{name:"author"},{name:"space",title:"Partner"}],
    types: ["page","blogpost"], showExcerpts: true, sortField: "title", sortDir: "asc", maxResults: 20, rateThreshold: 5, debug: false
};

function advancedSearch_lockControls(form, disable) {
    var lockControls = function (controls, disable) {
        for (var i=0; i<controls.length; i++) if (controls[i]) {
            controls[i].disabled = disable;
        }
    };
    // Disable the controls
    lockControls(form.getElementsByTagName("input"), disable);
    lockControls(form.getElementsByTagName("select"), disable);
}

function advancedSearch_submit(form) {
    var thisForm = form;
    // Disable the controls
    advancedSearch_lockControls(thisForm, true);
    // Data switch
    var excludeSpaceKeys = false; // TODO: Find out how to set this in the form?    
    // Build the data sets (spaceKeys, label, metadata, queries)
    var spaceKeys = [];
    var labels = [];
    var metadata = {};
    var queries = [];
    // Find any input items
    var processControls = function (controls) {
        for (var i=0; i<controls.length; i++) if (controls[i]) {
            var control = controls[i];
            // If I am a check box, skip if I am not checked
            if (control.tagName.toLowerCase() == "input" && control.type.toLowerCase() == "checkbox" && !control.checked) {
                continue;
            }
            // Check I have a value
            if (!control.value || control.value.length == 0) {
                continue;
            }
            // Process the data
            if (control.name == "advancedSearch_label") {
                labels.push(control.value);
            } else if (control.name == "advancedSearch_query") {
                queries.push(control.value);
            } else if (control.name == "advancedSearch_spaceKey") {
                spaceKeys.push(control.value);
            } else if (control.name.substring(0, 24) == "advancedSearch_metadata.") {
                metadata[ control.name.substring(24) ] = control.value;
            }
        }
    };
    processControls( form.getElementsByTagName("input") );
    processControls( form.getElementsByTagName("select") );
    // Throw up the spinner
    document.getElementById("advancedSearch_results").innerHTML = document.getElementById("advancedSearch_waitingMessage").innerHTML;
    // Build the field names
    var fieldNames = [];
    for (var i=0; i<AdvancedSearchConfiguration.fields.length; i++) if (AdvancedSearchConfiguration.fields[i]) {
        fieldNames.push( AdvancedSearchConfiguration.fields[i].name );
    }
    // Call DWR
    SearchDWR.doSearch(spaceKeys, excludeSpaceKeys, AdvancedSearchConfiguration.types, labels, metadata, queries, fieldNames, AdvancedSearchConfiguration.showExcerpts, AdvancedSearchConfiguration.maxResults, AdvancedSearchConfiguration.rateThreshold,
        { callback:function (resultSet) {
            // Enable the controls
            advancedSearch_lockControls(thisForm, false);
            // Display the table
            new ResultsTable(AdvancedSearchConfiguration.fields, AdvancedSearchConfiguration.showExcerpts, AdvancedSearchConfiguration.sortField, AdvancedSearchConfiguration.sortDir, resultSet, document.getElementById("advancedSearch_results"));
        }, errorHandler:function(errorString, exception) {
            // Enable the controls
            advancedSearch_lockControls(thisForm, false);
            // Display the error
            alert(errorString);
        } }
    );
}
