/*
*
* Copyright (c) 2007 Andrew Tetlaw & Millstream Web Software
* http://www.millstream.com.au/view/code/tablekit/
* Version: 1.2.1 2007-03-11
* 
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* * 
*/

Object.extend(String.prototype, {
    pluralize: function() {
        var l = this.length;
        return this.substr(l - 1) === 'y' ? this.substr(0, l - 1) + 'ies' : this + 's';
    }
});

if (window.Type) {
    Type.registerNamespace('WebTango');
} else {
    WebTango = {};
}

if (window.WebTangoConstantsLoader) { WebTangoConstantsLoader(); }

//a wrapper function for the script manager notification crap
//just to have a central place to remove it later
WebTango.notifyScriptManager = function() {
    if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
}

WebTango.DomUtils = Class.create({});
Object.extend(WebTango.DomUtils, {
    //clear the text selected with the mouse
    clearSelection: function() {
        if (document.selection && document.selection.empty) {
            //IE
            document.selection.empty();
        }
        if (window.getSelection) {
            //Others (but not relevant to FF)
            var sel = window.getSelection();
            if (sel && sel.rangeCount > 0 && sel.getRangeAt) {
                var rng = sel.getRangeAt(0);
                if (rng) {
                    rng.collapse(true);
                }
            }
        }
    },
    //returns n if node is an nth child
    getChildIndex: function(node) {
        node = $(node);
        var idx = -1;
        while (node) {
            node = node.previous();
            ++idx;
        }
        return idx;
    },
    getDropDownSelectedText: function(dropdown) {
        if (dropdown.selectedIndex == -1) { return null; }
        return dropdown.options[dropdown.selectedIndex].innerHTML;
    },
    makeLabelAndExplanation: function(label, explanation) {
        return Builder.node("span", { className: "label" }, [
            label,
            Builder.node("span", { className: "explanation" }, explanation)
        ]);
    },
    //replaces oldNode with newNode in-situ in the DOM, returning the new node
    replaceNode: function(newNode, oldNode) {
        var parent = $(oldNode).up();
        parent.replaceChild(newNode, oldNode);
        return newNode;
    },
    setDropDownValue: function(dropdown, newValue) {
        var opts = dropdown.options;
        var optCount = opts.length;
        var found = false;
        for (var i = 0; i < optCount; ++i) {
            var opt = opts[i];
            if (opt.value == newValue) {
                dropdown.selectedIndex = i;
                found = true;
                break;
            }
        }
        if (!found) { dropdown.selectedIndex = -1; }
    },
    setDropDownValues: function(dropdown, newValues) {
        dropdown.selectedIndex = -1; //deselect all;
        var opts = dropdown.options;
        var optCount = opts.length;
        var newValCount = newValues.length;
        for (var i = 0; i < newValCount; ++i) {
            var newValue = newValues[i];
            for (var j = 0; j < optCount; ++j) {
                var opt = opts[j];
                if (opt.value === newValue) {
                    opt.selected = true;
                    break;
                }
            }
        }
    },
    //toggle visibility of dom element 'elm', persisting the setting
    //in cookie 'cookieName'
    toggleWithCookie: function(elm, cookieName) {
        elm = $(elm);
        if (elm.visible()) {
            elm.hide();
            WebTango.Cookies.setCookie(cookieName, 'true', 14, '/', '', false);
        } else {
            elm.show();
            WebTango.Cookies.deleteCookie(cookieName, '/', '');
        }
    }
});

WebTango.Buttons = Class.create({});
Object.extend(WebTango.Buttons, {
    _KILLONCLICK: "this.blur();return false;",

    //this function makes the full-blown buttons with presently green image
    //they can be aligned left or right, or can be unaligned
    //the color of the button is defined based on whether the button is 'positive' or 'negative'
    big: function(text, align, isPositive) {
        if (align === undefined) { align = ""; }
        if (isPositive === undefined) { isPositive = true; }
        var cssClass = "button " + align + (isPositive ? "" : " negativebtn");

        return Builder.node("a", { className: cssClass, href: "#", onclick: WebTango.Buttons._KILLONCLICK }, Builder.node("span", text));
    },
    //this function makes a simple A-tag button.
    //the isPositive parameter can be true (cssclass: "positive")
    //false (cssclass: "negative"), or undefined (no cssclass)
    link: function(text, isPositive) {
        var cssClass = "";
        if (isPositive !== undefined) {
            cssClass = isPositive ? "positive" : "negative";
        }
        return Builder.node("a", { className: cssClass, href: "#", onclick: WebTango.Buttons._KILLONCLICK }, text);
    },
    createContentLink: function(text, typeName) {
        var createContentButton = $(Builder.node("a", { className: "positive", href: "#", onclick: WebTango.Buttons._KILLONCLICK }, text));
        Event.observe(createContentButton, "click", function() {
            WebTango.CreateContentModal.show({ defaultType: typeName });
        });
        return createContentButton;
    },
    createContentButton: function(options) {
        var defaultOptions = {
            align: "",
            text: "CREATE",
            baseType: null,
            defaultType: null
        };
        options = Object.extend(defaultOptions, options || {});
        var createContentButton = $(Builder.node("a", { className: "button " + options.align, href: "#", onclick: WebTango.Buttons._KILLONCLICK }, Builder.node("span", options.text)));
        Event.observe(createContentButton, "click", function() {
            WebTango.CreateContentModal.show({ defaultType: options.defaultType, baseType: options.baseType });
        });
        return createContentButton;
    },
    //makes a gray button for the home-made dropdown menus at the top of the doc editor
    //(e.g. language button)
    menu: function(text) {
        return Builder.node("a", { /*className: "dropdownbutton",*/href: "#", onclick: WebTango.Buttons._KILLONCLICK },
            Builder.node("span", text)
        );
    },
    search: function() {
        return Builder.node("a", { className: "searchbutton", href: "#", onclick: WebTango.Buttons._KILLONCLICK }, Builder.node("span", "SEARCH"));
    },
    //update the text of a button generated with WebTango.Buttons.menu
    setMenuText: function(button, text) {
        button.immediateDescendants()[0].innerHTML = text;
    }
});


function WebDeskLinkCellRenderer(row, table, text) {
    if (text === undefined) { text = row[this.columnName]; }
    
    var type = row.ObjectType || table.objectType;
    return Builder.node("a", { href : WebTango.makeWebDeskUrl(type,row.OID) }, text);
}

function StockCellRenderer(row, table) {
    return Builder.node("div", { className : (row.Stock == "Available" ? "iconLager" : "" )});
}

function AddToCartCellRenderer(row, table) {
    var oid = row.OID;
    var addToCartButton = null;
    var amountTextBox = null;
    var addingDiv = null;
    var addToCartSpan = null;
    var addSpan = null;
    
    addSpan = $(Builder.node("span", {}, [
        addToCartSpan = $(Builder.node("span", {}, [
            addToCartButton = $(Builder.node("a", { href : "javascript:void(0)", className : "tilfoj" }, WebTango.Add)),
            amountTextBox = Builder.node("input", {type: "text", "style": "width: 25px", value: "1"}, ""),
        ])),
        addingDiv = $(Builder.node("div", {style: "display:none"}, [
            Builder.node("img", {src:"/images/small-spinner.gif", id:"test"})
        ]))
    ]));
    
    Event.observe(addToCartButton, "click", addToCart.bind(this, oid, addToCartButton, amountTextBox, addToCartSpan, addingDiv));
    return addSpan;
}

function ProductInfoCellRenderer(row, table) {
    var oid = row.OID;
    var getInfoButton = $(Builder.node("a", { href : "#productOverlay" }, WebTango.DetailedInfo));
    $JQ(getInfoButton).facebox();
    Event.observe(getInfoButton, "click", function() {
        $JQ('#productOID').val(row.OID);
        $JQ('#productAmount').val(1);
        $JQ('#productID').html(row.ID);
        $JQ('#productItemName').html(row.ItemName);
        $JQ('#productItemName2UK').html(row.ItemName2UK);
        $JQ('#productApproval').html(row.Approval);
        $JQ('#productInnerDiameter').html(row.InnerDiameter);
        $JQ('#productOuterDiameter').html(row.OuterDiameter);
        $JQ('#productThickHigh').html(row.ThickHigh);
        $JQ('#productMaterial').html(row.Material);
        $JQ('#productPrice').html(row.Price);
        if (row.ImgName != "") {
            $JQ('#productImage').attr("src", "/images/profiles/" + row.ImgName.replace("BMP", "jpeg").replace("bmp", "jpeg").replace("%20", " "));
            $JQ('#productImage').show();
        } else {
            $JQ('#productImage').hide();
        }
        if (row.Stock == "Available") {
            $JQ('#productStock').show();
        } else {
            $JQ('#productStock').hide();
        }

    } .bind(this));
    return getInfoButton;
}

//this renderer requires the column data to be the absolute url of the image
function ThumbNailCellRenderer(row, table) {
    if (row[this.columnName].length === 0) { return ""; }
    
    var imageNode = Builder.node("img", { src : row[this.columnName] , alt : "" } );
    $(imageNode).setStyle({ "height" : "18px" });
    var linkNode = Builder.node("a", { href : row[this.columnName] }, imageNode);
    $(imageNode).setStyle({ "border" : "none" });
    var unused = new Tip(imageNode, "<img src='"+ row[this.columnName] +"' alt='' style='width:130px'/>");
    return linkNode;
}

//this function generates a cell rendering function based on a linkFormat object.
//the linkformat object is expected to describe the fields in which the cell data object stores the
//href and text of the link respectively, e.g.
//linkformat = { href : "HrefField", text : "TextField" }
//where the cell data is of the form: { HrefField : "http://www.google.com", TextField : "The non-evil search engine" }

function GetLinkCellRenderer(linkFormat) {
    return function (row, table) {
        var cellData = row[this.columnName];
        if (typeof(cellData) !== 'object') { return ""; }
        return Builder.node("a", { href : cellData[linkFormat.href] }, "" + cellData[linkFormat.text]);
    };
}

function GetImageCellRenderer(urlPrefix, extension) {
    urlPrefix = urlPrefix || "";
    extension = (extension === undefined) ? ".gif" : extension;
    return function (row, table) {
        return Builder.node("img", { src : urlPrefix + row[this.columnName] + extension, alt : ""});
    };
}

function ArrayCellRenderer(row,table) {
    var theArray = row[this.columnName];
    if (theArray === undefined) { return ""; }
    var l = theArray.length, result = "";
    if (l === 0) { return ""; }
    
    for (var i=0;i<l-1;++i) {
        result += theArray[i] + ", ";
    }
    result += theArray[l-1];
    return result;
}

function DefaultCellRenderer(row, table) {
    var data = row[this.columnName];
    if (this.cellFormat) {
        return String.localeFormat(this.cellFormat, data);
    }
    if (data === true) { data = "Yes"; }
    if (data === false) { data = "No"; }
    if (data === 0) { data = "0"; }
    return data;
}

//this creates a cell rendering function that looks up the values to render in
//the hash given as the argument. The data stored in the cell is the key
//The getterFunction is used when the hash values are complex objects, in order to
//extract the cell text from those objects
function GetLookupCellRenderer(hash, getterFunction) {
    return function(row, table) {
        var data = hash.get(row[this.columnName]);
        if (getterFunction) {
            data = getterFunction(data);
        }
        if (this.cellFormat) {
            data = String.localeFormat(this.cellFormat, data);
        }
        return data;
    };
}

function DummyRenderer() {
    return " ";
}

function GetTextboxCellRenderer(options) {
    return function(row, table) {
        var nestedRenderer = options.nestedRenderer || DefaultCellRenderer;
        nestedRenderer = nestedRenderer.bind(this);
        
        var textBoxRenderer = DefaultCellRenderer;
        textBoxRenderer = textBoxRenderer.bind(this);
        var data = nestedRenderer(row, table);
        
        var textBox, dataSpan, spinner;
        var mainSpan = 
        Builder.node("span", [
            dataSpan = $(Builder.node("span", data)),
            textBox = $(Builder.node("input", { type : "text" })),
            spinner = $(Builder.node("span", [ Builder.node("img", { src : "/images/spinner.gif", alt : "" }), "Saving..." ]))
        ]);
        textBox.hide();
        if (options.textBoxClass) { textBox.addClassName(options.textBoxClass); }
        textBox.value = textBoxRenderer(row, table);
        spinner.hide();
        
        mainSpan.isSaving = false;
        
        mainSpan.enterEditMode = function() {
            if (mainSpan.isSaving) { return; }
            textBox.show();
            if (options.activate) { textBox.activate(); }
            dataSpan.hide();
        };
        
        mainSpan.cancelEditMode = function() {
            textBox.hide();
            dataSpan.show();
        };
        
        mainSpan.startSave = function(updatedRow) {
            var val = textBox.value;
            if (options.parseValue) { val = options.parseValue(val); }
            
            updatedRow[this.columnName] = val;
            
            textBox.hide();
            dataSpan.hide();
            spinner.show();
            mainSpan.isSaving = true;
        }.bind(this);
        
        mainSpan.saveNewValue = function(savedRow) {
            textBox.value = textBoxRenderer(savedRow, table);
            var children = dataSpan.immediateDescendants();
            if (children.length > 0) {
                children[0].remove();
                dataSpan.appendChild(nestedRenderer(savedRow, table));
            } else {
                dataSpan.innerHTML = nestedRenderer(savedRow, table);
            }
            
            spinner.hide();
            dataSpan.show();
            mainSpan.isSaving = false;
        }.bind(this);
        
        return mainSpan;
    };
}

function GetCheckboxCellRenderer(options) {
    return function(row, table) {
        var nestedRenderer = options.nestedRenderer || DefaultCellRenderer;
        nestedRenderer = nestedRenderer.bind(this);
        
        var textBoxRenderer = DefaultCellRenderer;
        textBoxRenderer = textBoxRenderer.bind(this);
        var data = nestedRenderer(row, table);
        
        var checkBox, dataSpan, spinner;
        var mainSpan = 
        Builder.node("span", [
            dataSpan = $(Builder.node("span", data)),
            checkBox = $(Builder.node("input", { type : "checkbox" })),
            spinner = $(Builder.node("span", [ Builder.node("img", { src : "/images/spinner.gif", alt : "" }), "Saving..." ]))
        ]);
        checkBox.hide();
        if (options.textBoxClass) { textBox.addClassName(options.textBoxClass); }
        var chk = textBoxRenderer(row, table);
        checkBox.checked = chk == "Yes";
        spinner.hide();
        
        mainSpan.isSaving = false;
        
        mainSpan.enterEditMode = function() {
            if (mainSpan.isSaving) { return; }
            checkBox.show();
            if (options.activate) { checkBox.activate(); }
            dataSpan.hide();
        };
        
        mainSpan.cancelEditMode = function() {
            checkBox.hide();
            dataSpan.show();
        };
        
        mainSpan.startSave = function(updatedRow) {
            var val = checkBox.checked;
            
            updatedRow[this.columnName] = val;
            
            checkBox.hide();
            dataSpan.hide();
            spinner.show();
            mainSpan.isSaving = true;
        }.bind(this);
        
        mainSpan.saveNewValue = function(savedRow) {
            checkBox.checked = textBoxRenderer(savedRow, table) == "Yes";
            var children = dataSpan.immediateDescendants();
            if (children.length > 0) {
                children[0].remove();
                dataSpan.appendChild(nestedRenderer(savedRow, table));
            } else {
                dataSpan.innerHTML = nestedRenderer(savedRow, table);
            }
            
            spinner.hide();
            dataSpan.show();
            mainSpan.isSaving = false;
        }.bind(this);
        
        return mainSpan;
    };
}

function GetDropdownCellRenderer(ddvalues, options) {
    if (options === undefined) { options = {}; }
    return function(row, table) {
        var nestedRenderer = options.nestedRenderer || DefaultCellRenderer;
        nestedRenderer = nestedRenderer.bind(this);
        
        var dropdownRenderer = DefaultCellRenderer;
        dropdownRenderer = dropdownRenderer.bind(this);
        var data = nestedRenderer(row, table);
        
        var dropdown, dataSpan, spinner;
        var mainSpan = 
        Builder.node("span", [
            dataSpan = $(Builder.node("span", data)),
            dropdown = $(Builder.node("select", { className : "slimselect" } )),
            spinner = $(Builder.node("span", [ Builder.node("img", { src : "/images/spinner.gif", alt : "" }), "Saving..." ]))
        ]);
        dropdown.hide();
        spinner.hide();
        
        mainSpan.isSaving = false;
        
        mainSpan.childrenLoaded = false;
        
        mainSpan.enterEditMode = function() {
            if (mainSpan.isSaving) { return; }
            if (!mainSpan.childrenLoaded) {
                var selIndex = -1;
                
                if (options.valuesAsHash === true) {
                    var i=0;
                    ddvalues.each( function(pair) {
                        if (pair.value == data) { selIndex = i; }
                        dropdown.appendChild(Builder.node("option", { value : pair.key }, pair.value));
                        i++;
                    });
                } else {
                    for (var j=0;j<ddvalues.length;++j) {
                        if (ddvalues[j] == data) { selIndex = j; }
                        dropdown.appendChild(Builder.node("option", ddvalues[j]));
                    }
                }
                dropdown.selectedIndex = selIndex;
                mainSpan.childrenLoaded = true;
            }
            dropdown.show();
            if (options.activate) { dropdown.activate(); }
            dataSpan.hide();
        };
        
        mainSpan.cancelEditMode = function() {
            dropdown.hide();
            dataSpan.show();
        };
        
        mainSpan.startSave = function(updatedRow) {
            updatedRow[this.columnName] = $F(dropdown);
            
            dropdown.hide();
            dataSpan.hide();
            spinner.show();
            mainSpan.isSaving = true;
        }.bind(this);
        
        mainSpan.saveNewValue = function(savedRow) {
            var newVal = dropdownRenderer(savedRow, table);
            for (var i=0;i<dropdown.options.length;++i) {
                if (dropdown.options[i].value == newVal) {
                    dropdown.selectedIndex = i;
                    break;
                }
            }
            
            var children = dataSpan.immediateDescendants();
            if (children.length > 0) {
                children[0].remove();
                dataSpan.appendChild(nestedRenderer(savedRow, table));
            } else {
                dataSpan.innerHTML = nestedRenderer(savedRow, table);
            }
            
            spinner.hide();
            dataSpan.show();
            mainSpan.isSaving = false;
        }.bind(this);
        
        return mainSpan;
    };
}

function GetAutocompleteRenderer(values, options) {
        
    if (options === undefined) { options = {}; }
    return function(row, table) {
        var nestedRenderer = options.nestedRenderer || DefaultCellRenderer;
        nestedRenderer = nestedRenderer.bind(this);
        
        var dropdownRenderer = DefaultCellRenderer;
        dropdownRenderer = dropdownRenderer.bind(this);
        var data = nestedRenderer(row, table);
        
        var autocompleteID = "test_" + row.OID;
        var textbox, dataSpan, spinner;
        var mainSpan = 
        Builder.node("span", [
            dataSpan = $(Builder.node("span", data)),
            textbox = $(Builder.node("input", { type: "text", className: "text autocomplete", id: autocompleteID } )),
            spinner = $(Builder.node("span", [ Builder.node("img", { src : "/images/spinner.gif", alt : "" }), "Saving..." ]))
        ]);
        textbox.hide();
        spinner.hide();
        
        mainSpan.isSaving = false;
        
        mainSpan.childrenLoaded = false;
        
        mainSpan.enterEditMode = function() {
            if (mainSpan.isSaving) { return; }
            textbox.show();
            dataSpan.hide();
        };
        
        mainSpan.cancelEditMode = function() {
            textbox.hide();
            dataSpan.show();
        };
        
        mainSpan.startSave = function(updatedRow) {
            updatedRow[this.columnName] = $F(dropdown);
            
            textbox.hide();
            dataSpan.hide();
            spinner.show();
            mainSpan.isSaving = true;
        }.bind(this);
        
        mainSpan.saveNewValue = function(savedRow) {
            var newVal = dropdownRenderer(savedRow, table);
            for (var i=0;i<dropdown.options.length;++i) {
                if (dropdown.options[i].value == newVal) {
                    dropdown.selectedIndex = i;
                    break;
                }
            }
            
            var children = dataSpan.immediateDescendants();
            if (children.length > 0) {
                children[0].remove();
                dataSpan.appendChild(nestedRenderer(savedRow, table));
            } else {
                dataSpan.innerHTML = nestedRenderer(savedRow, table);
            }
            
            spinner.hide();
            dataSpan.show();
            mainSpan.isSaving = false;
        }.bind(this);
        
        Autocomplete.entries[autocompleteID] = new AutocompleteInput(autocompleteID, textbox);
        Autocomplete.entries[autocompleteID].register();
        Autocomplete.entryIds.push(autocompleteID);
        
        var suggestions = "";
        values.each(function (pair) {
            var strValue = pair.value.replace(/ /g, "_").toLowerCase();
            if (strValue.indexOf('alger') == -1 && strValue.indexOf('_') == -1) {
                if (suggestions == "")
                    suggestions += strValue+','+strValue.length;
                else
                    suggestions += " " + strValue+','+strValue.length;   
            }
        });
        
        return mainSpan;
    };
}


function PriceCellRenderer(row, table) {
    var data = row[this.columnName];
    if (this.cellFormat) {
        return String.localeFormat(this.cellFormat + " " + currencyCode, data);
    }
    return data;
}

/* -------------------------------------------------------------------------------------*/
/* -------------------------------------------------------------------------------------*/
/* WebTango delete panel class                                                          */
/* -------------------------------------------------------------------------------------*/
/* -------------------------------------------------------------------------------------*/


var WTConfirmPanel = Class.create();

WTConfirmPanel.prototype = {
    initialize : function(parentElm, typeName) {
        this.typeName = typeName || "item";
        
        this.confirmButton = WebTango.Buttons.big("DELETE", "right", false);

        Event.observe(this.confirmButton, "click", function() { $(this.mainDiv).hide(); }.bindAsEventListener(this) );
        this.cancelButton = WebTango.Buttons.big("CANCEL");
        
        this.textSpan = Builder.node("span", {}, "Are you sure you wish to delete this item?");
        
        this.mainDiv =
        Builder.node("div", {className : "negativepanel uniquepanel", style : "display:none"}, [
            this.heading = Builder.node("h2", {}, "Delete?"),
            this.textSpan,
            Builder.node("div", {className : "bottompanel"}, [
                this.confirmButton,
                this.cancelButton
            ])
        ]);
        
        parentElm.appendChild(this.mainDiv);
        
        Event.observe(this.cancelButton, "click", function() { $(this.mainDiv).hide(); }.bindAsEventListener(this) );
    },
    
    addOnConfirmListener : function(listener) {
        Event.observe(this.confirmButton, "click", listener);
    },
    
    show : function(deletingEntityName, cancelButtonText, confirmButtonText, operationName, heading) {
        heading = heading || "Delete?";
        operationName = operationName || "delete";
        confirmButtonText = confirmButtonText || "DELETE";
        cancelButtonText = cancelButtonText || "CANCEL";
        this.confirmButton.innerHTML = "<span>" + confirmButtonText + "</span>";
        this.cancelButton.innerHTML = "<span>" + cancelButtonText + "</span>";
        this.heading.innerHTML = heading;
        
        this.textSpan.innerHTML = "Are you sure you wish to " + operationName + " the " + this.typeName + " " + deletingEntityName + "?";
        $(this.mainDiv).show();
    }
};


/* -------------------------------------------------------------------------------------*/
/* -------------------------------------------------------------------------------------*/
/* WebTango tablekit adaptation - WebTango.Table                                            */
/* -------------------------------------------------------------------------------------*/
/* -------------------------------------------------------------------------------------*/

var WTPagingMode = Class.create();
Object.extend(WTPagingMode, 
{
    First : 0,
    Previous : 1,
    Next : 2,
    Last : 3
});

WebTango.Table = Class.create({
    initialize: function(elm, options, /*rows, rowCount,*/objectType) {

        var container = $(elm);

        this.containerId = container.id;
        this.id = this.containerId + "-WebTango.Table";

        options = Object.extend(WebTango.Table.options, options || {});

        //this.webDeskObject = webDeskObject;
        this.columns = options.columns;

        this.handlersRegistered = false;

        //events:
        this.onAfterPaging = options.onAfterPaging;
        this.onRowDeleted = options.onRowDeleted;

        this.alwaysShowFooter = options.alwaysShowFooter;
        this.pageSize = options.pageSize;
        //this.rowCount = rowCount;

        this.pageCount = Math.max(1, Math.ceil(this.rowCount / this.pageSize));

        this.pageIndex = 0;
        this.sortAscending = options.sortAscending;
        this.sortColumn = options.initialSort || this.columns[0].columnName;

        this.searcherType = options.searcherType;
        this.urlAnchorPrefix = options.urlAnchorPrefix;

        this.searchFilter = this.lastSearchFilter = options.initialSearchFilter || WebTango.Searcher.parseFromUrl(this.searcherType, this.urlAnchorPrefix);
        //the default search filter is the filter used when the user "clears" the search - this can
        //be different from the initial search filter if a saved search filter was found in the session
        this.defaultSearchFilter = options.defaultSearchFilter || options.initialSearchFilter
        this.searchWidgets = $A();

        this.typeName = options.typeName;
        this.objectType = objectType;

        this.emptyPanel = options.emptyPanel || Builder.node("div", { className: "attentionpanel" }, WebTango.NoProductsFound);

        this.nameField = options.nameField;

        if (options.columnBitMask !== undefined) {
            var pow = 1;
            for (var i = 0; i < this.columns.length; ++i) {
                this.columns[i].isVisible = !!(options.columnBitMask & pow);
                pow *= 2;
            }
        }

        this.tfoot = $(Builder.node("tfoot"));
        this._buildMain(container);
        //this._buildTable(rows);
        this.webService = options.webService;

        //this._doPaging();

        //WebTango.Table.register(this.table,options);

        //WebTango.Table.Resizable.init(this.table);
    },



    addRow: function(rowObj/*, allowEdit*/) {
        var rowNode = this._buildRow(rowObj);
        this.table.tBodies[0].appendChild(rowNode);
        //remove the tablekit row cache;
        WebTango.Table.rows[this.table.id] = null;
        //restripe
        WebTango.Table.Rows.stripe(this.table);

        this.rowCount++;
        this._updateCounts();
        this._showTableOrEmptyPanel();
        var unused = new Effect.Highlight(rowNode);

        //WebTango.Table.addRow(this.id, rowdata, allowEdit);
    },
    refreshRow: function(rowObj) {
        var oldRow = $(this.getRowId(rowObj.OID));
        if (!oldRow) {
            //insert row if not already present:
            this.addRow(rowObj);
        } else {
            var newRow = this._buildRow(rowObj);
            WebTango.DomUtils.replaceNode(newRow, oldRow);
        }
    },

    sort: function(column, order) {
        WebTango.Table.Sortable.sort(this.id, column, order);
    },
    resizeColumn: function(column, w) {
        WebTango.Table.Resizable.resize(this.id, column, w);
    },
    editCell: function(row, column) {
        WebTango.Table.Editable.editCell(this.id, row, column);
    },

    addSearchWidget: function(widget) {
        this.searchWidgets.push(widget);
        //widget.render();
    },

    getSearchFilter: function() {
        if (this.searcherPostDeserialization) {
            return this.searcherPostDeserialization(Object.clone(this.searchFilter));
        }
        return Object.clone(this.searchFilter);
    },

    clearSearch: function() {
        this.searchFilter = Object.clone(this.defaultSearchFilter);
        this.searchWidgets.each(function(widget) {
            widget.onSearcherUpdated(Object.clone(this.defaultSearchFilter));
        }, this);
        this.search();
    },

    search: function(newSearchFilter, callingWidget) {
        this.pageIndex = 0;
        if (newSearchFilter) {
            this.searchFilter = Object.clone(newSearchFilter);
        }
        if (callingWidget) {
            //reset all widgets to the default search state
            this.searchWidgets.each(function(widget) {
                widget.onSearcherUpdated(Object.clone(this.defaultSearchFilter));
            }, this);
            //then give the caller back the actual state
            callingWidget.onSearcherUpdated(Object.clone(this.searchFilter));
        } else {
            this.searchWidgets.each(function(widget) {
                widget.onSearcherUpdated(Object.clone(this.searchFilter));
            }, this);
        }
        this._doPaging();
    },

    _toggleColumn: function(columnIdx) {
        //special support for the actions row even though it is not part of the columns array
        //only set isVisible for the other columns
        if (columnIdx >= 0 && columnIdx < this.columns.length) {
            this.columns[columnIdx].isVisible = !this.columns[columnIdx].isVisible;
        }

        var headRow = this.table.tHead ? this.table.tHead.rows[0] : this.table.rows[0]; //no tHead in Safari!

        $(headRow.cells[columnIdx]).toggle();

        var rows = this.table.tBodies[0].rows;
        var rowCount = rows.length;
        for (var r = 0; r < rowCount; ++r) {
            $(rows[r].cells[columnIdx]).toggle();
        }
    },  
    
    _buildMain: function(containerElm) {

        this.firstButton = $(Builder.node("a", { href: "#", className: "navFirst", title: "First", onclick: 'return false;'}));
        this.previousButton = $(Builder.node("a", { href: "#", className: "navPrevious", title: "Previous", onclick: 'return false;' }));
        this.nextButton = $(Builder.node("a", { href: "#", className: "navNext", title: "Next", onclick: 'return false;' }));
        this.lastButton = $(Builder.node("a", { href: "#", className: "navLast", title: "Last", onclick: 'return false;'}));

        //this.firstButton.disable();
        //this.previousButton.disable();
        //if (this.pageCount < 2) {
        //    this.nextButton.disable();
        //    this.lastButton.disable();
        //}

        Event.observe(this.firstButton, "click", this._onPageButtonClick.bindAsEventListener(this, WTPagingMode.First));
        Event.observe(this.previousButton, "click", this._onPageButtonClick.bindAsEventListener(this, WTPagingMode.Previous));
        Event.observe(this.nextButton, "click", this._onPageButtonClick.bindAsEventListener(this, WTPagingMode.Next));
        Event.observe(this.lastButton, "click", this._onPageButtonClick.bindAsEventListener(this, WTPagingMode.Last));

        this.rowCountElement = $(Builder.node("span", "" + this.rowCount));
        this.currentPageElement = $(Builder.node("input", { value: this.pageIndex + 1, type: "text", className: "pageNumberInputStyle" }));
        this.pageCountElement = $(Builder.node("span", {}, "" + this.pageCount));


        this.pageSizeDropDown = $(
	        Builder.node("select", { className: "slimselect" }, $A([20, 50, 100]).map(function(i) { return Builder.node("option", "" + i); }))
	    );
        WebTango.DomUtils.setDropDownValue(this.pageSizeDropDown, "" + this.pageSize);

        this.pageSizeDropDown.observe("change", function() {
            this.pageSize = parseInt($F(this.pageSizeDropDown));
            this.pageIndex = 0;
            this._doPaging();
        } .bind(this));

        var currentPageHandler = function(eventArgs) {
            if (eventArgs.keyCode == Event.KEY_RETURN) {
                var pageNumber = parseInt(this.currentPageElement.value, 10);
                if (isNaN(pageNumber) || pageNumber < 1 || pageNumber > this.pageCount) {
                    WebTango.Feedback.negative("Invalid page number, please enter an integer between 1 and " + this.pageCount);
                    this.currentPageElement.value = "" + (this.pageIndex + 1);
                } else {
                    this.pageIndex = pageNumber - 1;
                    this._doPaging();
                }
                Event.stop(eventArgs);
            }
        } .bindAsEventListener(this);

        var activateOnFocus = function() {
            $(this.currentPageElement).activate();
        } .bind(this);

        Event.observe(this.currentPageElement, "keypress", currentPageHandler);
        Event.observe(this.currentPageElement, "focus", activateOnFocus);

        this.tableContainer = Builder.node("div", { style: 'display:none' });

        this.confirmPanel = new WTConfirmPanel(containerElm, this.typeName);


        this.loadingPanel =
	    $(Builder.node("div", { style: 'display:none', className: "tableloadingpanel" }, [
                Builder.node("br"),
                Builder.node("div", [
                    Builder.node("img", { alt: '', src: '/images/loading-mac.gif' }),
                    'Henter ' + this.typeName.pluralize() + '...'
                ])
        ]));

        var loadingAndTableDiv =
	    $(Builder.node("div", { className: "tableloadingcontainer" }, [
            this.loadingPanel,
            this.tableContainer
        ]));

        this.pagingDiv =
        $(Builder.node("div", { className: "pagingfooter" }, [
            Builder.node("ul", [
                Builder.node("li", this.firstButton),
                Builder.node("li", this.previousButton),
                Builder.node("li", { className: "pagenumber" }, /*Builder.node("span", {},*/[

                    this.currentPageElement,
                    " of ",
                    this.pageCountElement
                ])/*)*/,
                Builder.node("li", this.nextButton),
                Builder.node("li", this.lastButton),
                Builder.node("li", { className: "pagenumber" }, [
                    "Total: ",
                    this.rowCountElement
                ]),
                Builder.node("li", { className: "pagenumber" }, [
                    " Page size: ",
                    this.pageSizeDropDown
                ])
            ])
        ]));

        this._updatePagerVisibility();
        var pagerColumn;
        this.tfoot.appendChild($(Builder.node("tr", {}, [
            pagerColumn = $(Builder.node("td", {"colspan": "8", "align" : "right"}, [
                $(Builder.node("div", {className: "sortSettings"}, [
                    $(Builder.node("div", {className: "perPage"}, [
                        WebTango.PageSize,
                        this.pageSizeDropDown
                    ])),
                    this.firstButton,
                    this.previousButton,
                    $(Builder.node("div", {className: "pageNumber"}, [
                        this.currentPageElement,
                        " " + WebTango.PageSizeOf + " ",
                        this.pageCountElement
                    ])),
                    this.nextButton,
                    this.lastButton
                ]))
            ]))
        ])));
        pagerColumn.writeAttribute({colspan: "9"});
        

        //containerElm.appendChild(loadingAndTableDiv);
        //containerElm.appendChild(this.pagingDiv);

        //put this all into scrollable div
        var scrollDiv = $(Builder.node("div", { style: 'overflow:auto;overflow-y:hidden;' }));
        scrollDiv.appendChild(loadingAndTableDiv);
        //scrollDiv.appendChild(this.pagingDiv);

        containerElm.appendChild(scrollDiv);
    },
    
    //    <tfoot> 
//			<tr> 
//				<td colspan="10"> 
//					<div class="sortSettings"> 
//						<div class="perPage"> 
//							Antal pr. side
//							<select class="itemsPerPage"> 
//								<option>10</option> 
//								<option>20</option> 
//								<option>30</option> 
//							</select> 
//						</div> 
//						
//						<a href="#" class="navFirst" title="First">&nbsp;</a> 
//						<a href="#" class="navPrevious" title="Previous">&nbsp;</a> 
//						
//						<div class="pageNumber"> 
//							<input type="text" id="Text1" class="pageNumberInputStyle" /> 
//							af 10
//						</div> 
//						
//						<a href="#" class="navNext" title="Next">&nbsp;</a> 
//						<a href="#" class="navLast" title="Last">&nbsp;</a> 
//						
//					</div><!-- /sortSettings -->							
//				</td> 
//			</tr> 
//		</tfoot>


    _buildTable: function(rows) {
        this.rowData = $A(rows);
        var columns = this.columns;
        var columnNodes = [];        

        for (var c = 0; c < columns.length; ++c) {
            if (!columns[c]) {
                break;
            }
                
            var classname = columns[c].sortable ? "" : "nosort";

            if (c == columns.length - 1) { classname += " last"; }

            if (columns[c].columnName == this.sortColumn) {
                classname += (" sort_" + (this.sortAscending ? "asc" : "des"));
            }
            var columnProps = classname.length > 0 ? { className: classname} : {};

            var textSpan;
            var columnNode = $(Builder.node("th", columnProps, textSpan = $(Builder.node("span", columns[c].displayName))));
            var headerClass = columns[c].headerClass;
            if (headerClass !== null) { $(columnNode).addClassName(headerClass); }

            var theSortButton = columnNode;
            if (columns[c].toggler) {
                var toggler = columns[c].toggler;
                var toggleButton = $(WebTango.Buttons.link(Builder.node("img", { border: 0, alt: '', src: toggler.iconPath })));
                theSortButton = textSpan;
                if (toggler.tooltip) { toggleButton.setAttribute("title", toggler.tooltip); }
                toggleButton.observe("click", function() {
                    $(toggler.indices).each(function(idx) {
                        this._toggleColumn(idx);
                    }, this);
                } .bind(this));
                $(columnNode).insert({ top: toggleButton });
            }

            //make the node invisible in this hacky way because IE does not like style in builder attribs
            if (!columns[c].isVisible) { $(columnNode).toggle(); }

            if (columns[c].sortable) {
                theSortButton.addClassName("sortbutton");
                Event.observe(theSortButton, "click", this._onSortClick.bindAsEventListener(this, columns[c].columnName));
            }

            columnNodes.push(columnNode);
        }

        var thead =
        Builder.node("thead", {},
            Builder.node("tr", {}, columnNodes)
        );

        var rowNodes = [];
        for (var r = 0; r < rows.length; ++r) {
            var rowNode = this._buildRow(rows[r]);
            rowNodes.push(rowNode);
        }

        this.table = Builder.node("table", { cellpadding: 0, cellspacing: 0, className: 'productTable', id: this.id }, [
            thead
        ]);
        $(this.table).setStyle(this.tableStyle);
        //IE autogenerates the tbody when making the table, so we need to insert in that tbody rather than adding a second one
        if (this.table.tBodies.length === 0) {
            this.table.appendChild(Builder.node("tbody")); //build body for non-IE browsers
        }
        var rowCount = rowNodes.length;
        for (var r2 = 0; r2 < rowCount; ++r2) {
            this.table.tBodies[0].appendChild(rowNodes[r2]);
        }
        
        this.table.appendChild(this.tfoot);

        this.tableContainer.appendChild(this.table);

        //for unknown reasons, only sortable tables are striped automatically by tablekit
        //so here goes a manual call
        WebTango.Table.Rows.stripe(this.table);

        this.table.show();
        this._showTableOrEmptyPanel();
    },

    _showTableOrEmptyPanel: function() {
        if (this.rowCount === 0) {
            $(this.emptyPanel).show();
            $(this.tableContainer).hide();
        } else {
            $(this.emptyPanel).hide();
            $(this.tableContainer).show();
        }
    },

    _buildRow: function(row) {
        var cellNodes = [];
        var columns = this.columns;
        var columnCount = this.columns.length;

        for (var c = 0; c < columnCount; ++c) {
            if (!columns[c])
                break;
            var val;
            val = columns[c].renderCell(row, this);

            if (val === 0.0) { val = "0"; }
            if (Prototype.Browser.IE && !val) { val = Builder.node("span"); }

            var cellProps = {};
            if (columns[c].columnName == this.sortColumn) {
                cellProps.className = "sortcell";
            }

            var td = Builder.node("td", cellProps, val);

            var cellClass = columns[c].cellClass;
            if (cellClass !== null) { $(td).addClassName(cellClass); }

            //make the node invisible in this hacky way because IE does not like style in builder attribs
            if (!this.columns[c].isVisible) { $(td).toggle(); }
            cellNodes.push(td);
        }

        return Builder.node("tr", { id: this.getRowId(row.OID), className: "standard" }, cellNodes);
    },

    getRowId: function(OID) {
        return this.id + "_row_" + OID;
    },

    _updateCounts: function() {
        this.rowCountElement.innerHTML = "" + this.rowCount;
        this.currentPageElement.value = "" + (this.pageIndex + 1);
        this.pageCountElement.innerHTML = "" + this.pageCount;

        this.lastButton.disabled = this.nextButton.disabled = (this.pageIndex == this.pageCount - 1);
        this.firstButton.disabled = this.previousButton.disabled = (this.pageIndex === 0);
    },

    _onSortClick: function(eventTarget, sortColumnName) {
        if (sortColumnName == this.sortColumn) {
            this.sortAscending = !this.sortAscending;
        } else {
            this.sortAscending = true;
            this.sortColumn = sortColumnName;
        }

        this._doPaging();
    },

    _onPageButtonClick: function(eventTarget, pageMode) {
        switch (pageMode) {
            case WTPagingMode.First:
                this.pageIndex = 0;
                break;
            case WTPagingMode.Previous:
                this.pageIndex--;
                break;
            case WTPagingMode.Next:
                this.pageIndex++;
                break;
            case WTPagingMode.Last:
                this.pageIndex = this.pageCount - 1;
                break;
        }

        this._doPaging();
    },

    _doPaging: function() {
        //new Effect.Appear(this.loadingPanel, {queue:{position:'end', scope: this.table.id + 'queue'},duration: 0.4});
        $(this.loadingPanel).show();

        var fixedSearcher = this.searchFilter
        if (this.searcherPreSerialization) {
            fixedSearcher = this.searcherPreSerialization(this.searchFilter);
        }

        this.webService.GetPage(
            "/cms.ashx/produkter",
            this.pageSize,
            this.pageIndex,
            this.sortColumn,
            this.sortAscending,
            fixedSearcher,
            this._onPagingSucceeded.bind(this),
            this._onPagingFailed.bind(this)
        );

        this.lastSearchFilter = this.searchFilter;
    },

    // this function is called when the paging web service call returns with success
    _onPagingSucceeded: function(searchResult) {
        //new Effect.Fade(this.loadingPanel, {queue:{position:'end', scope: this.table.id + 'queue'},duration: 0.4});
        $(this.loadingPanel).hide();

        //clear container
        $(this.tableContainer).immediateDescendants().each(Element.remove);
        //new Effect.Fade(this.tableContainer, {queue:{position:'end', scope: this.table.id + 'queue'},duration: 0.4});
        //destroy previous tablekit instance
        WebTango.Table.unregister(this.table);
        
        this.rowCount = searchResult.TotalCount;
        this.pageCount = Math.max(1, Math.ceil(this.rowCount / this.pageSize));

        this._buildTable(searchResult.Rows);

        this._updateCounts();

        this._updatePagerVisibility();

        if (this.onAfterPaging) { this.onAfterPaging(searchResult); }
        
        $('containerDiv').show();
    },

    // this function is called when the paging web service call returns with an error
    _onPagingFailed: function() {
        //WebTango.Feedback.negative("Paging failed");
    },
    _updatePagerVisibility: function() {
        //Set visibility of the pager based on pageCount;
        if (this.pageCount < 2 && !this.alwaysShowFooter) {
            this.pagingDiv.hide();
            //we have to change the bottom margin of the table element based on whether the pager
            //is shown or not
            this.tableStyle = {};
            this.pagingDiv.setStyle({});
        } else {
            this.pagingDiv.show();
            this.tableStyle = { marginBottom: "0px" };
            this.pagingDiv.setStyle({ marginBottom: "20px" });
        }
    }
});

/* -------------------------------------------------------------------------------------*/
/* -------------------------------------------------------------------------------------*/
/* WebTango column class                                                                */
/* TODO: change so it can take a bool as parameter for determining where to get the     */
/* ObjectType                                                                           */
/* -------------------------------------------------------------------------------------*/
/* -------------------------------------------------------------------------------------*/

WebTango.Table.Column = Class.create({
    initialize : function(columnName, options) {
        options = options || {};
        this.columnName = columnName;
        options.displayName = options.displayName || columnName; //columns have display names identical to their internal name by default
        options = Object.extend(Object.clone(WebTango.Table.Column.options), options || {});
        for (propName in options) {
            this[propName] = options[propName];
        }
    }
});

WebTango.Table.Column.options = {
    sortable : true, 
    isVisible : true, 
    cellClass : null, 
    headerClass : null, 
    cellFormat : null,
    toggler: null,
    renderCell: DefaultCellRenderer
};

/* static table methods */

Object.extend(WebTango.Table, {
	
	getBodyRows : function(table) {
		table = $(table);
		var id = table.id;
		if(!WebTango.Table.rows[id]) {
			WebTango.Table.rows[id] = (table.tHead && table.tHead.rows.length > 0) ? $A(table.tBodies[0].rows) : $A(table.rows).without(table.rows[0]);
		}
		return WebTango.Table.rows[id];
	},
	addRow : function(table, rowdata, allowEdit) {
	    table = $(table);
	    
	    var id = table.id;
		var rows = WebTango.Table.rows[id];
		if(rows) {
		
	        var rowHtml = "<tr>";
    	    
	        rowdata.each(
	            function(item) { 
	                if (item.length === 0) { item = "&nbsp;"; }
	                if (allowEdit) {
	                    rowHtml += "<td>" + item + "</td>";
	                } else {
	                    rowHtml += "<td class='" + WebTango.Table.options.noEditClass + "'>" + item + "</td>";
	                }   
	            }
	        );
	        rowHtml += "</tr>";
	        var unused = new Insertion.After(table.firstDescendant().next().firstDescendant(), rowHtml);
	        var newRow = table.firstDescendant().next().firstDescendant().next();
    	    var rowsAfter = [];
    	    rowsAfter[0] = newRow;
    	    rowsAfter = rowsAfter.concat(rows);
    	    rowsAfter = $A(rowsAfter);
    	    WebTango.Table.rows[id] = rowsAfter;
		}
	},
	
	removeRow : function(table, row) {
	    table = $(table);
		//sender = $(sender);
		//var row = sender.up('tr');
		var idx = WebTango.Table.getRowIndex(row);
		
		var id = table.id;
		var rows = WebTango.Table.getBodyRows(id);
		if(rows !== undefined) {
		    var rowToRemove = rows[idx];
		    WebTango.Table.rows[id] = rows.without(rowToRemove);
		    $(rowToRemove).remove();
		    WebTango.Table.Rows.stripe(table);
		}
	},
	
	getHeaderCells : function(table, cell) {
		if(!table) { table = $(cell).up('table'); }
		var id = table.id;
		if(!WebTango.Table.heads[id]) {
			WebTango.Table.heads[id] = $A((table.tHead && table.tHead.rows.length > 0) ? table.tHead.rows[table.tHead.rows.length-1].cells : table.rows[0].cells);
		}
		return WebTango.Table.heads[id];
	},
	getCellIndex : function(cell) {
		return $A(cell.parentNode.cells).indexOf(cell);
	},
	getRowIndex : function(row) {
		return $A(row.parentNode.rows).indexOf(row);
	},
	getCellText : function(cell, refresh) {
		if(!cell) { return ""; }
		WebTango.Table.registerCell(cell);
		var data = WebTango.Table.cells[cell.id];
		if(refresh || data.refresh || !data.textContent) {
			data.textContent = cell.textContent ? cell.textContent : cell.innerText;
			data.refresh = false;
		}
		return data.textContent;
	},
	register : function(table, options) {
		if(!table.id) {
			WebTango.Table._tblcount += 1;
			table.id = "tablekit-table-" + WebTango.Table._tblcount;
		}
		var id = table.id;
		WebTango.Table.tables[id] = WebTango.Table.tables[id] ? Object.extend(WebTango.Table.tables[id], options || {}) : Object.extend({sortable:false,resizable:false,editable:false}, options || {});
	},
	
	/* added by JH */
	unregister : function(table) {
	    var tables = $A(WebTango.Table.tables); 
	    WebTango.Table.tables = tables.without(table);
	    
	    var ourrows = WebTango.Table.rows[table];
	    var allrows = $A(WebTango.Table.rows);
	    
	    WebTango.Table.rows = allrows.without(ourrows);
	},
	
	registerCell : function(cell) {
		if(!cell.id) {
			WebTango.Table._cellcount += 1;
			cell.id = "tablekit-cell-" + WebTango.Table._cellcount;
		}
		if(!WebTango.Table.cells[cell.id]) {
			WebTango.Table.cells[cell.id] = {textContent : '', htmlContent : '', active : false};
		}
	},
	isSortable : function(table) {
		return WebTango.Table.tables[table.id] ? WebTango.Table.tables[table.id].sortable : false;
	},
	isResizable : function(table) {
		return WebTango.Table.tables[table.id] ? WebTango.Table.tables[table.id].resizable : false;
	},
	isEditable : function(table) {
		return WebTango.Table.tables[table.id] ? WebTango.Table.tables[table.id].editable : false;
	},
	setup : function(o) {
		Object.extend(WebTango.Table.options, o || {} );
	},
	option : function(s, id, o1, o2) {
		o1 = o1 || WebTango.Table.options;
		o2 = o2 || (id ? (WebTango.Table.tables[id] ? WebTango.Table.tables[id] : {}) : {});
		var key = id + s;
		if(!WebTango.Table._opcache[key]){
			WebTango.Table._opcache[key] = $A($w(s)).inject([],function(a,v){
				a.push(a[v] = o2[v] || o1[v]);
				return a;
			});
		}
		return WebTango.Table._opcache[key];
	},
	e : function(event) {
		return event || window.event;
	},
	tables : {},
	_opcache : {},
	cells : {},
	rows : {},
	heads : {},
	options : {
		autoLoad : true,
		stripe : true,
		sortable : true,
		resizable : true,
		editable : true,
		rowEvenClass : 'standard',
		rowOddClass: 'alternative',
		sortableSelector : ['table.sortable'],
		columnClass : 'sortcol',
		descendingClass : 'sortdesc',
		ascendingClass : 'sortasc',
		noSortClass : 'nosort',
		sortFirstAscendingClass : 'sortfirstasc',
		sortFirstDecendingClass : 'sortfirstdesc',
		resizableSelector : ['table.resizable'],
		minWidth : 10,
		showHandle : true,
		resizeOnHandleClass : 'resize-handle-active',
		editableSelector : ['table.editable'],
		formClassName : 'editable-cell-form',
		noEditClass : 'noedit',
		editAjaxURI : '/',
		editAjaxOptions : {},
		columns : [ new WebTango.Table.Column("DisplayName", "Name", true) ],
		typeName : "item",
		pageSize : 50,
		sortAscending : true,
		initialSort : null,
		initialSearchFilter : { __type : "WebTango.Json.Search.Searcher" },
		alwaysShowFooter : true,
		nameField : 'DisplayName',
		onAfterPaging : null,
		onRowDeleted : null
	},
	_tblcount : 0,
	_cellcount : 0,
	load : function() {
		if(WebTango.Table.options.autoLoad) {
			if(WebTango.Table.options.sortable) {
				$A(WebTango.Table.options.sortableSelector).each(function(s){
					$$(s).each(function(t) {
						WebTango.Table.Sortable.init(t);
					});
				});
			}
			if(WebTango.Table.options.resizable) {
				$A(WebTango.Table.options.resizableSelector).each(function(s){
					$$(s).each(function(t) {
						WebTango.Table.Resizable.init(t);
					});
				});
			}
			if(WebTango.Table.options.editable) {
				$A(WebTango.Table.options.editableSelector).each(function(s){
					$$(s).each(function(t) {
						WebTango.Table.Editable.init(t);
					});
				});
			}
		}
	}
});

WebTango.Table.Rows = {
	stripe : function(table) {
		var rows = WebTango.Table.getBodyRows(table);
		rows.each(function(r,i) {
			WebTango.Table.Rows.addStripeClass(table,r,i);
		});
	},
	addStripeClass : function(t,r,i) {
		t = t || r.up('table');
		var op = WebTango.Table.option('rowEvenClass rowOddClass', t.id);
		var css = ((i+1)%2 === 0 ? op[0] : op[1]);
		// using prototype's assClassName/RemoveClassName was not efficient for large tables, hence:
		var cn = r.className.split(/\s+/);
		var newCn = [];
		for(var x = 0, l = cn.length; x < l; x += 1) {
			if(cn[x] !== op[0] && cn[x] !== op[1]) { newCn.push(cn[x]); }
		}
		newCn.push(css);
		r.className = newCn.join(" ");
	}
};

WebTango.Table.Resizable = {
	init : function(elm, options){
		var table = $(elm);
		if(table.tagName !== "TABLE") {return;}
		WebTango.Table.register(table,Object.extend(options || {},{resizable:true}));		 
		var cells = WebTango.Table.getHeaderCells(table);
		cells.each(function(c){
			c = $(c);
			Event.observe(c, 'mouseover', WebTango.Table.Resizable.initDetect);
			Event.observe(c, 'mouseout', WebTango.Table.Resizable.killDetect);
		});
	},
	resize : function(table, index, w) {
		var cell;
		if(typeof index === 'number') {
			if(!table || (table.tagName && table.tagName !== "TABLE")) {return;}
			table = $(table);
			index = Math.min(table.rows[0].cells.length, index);
			index = Math.max(1, index);
			index -= 1;
			cell = (table.tHead && table.tHead.rows.length > 0) ? $(table.tHead.rows[table.tHead.rows.length-1].cells[index]) : $(table.rows[0].cells[index]);
		} else {
			cell = $(index);
			table = table ? $(table) : cell.up('table');
			index = WebTango.Table.getCellIndex(cell);
		}
		var pad = parseInt(cell.getStyle('paddingLeft'),10) + parseInt(cell.getStyle('paddingRight'),10);
		w = Math.max(w-pad, WebTango.Table.option('minWidth', table.id)[0]);
		
		cell.setStyle({'width' : w + 'px'});
	},
	initDetect : function(e) {
		e = WebTango.Table.e(e);
		var cell = Event.element(e);
		Event.observe(cell, 'mousemove', WebTango.Table.Resizable.detectHandle);
		Event.observe(cell, 'mousedown', WebTango.Table.Resizable.startResize);
	},
	detectHandle : function(e) {
		e = WebTango.Table.e(e);
		var cell = Event.element(e);
  		if(WebTango.Table.Resizable.pointerPos(cell,Event.pointerX(e),Event.pointerY(e))){
  			cell.addClassName(WebTango.Table.option('resizeOnHandleClass', cell.up('table').id)[0]);
  			WebTango.Table.Resizable._onHandle = true;
  		} else {
  			cell.removeClassName(WebTango.Table.option('resizeOnHandleClass', cell.up('table').id)[0]);
  			WebTango.Table.Resizable._onHandle = false;
  		}
	},
	killDetect : function(e) {
		e = WebTango.Table.e(e);
		WebTango.Table.Resizable._onHandle = false;
		var cell = Event.element(e);
		Event.stopObserving(cell, 'mousemove', WebTango.Table.Resizable.detectHandle);
		Event.stopObserving(cell, 'mousedown', WebTango.Table.Resizable.startResize);
		cell.removeClassName(WebTango.Table.option('resizeOnHandleClass', cell.up('table').id)[0]);
	},
	startResize : function(e) {
		e = WebTango.Table.e(e);
		if(!WebTango.Table.Resizable._onHandle) {return;}
		var cell = Event.element(e);
		Event.stopObserving(cell, 'mousemove', WebTango.Table.Resizable.detectHandle);
		Event.stopObserving(cell, 'mousedown', WebTango.Table.Resizable.startResize);
		Event.stopObserving(cell, 'mouseout', WebTango.Table.Resizable.killDetect);
		WebTango.Table.Resizable._cell = cell;
		var table = cell.up('table');
		WebTango.Table.Resizable._tbl = table;
		if(WebTango.Table.option('showHandle', table.id)[0]) {
			WebTango.Table.Resizable._handle = $(document.createElement('div')).addClassName('resize-handle').setStyle({
				'top' : Position.cumulativeOffset(cell)[1] + 'px',
				'left' : Event.pointerX(e) + 'px',
				'height' : table.getDimensions().height + 'px'
			});
			document.body.appendChild(WebTango.Table.Resizable._handle);
		}
		Event.observe(document, 'mousemove', WebTango.Table.Resizable.drag);
		Event.observe(document, 'mouseup', WebTango.Table.Resizable.endResize);
		Event.stop(e);
	},
	endResize : function(e) {
		e = WebTango.Table.e(e);
		var cell = WebTango.Table.Resizable._cell;
		WebTango.Table.Resizable.resize(null, cell, (Event.pointerX(e) - Position.cumulativeOffset(cell)[0]));
		Event.stopObserving(document, 'mousemove', WebTango.Table.Resizable.drag);
		Event.stopObserving(document, 'mouseup', WebTango.Table.Resizable.endResize);
		if(WebTango.Table.option('showHandle', WebTango.Table.Resizable._tbl.id)[0]) {
			$$('div.resize-handle').each(function(elm){
				document.body.removeChild(elm);
			});
		}
		Event.observe(cell, 'mouseout', WebTango.Table.Resizable.killDetect);
		WebTango.Table.Resizable._tbl = WebTango.Table.Resizable._handle = WebTango.Table.Resizable._cell = null;
		Event.stop(e);
	},
	drag : function(e) {
		e = WebTango.Table.e(e);
		if(WebTango.Table.Resizable._handle === null) {
			try {
				WebTango.Table.Resizable.resize(WebTango.Table.Resizable._tbl, WebTango.Table.Resizable._cell, (Event.pointerX(e) - Position.cumulativeOffset(WebTango.Table.Resizable._cell)[0]));
			} catch(ex) {}
		} else {
			WebTango.Table.Resizable._handle.setStyle({'left' : Event.pointerX(e) + 'px'});
		}
		return false;
	},
	pointerPos : function(element, x, y) {
    	var offset = Position.cumulativeOffset(element);
	    return (y >= offset[1] &&
	            y <  offset[1] + element.offsetHeight &&
	            x >= offset[0] + element.offsetWidth - 5 &&
	            x <  offset[0] + element.offsetWidth);
  	},
	_onHandle : false,
	_cell : null,
	_tbl : null,
	_handle : null
};

if(window.FastInit) {
	FastInit.addOnLoad(WebTango.Table.load);
} else {
	Event.observe(window, 'load', WebTango.Table.load);
}

WebTango.Searcher = Class.create({});
Object.extend(WebTango.Searcher,{
    parseFromUrl: function(type, prefix) {
	    var searcher = {
	        "__type" : type
	    };
	    var anchor = window.location.hash;
	    anchor = anchor.substr(1,anchor.length-1); //remove # char
	    if (prefix) {
	        anchor = prefix + "&" + anchor;
	    }
	    var anchorParts = anchor.split("&");
	    for (var i=0;i<anchorParts.length;++i) {
	        var part = anchorParts[i];
	        var nameVal = part.split("=");
	        if (nameVal.length > 1) {
	            searcher[nameVal[0]] = nameVal[1];
	        }
	    }
	    return searcher;
	},
    toUrlString: function(searcher) {
        var result = "#";
        for (var propName in searcher) {
            if (propName == "__type") { continue; }
            var propVal = searcher[propName];
            //we define some defaults in order to keep the string as short as possible
            //all falsy values are considered default (e.g. "", false, 0)
            if (!propVal) { continue; }
            //the empty Guid is the default too
            if (propVal == WebTango.Guid.Empty) { continue; }
            result += propName +"="+ propVal + "&"; 
        }
        //trim trailing &
        if (result.length > 1) {
            result = result.substr(0,result.length-1);
        }
        return result;
    }
});

// this base class can be used as a hidden element in order to bind a property permanently to
// a fixed value - e.g. the OID of the browsed FormTemplate when searching for SubmittedForms
WebTango.Table.SearchWidgetElement = Class.create({
    initialize: function(options) {
        this._options = options;
    },
    onSearcherUpdated: function() {},
    render: function(container) {},
    setParent: function(parent) {
        this._parent = parent;
    }
});

WebTango.Table.AppleSearchWidgetElement = Class.create(WebTango.Table.SearchWidgetElement, {
    onSearcherUpdated: function() {
        this._inputField.value = this._parent._searcher[this._options.boundProperty] || "";
    },
    onValueChanged: function() {
        this._parent._searcher[this._options.boundProperty] = $F(this._inputField);
    },

    render: function(container) {
        var inlineClearButton, searchButton, clearButton;
        var widget = Builder.node("div", [
            Builder.node("div", {id:"applesearch"}, [
                Builder.node("span", {className:"sbox_l"}),
                Builder.node("span", {className:"sbox"},
                    this._inputField = $(Builder.node("input", { id:"srch_fld", type:"search", placeholder:"Search..."}))
                ),
                inlineClearButton = $(Builder.node("span", {className:"sbox_r"}))
	        ]),
	        searchButton = $(WebTango.Buttons.search()),
	        Builder.node("div", {className:"right_of_button"}, [
	            "or ", 
	            clearButton = $(WebTango.Buttons.link("Clear", false))
	        ]),
	        Builder.node("div", {className:"clearboth"})
	    ]);
	    this._inputField.observe("keyup", function() { applesearch.onChange(this._inputField.identify(), inlineClearButton.identify()); }.bind(this));
	    
	    WebTango.Events.addEnterHandler(this._inputField, this._parent.search.bind(this._parent));
	    searchButton.observe("click", this._parent.search.bind(this._parent));
	    this._inputField.observe("keyup", this.onValueChanged.bind(this));
	    clearButton.observe("click", this._parent.clearSearch.bind(this._parent));
	    inlineClearButton.observe("click", this._parent.clearSearch.bind(this._parent));
	    
	    container.appendChild(widget);
    }
});

WebTango.Table.DropDownSearchWidgetElement = Class.create(WebTango.Table.SearchWidgetElement, {
    onSearcherUpdated: function() {
        WebTango.DomUtils.setDropDownValue(this._inputField, this._parent._searcher[this._options.boundProperty] || this._options.defaultValue);
    },
    onValueChanged: function() {
        this._parent._searcher[this._options.boundProperty] = $F(this._inputField);
        if (this._options.autoSearch) {
            this._parent.search();
        }
    },
    render: function(container) {
        var optionElms = this._options.data.map(function (pair) {
            return Builder.node("option", {value:pair.key}, pair.value);
        });
        var widget = Builder.node("div", {className:"content"}, [
            Builder.node("h3", this._options.text),
            this._inputField = Builder.node("select", optionElms)
	    ]);
	    WebTango.Events.addEnterHandler(this._inputField, this._parent.search.bind(this._parent));
	    this._inputField.observe("change", this.onValueChanged.bind(this));
	    
	    container.appendChild(widget);
    }
});

WebTango.Table.ButtonListSearchWidgetElement = Class.create(WebTango.Table.SearchWidgetElement, {
    onSearcherUpdated: function() {
        var newValue = this._parent._searcher[this._options.boundProperty];
        var idx = -1;
        
        var compare = Object.isArray(newValue) ? 
            function(o1, o2) {
                if (o1.length !== o2.length) return false;
                
                for (var i=0;i<o1.length;i++) {
                    if (o1[i] !== o2[i]) return false;
                }
                return true;
            } 
        :
            function(o1, o2) { return o1 === o2; };
        
        for (var i=0;i<this._options.buttons.length;i++) {
            if (compare(this._options.buttons[i].argument,newValue)) {
                idx = i;
                break;
            }
        }
        if (idx != -1) {
            this._updateSelection(idx);
        }
    },
    render: function(container) {
        var i = 0;
        var buttons = this._options.buttons.map(function (button) {
            var buttonLink;
            var listItem = Builder.node("li",
                buttonLink = $(Builder.node("a", {href:"#", onclick:"return false;", className:button.className||""}, button.text))
            );
            buttonLink.observe("click", function(idx) {
                this._updateSelection(idx);
                this._parent._searcher[this._options.boundProperty] = this._options.buttons[idx].argument;
                this._parent.search();
            }.bind(this, i++));

            return listItem;
        }, this);
        
        var widget =
            Builder.node("div", {className:"content"}, 
                this._buttonList = Builder.node("ul", {id:"quicksort"}, buttons)
            );
        container.appendChild(widget);
    },
    _updateSelection: function(idx) {
        $(this._buttonList).getElementsBySelector("a").each( function(otherButton) {
            otherButton.removeClassName("current");
        });
        var buttonLink = this._buttonList.down("a",idx);
        if (buttonLink) { $(buttonLink).addClassName("current"); }
    }
});

WebTango.Table.SearchWidget = Class.create({
    initialize: function(options) {
        this._options = options;
        this._options.elements.invoke("setParent", this);
        
        this._boundPropertiesOfElements = this._options.elements.map(function (element) {
            return element._options.boundProperty;
        }).uniq();
        this._searcher = {};
        this.render();
        WebTango.Table.SearchPoller.getInstance(this._options.table);
        this.onSearcherUpdated(this._options.table.getSearchFilter());
    },
    clearSearch: function() {
        this._options.table.clearSearch();
    },
    onSearcherUpdated: function(newSearcher) {
        this._searcher = newSearcher;
        
        //we only wish to define properties on the searcher that are bound to one or more of our elements - delete the rest
        for (var propName in this._searcher) {
            if (propName != "__type" && !this._boundPropertiesOfElements.find(function (boundProp) { return boundProp === propName; })) {
                delete this._searcher[propName];
            }
        }
        this._options.elements.invoke("onSearcherUpdated");
    },
    render: function() {
        var sideBarElement = $(Builder.node("div", {className:"sidebarelement"}, [
            Builder.node("h2", this._options.title || "Search")
        ]));
        if (this._options.elementClass) { sideBarElement.addClassName(this._options.elementClass); }
        
        if (this._options.text) {
            sideBarElement.appendChild(            
                Builder.node("div", {className:"content"}, [
                    this._options.text,
                    Builder.node("br")
                ])
            );
        }
        
        this._options.container.appendChild(sideBarElement);
        
        this._options.elements.each(function (elm) {
            elm.render(sideBarElement);
            elm.onSearcherUpdated();
        }, this);
        
        
    },
    search: function() {
        var newHash = WebTango.Searcher.toUrlString(this._searcher);
        WebTango.Table.SearchPoller.getInstance(this._options.table).setActiveSearchWidget(this);
        window.location.href = newHash;
        //this._options.table.search(this._searcher, this);
    }
});

WebTango.Table.SearchPoller = Class.create({
    initialize: function(table) {
        this.table = table;
        this._oldHash = null;
        
        var dummy = new PeriodicalExecuter(function(pe) {
            if (window.location.hash !== this._oldHash) { 
                this._oldHash = window.location.hash;
                this.table.search(WebTango.Searcher.parseFromUrl(this.table.searcherType, this.table.urlAnchorPrefix), this._activeSearchWidget); 
            }
        }.bind(this), 0.2);
    },
    setActiveSearchWidget: function(widget) {
        this._activeSearchWidget = widget;
    }
});

WebTango.Table.SearchPoller.getInstance = function(table) {
    if (!WebTango.Table.SearchPoller._instance) {
        WebTango.Table.SearchPoller._instance = new WebTango.Table.SearchPoller(table);
    }
    return WebTango.Table.SearchPoller._instance;
};
WebTango.notifyScriptManager();
