/* login functinality */
jQuery(document).ready(function(){
    jQuery("input.login-submit").click(function(event){
        var form = jQuery(this).parents("form.loginForm").eq(0);
        if (!form.attr("action").indexOf("https://") == 0) {
            jQuery("form.loginForm").removeClass('currentLoginForm');
            form.addClass('currentLoginForm');
            if (jQuery.browser.msie) {
                // javascript indirection needed to allow password autocomplete in ie
                form.attr("action", "javascript: safeLoginSubmit();");
            }
            else {
                prepareLoginFormForSubmit(form);
            }
        }
    });
});

function prepareLoginFormForSubmit(form){
    form.attr("action", "/login");
    
    var login = form.find(".login-login").eq(0).val().toLowerCase();
    var password = hex_md4(form.find(".login-password").eq(0).val());
    var nonce = form.find(".login-nonce").eq(0).val();
    
    form.find(".login-password").eq(0).val("");
    form.find(".login-nonce").eq(0).val("");
    form.find(".login-digest").eq(0).val(MD5(login + password + nonce));
}

function safeLoginSubmit(){
    var form = jQuery("form.loginForm.currentLoginForm").eq(0);
    prepareLoginFormForSubmit(form);
    form.submit();
}

/* search form */

function SearchForm(id){

    var tagFilterControl = null;
    var controlIsPressed = false;
    
    jQuery('*').keydown(function(event){
        if (event.keyCode == 17) {
            controlIsPressed = true;
        }
    });
    jQuery('*').keyup(function(event){
        if (event.keyCode == 17) {
            controlIsPressed = false;
        }
    });
    
    this.bindTagDragAndDropEvents = function(){
        makeTagsDraggable(jQuery('#' + id + ' .searchHit .tag.draggable'));
    };
    
    this.setTagFilterControl = function(control){
        tagFilterControl = control;
    };
	
	this.submit = function(){
		jQuery('#' + id).submit();
	};
    
    
    this.makeTagsClickable = function(jQueryObjectSet){
        jQueryObjectSet.click(function(event){
            if (tagFilterControl != null) {
                if (controlIsPressed) {
                    tagFilterControl.addTagMustNot(jQuery(this).text());
                }
                else {
                    tagFilterControl.addTagMust(jQuery(this).text());
                }
                event.stopPropagation();
                event.preventDefault();
            }
        });
    };
}

function attachQuickSearchAutocomplete(inputElement, formElement){
    jQuery("body").append('<div id="quicksearch-menu-wrapper"></div>');
    inputElement.triciaautocomplete({
        minLength: 1,
        appendTo: '#quicksearch-menu-wrapper',
        delay: 150,
        source: function(request, response){
            jQuery.ajax({
                url: "/functions/findAsset",
                dataType: "json",
                data: {
                    query: request.term,
                    autocompleteUrl: true,
                    assetUid: window.location.pathname,
                    extractionEnabled: true
                },
                success: function(data){
                    if (!inputElement.data('autocompleteused') && typeof trackQuickSearchUsage == 'function') {
                        trackQuickSearchUsage();
                        inputElement.data('autocompleteused', true);
                    }
                    response(data, request.term);
                }
            });
        },
        focus: function(event, ui){
            return false;
        },
        select: function(event, ui){
            if (ui.item.extract) {
				if(confirm("Are you sure you want to create a new page?")) {
	                jQuery.ajax({
	                    type: 'POST',
	                    dataType: 'json',
	                    url: '/extractWikiPage?empty=true',
	                    data: {
	                        value: ui.item.label,
	                        assetUid: window.location.pathname
	                    },
	                    success: function(data){
	                        var messageObject = jQuery(data.message);
	                        if (data.success) {
	                            handleSelect(data.index, data.editUrl);
	                        }
	                        jQuery("#wrapper").find('.tricia-messages:first').replaceWith(messageObject);
	                        messageObject.delay(2000).fadeOut(1000);
	                    }
	                });
				}
            }
            else {
                handleSelect(ui.item.index, ui.item.url);
            }
        }
    }).data('triciaautocomplete')._renderItem = function(ul, item){
        return $("<li></li>").data("item.autocomplete", item).append(item.html).appendTo(ul);
    };
    
    addHandlerForAutocompleteSubmitEvent(inputElement, function(event){
        if (typeof trackQuickSearchSubmit == 'function') {
            event.preventDefault();
            trackQuickSearchSubmit(inputElement.data("triciaautocomplete").term, function(){
                formElement.submit();
            });
        }
    });
    
    function handleSelect(index, url){
        if (typeof trackQuickSearchSelect == 'function') {
            trackQuickSearchSelect(index, inputElement.data("triciaautocomplete").term, function(){
                goToUrl(url);
            });
        }
        else {
            goToUrl(url);
        }
    }
}

function addHandlerForAutocompleteSubmitEvent(inputElement, handler){
    var lastSelectEvent = null; // needed to avoid duplicate selection of entries (one with autocomplete select event and one with ENTER)
    inputElement.bind("triciaautocompleteselect", function(event, ui){
        lastSelectEvent = getOriginalEvent(event);
    });
    
    inputElement.keydown(function(event){
        var keyCode = $.ui.keyCode;
        if ((event.keyCode == keyCode.ENTER || event.keyCode == keyCode.NUMPAD_ENTER) &&
        getOriginalEvent(event) != lastSelectEvent) {
            handler(event);
        }
    });
}

function getOriginalEvent(event){
    if (event.originalEvent !== undefined) {
        return getOriginalEvent(event.originalEvent);
    }
    else {
        return event;
    }
}

function attachTagAutocomplete(inputElement, selectHandler, mode, spaceUrl, appendTo, newTagOption){
    if (typeof mode == 'undefined') {
        mode = "";
    }
    
    if (typeof appendTo == 'undefined') {
        appendTo = "body";
    }
    
    if (typeof newTagOption == 'undefined') {
        newTagOption = false;
    }
    
    var lastSelectEvent = null;
    
    inputElement.triciaautocomplete({
        minLength: 1,
        delay: 100,
        source: function(request, response){
            jQuery.ajax({
                url: "/functions/findTag",
                dataType: "json",
                data: {
                    query: request.term,
                    mode: mode,
                    spaceUrl: spaceUrl,
                    newTagOption: newTagOption
                },
                success: function(data){
                    response(data, request.term);
                }
            });
        },
        open: function(event, ui){
            if (newTagOption) {
                inputElement.data("triciaautocomplete").menu.next(event);
            }
        },
        select: function(event, ui){
            lastSelectEvent = getOriginalEvent(event);
            if (newTagOption && getOriginalEvent(event).keyCode == $.ui.keyCode.TAB) {
                getOriginalEvent(event).preventDefault();
            }
            return selectHandler(ui.item.value, lastSelectEvent);
        },
        appendTo: appendTo
    }).data("triciaautocomplete")._renderItem = function(ul, item){
        return $("<li></li>").data("item.autocomplete", item).append(item.html).appendTo(ul);
    };
    
    inputElement.keydown(function(event){
        var keyCode = $.ui.keyCode;
        
        if ((event.keyCode == keyCode.ENTER || event.keyCode == keyCode.NUMPAD_ENTER) &&
        getOriginalEvent(event) != lastSelectEvent) {
            event.preventDefault(); // no form submit
            selectHandler(inputElement.val());
            inputElement.data("triciaautocomplete").close();
        }
    });
}

function attachAttributeNameAutocomplete(inputElement){
    if (inputElement.length > 0) {
        inputElement.triciaautocomplete({
            minLength: 1,
            close: function(event, ui){
                //prevent overlay dialog is closed on esc 
                if (event.keyCode == 27) {
                    event.stopPropagation();
                }
            },
            source: function(request, response){
                jQuery.ajax({
                    url: "/functions/findAttributeName",
                    dataType: "json",
                    data: {
                        query: request.term
                    },
                    success: function(data){
                        response(data, request.term);
                    }
                });
            }
        }).data("triciaautocomplete")._renderItem = function(ul, item){
            return $("<li></li>").data("item.autocomplete", item).append(item.html).appendTo(ul);
        };
    }
}

/* tag based search result table */

function updateTableCell(cellId, newValue, oldValue, finishedHandler){
    if (newValue != oldValue) {
        var oldTags = oldValue.split(',');
        var newTags = newValue.split(',');
        removeTagsRecursively(getAssetIdFromCellId(cellId), getColumnNameFromCellId(cellId), oldTags, '', function(){
            addTagsRecursively(getAssetIdFromCellId(cellId), getColumnNameFromCellId(cellId), newTags, '', function(){
                finishedHandler();
            });
        });
    }
    else {
        finishedHandler();
    }
}

function undoServerSideIdEscaping(id){
    return id.replace('_', '/');
}

function removeTagsRecursively(assetId, prefix, remainingValues, mode, finishedHandler){
    if (remainingValues.length > 0) {
        var currentValue = remainingValues.shift();
        
        if (jQuery.trim(currentValue) == "") {
            removeTagsRecursively(assetId, prefix, remainingValues, mode, finishedHandler);
        }
        else {
            jQuery.ajax({
                type: "POST",
                url: "/functions/removeTagFromAsset",
                data: {
                    "assetId": undoServerSideIdEscaping(assetId),
                    "tag": (prefix != null ? prefix + ":" : "") + jQuery.trim(currentValue),
                    "mode": mode
                },
                success: function(msg){
                    if (msg == "success") {
                        removeTagsRecursively(assetId, prefix, remainingValues, mode, finishedHandler);
                    }
                    else {
                        alert('tag could not be removed');
                    }
                },
                error: function(XMLHttpRequest, textStatus, errorThrown){
                    alert('The server is unavailable. A tag could not be removed.');
                }
            });
        }
    }
    else {
        finishedHandler();
    }
}

function addTagsRecursively(assetId, prefix, remainingValues, mode, finishedHandler){
    if (remainingValues.length > 0) {
        var currentValue = remainingValues.shift();
        
        if (jQuery.trim(currentValue) == "") {
            addTagsRecursively(assetId, prefix, remainingValues, mode, finishedHandler);
        }
        else {
            jQuery.ajax({
                type: "POST",
                url: "/functions/addTagToAsset",
                data: {
                    "assetId": undoServerSideIdEscaping(assetId),
                    "tag": (prefix != null ? prefix + ":" : "") + jQuery.trim(currentValue),
                    "mode": mode
                },
                success: function(msg){
                    if (msg == "success") {
                        addTagsRecursively(assetId, prefix, remainingValues, mode, finishedHandler);
                    }
                    else {
                        alert('tag could not be added: ' + msg);
                    }
                },
                error: function(XMLHttpRequest, textStatus, errorThrown){
                    alert('The server is unavailable. A tag could not be added.');
                }
            });
        }
    }
    else {
        finishedHandler();
    }
}

function getAssetIdFromCellId(cellId){
    var firstDashPosition = cellId.indexOf('-');
    var secondPart = cellId.substring(firstDashPosition + 1);
    return secondPart.substring(0, secondPart.indexOf('-'));
}

function getColumnNameFromCellId(cellId){
    var firstDashPosition = cellId.indexOf('-');
    var secondPart = cellId.substring(firstDashPosition + 1);
    return secondPart.substring(secondPart.indexOf('-') + 1);
}




/* ++ tags general ++++++++++++++++++++++++++++++ */

function makeTagsDraggable(jQueryObjectSet){
    var draggingHelper;
    jQueryObjectSet.draggable({
        revert: "invalid",
        scroll: false,
        helper: function(){
            draggingHelper = jQuery(this).clone();
            return draggingHelper;
        },
        start: function(event, ui){
            jQuery(this).css('visibility', 'hidden');
        },
        stop: function(event, ui){
            draggingHelper.remove();
            jQuery(this).css('visibility', 'visible');
        }
    });
}

/* ++++++++++++++++++++++++++++++++++++++++++++++ */

jQuery(document).ready(function(){
    jQuery('input.tricia-edit-input:first').focus();
    
    jQuery('a.tricia-delete-link').click(function(){
        jQuery(this).find(".modalContent").modal({
            onShow: function(dialog){
                dialog.container.find('input.tricia-delete-link-submit').focus();
            }
        });
    });
    
    jQuery('.tricia-in-place-editing').live('hover', function(ev){
        if (ev.type == 'mouseover') {
            jQuery(this).find(".tricia-in-place-editing-link:first").show();
        }
        if (ev.type == 'mouseout') {
            jQuery(this).find(".tricia-in-place-editing-link:first").hide();
        }
    });
    
    jQuery('.tricia-in-place-editing-link').live('click', function(event){
        new EditFeatureDialog(jQuery(this).attr("href"), findElementToRefresh(jQuery(this)).data("refreshHandler"), jQuery(this));
        return false;
    });
    jQuery('.tricia-in-place-editing').live('click', function(event){
        if (event.ctrlKey) {
            if (!(event.target.tagName.toLowerCase() == "a" || jQuery(event.target).parents("a").length > 0)) {
                var editingLink = jQuery(this).find('.tricia-in-place-editing-link').eq(0);
                var elementToRefresh = findElementToRefresh(editingLink);
                new EditFeatureDialog(editingLink.attr("href"), elementToRefresh.data("refreshHandler"), jQuery(this));
                return false;
            }
        }
    });
    registerChangeValue();
    
    jQuery(".tricia-divergent-access-warning-link").each(function(){
        jQuery(this).tooltip( { showURL: false } );
    });
    
    jQuery(".tricia-remove-from-many-role").live("click", function(){
        var container = jQuery(this).parents("div.tricia-edit-manyRoleControl").eq(0);
        jQuery(this).parents("li").eq(0).remove();
        changeManyRoleValue(container);
        var overrideReaders = container.find("input.tricia-edit-override-readers-overrides");
        if (overrideReaders.length > 0) {
            if (container.find("ul.tricia-associations").find("li").length == 0) {
                overrideReadersInherits = container.parents(".tricia-edit-control").find("input.tricia-edit-override-readers-inherits");
                overrideReadersInherits.eq(0).attr("checked", true);
                changeValue(overrideReadersInherits);
            }
        }
        return false;
    });
    jQuery(".tricia-remove-from-one-role").live("click", function(){
        var container = jQuery(this).parents("div.tricia-edit-oneRoleControl").eq(0);
        container.empty();
        container.removeAttr("uid");
        changeOneRoleValue(container, "");
        handleOneRoleControl(container);
        return false;
    });
    
    jQuery("table.tricia-default-table").each(function(){
        if (!(jQuery(this).hasClass("tricia-data-table") || jQuery(this).hasClass("tricia-custom-data-table"))) {
            if (jQuery(this).find("thead").length > 0) {
                try {
                    jQuery(this).dataTable({
                        "bPaginate": false,
                        "bFilter": false,
                        "bSort": false,
                        "bInfo": false
                    });
                } 
                catch (e) {
                }
            }
        }
    });
    jQuery("table.tricia-data-table").each(function(){
        try {
            jQuery(this).dataTable({
                "bPaginate": false,
                "bFilter": false,
                "bInfo": false
            });
        } 
        catch (e) {
        }
    });
    
    jQuery.fn.dataTableExt.oSort['modified-asc'] = function(x, y){
        xAsInt = parseInt(jQuery(x).attr("asNumber"));
        yAsInt = parseInt(jQuery(y).attr("asNumber"));
        return ((xAsInt < yAsInt) ? -1 : ((xAsInt > yAsInt) ? 1 : 0));
    };
    jQuery.fn.dataTableExt.oSort['modified-desc'] = function(x, y){
        xAsInt = parseInt(jQuery(x).attr("asNumber"));
        yAsInt = parseInt(jQuery(y).attr("asNumber"));
        return ((xAsInt < yAsInt) ? 1 : ((xAsInt > yAsInt) ? -1 : 0));
    };
    jQuery.fn.dataTableExt.oSort['file-size-asc'] = function(x, y){
        xAsInt = parseInt(jQuery(x).attr("inKiloBytes"));
        yAsInt = parseInt(jQuery(y).attr("inKiloBytes"));
        return ((xAsInt < yAsInt) ? -1 : ((xAsInt > yAsInt) ? 1 : 0));
    };
    jQuery.fn.dataTableExt.oSort['file-size-desc'] = function(x, y){
        xAsInt = parseInt(jQuery(x).attr("inKiloBytes"));
        yAsInt = parseInt(jQuery(y).attr("inKiloBytes"));
        return ((xAsInt < yAsInt) ? 1 : ((xAsInt > yAsInt) ? -1 : 0));
    };
    jQuery.fn.dataTableExt.oSort['html-asc'] = function(x, y){
        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
    };
    jQuery.fn.dataTableExt.oSort['html-desc'] = function(x, y){
        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
    };
    jQuery.fn.dataTableExt.oSort['in-place-edit-numeric-asc'] = function(a, b){
        var x = jQuery(a).find("span.tricia-value").eq(0).html();
        var y = jQuery(b).find("span.tricia-value").eq(0).html();
        x = parseFloat(x);
        y = parseFloat(y);
        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
    };
    jQuery.fn.dataTableExt.oSort['in-place-edit-numeric-desc'] = function(a, b){
        var x = jQuery(a).find("span.tricia-value").eq(0).html();
        var y = jQuery(b).find("span.tricia-value").eq(0).html();
        x = parseFloat(x);
        y = parseFloat(y);
        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
    };
    jQuery.fn.dataTableExt.oSort['in-place-edit-boolean-asc'] = function(a, b){
        var x = jQuery(a).find(".tricia-boolean").eq(0).attr("asBoolean");
        var y = jQuery(b).find(".tricia-boolean").eq(0).attr("asBoolean");
        x = parseFloat(x);
        y = parseFloat(y);
        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
    };
    jQuery.fn.dataTableExt.oSort['in-place-edit-boolean-desc'] = function(a, b){
        var x = jQuery(a).find(".tricia-boolean").eq(0).attr("asBoolean");
        var y = jQuery(b).find(".tricia-boolean").eq(0).attr("asBoolean");
        x = parseFloat(x);
        y = parseFloat(y);
        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
    };
    jQuery(".tricia-page-content").find('a[href^="/file/"]').each(function(){
        var a = jQuery(this);
        if (!(a.hasClass("tricia-entity-kind-directory") || a.hasClass("tricia-kind-image") || a.hasClass("tricia-file-download"))) {
            var params = jQuery.deparam.querystring(a.attr("href"));
            if (!params.details) {
                var detailsUrl = jQuery.param.querystring(a.attr("href"), "details=true");
                a.after(jQuery('<a class="tricia-file-details-link" title="Details" href="' + detailsUrl + '"><img src="/__cachebreakerfake/icons/details.png"></a>'));
            }
        }
    });
    jQuery('a.tricia-long-help').live('click', function(event){
        jQuery.ajax({
            dataType: "json",
            url: jQuery(this).attr("href"),
            success: function(data){
                var overlayDiv = getOverlayDiv("tricia-long-help-details-overlay");
                overlayDiv.empty();
                overlayDiv.append(data.html);
                dialog = overlayDiv.dialog({
                    modal: true,
                    title: data.title
                });
            }
        });
        return false;
    });
    jQuery('.hybridPropertyValidationMessage').live('click', function(){
        var messageDiv = jQuery(this);
        messageDiv.parents('.tricia-in-place-editing:first').each(function(){
            jQuery(this).prepend(messageDiv.clone());
            messageDiv.remove();
        });
    });
    jQuery('a.tricia-validation-message-detail').live('click', function(event){
        jQuery.ajax({
            dataType: "json",
            url: jQuery(this).attr("href"),
            success: function(data){
                var overlayDiv = getOverlayDiv("tricia-validation-message-details-overlay");
                overlayDiv.empty();
                overlayDiv.append(data.html);
                dialog = overlayDiv.dialog({
                    width: 440,
                    height: 100,
                    modal: true,
                    title: data.title
                });
            }
        });
        return false;
    });
});

function EditFeatureDialog(editUrl, finishedHandler, triggeringElement){

    var overlayDiv = getOverlayDiv("tricia-edit-feature-overlay");
    
    var self = this;
    
    var dialog = null;
    
    this.onClose = function(event, ui){
        if (finishedHandler) {
            finishedHandler();
        }
    };
    
    this.onFormSubmit = function(){
        if (tinyMCE != null) {
            tinyMCE.triggerSave();
        }
        if (overlayDiv.find('form').valid()) {
            overlayDiv.find('.tricia-edit-input').each(function(){
                jQuery(this).val(jQuery.trim(jQuery(this).val()));
            });
            if (!finishedHandler) { // server checks whether current Url still valid (urlName might change)
                overlayDiv.find('.tricia-on-success-url').val(window.location.href);
            }
            overlayDiv.find('form').ajaxSubmit({
                dataType: "json",
                success: function(data){
                    if (data.success) {
                        if (!finishedHandler && data.changedSuccessUrl) {
                            goToUrl(data.changedSuccessUrl);
                        }
                        else {
                            if (!finishedHandler) {
                                goToUrl(window.location.href);
                            }
                            else {
                                dialog.dialog('close');
                            }
                        }
                    }
                    else {
                        var tinyMceTextArea = overlayDiv.find('textarea.tricia-tinymce');
                        if (tinyMceTextArea.length >= 1) {
                            tinyMCE.execCommand('mceRemoveControl', false, tinyMceTextArea.attr('id'));
                        }
                        self.openEditUrlInDialog(data.editUrl);
                    }
                }
            });
        }
        return false;
    };
    
    this.initForm = function(){
        registerValidateForm(overlayDiv.find('form'));
        overlayDiv.find('form').submit(self.onFormSubmit);
        registerChangeValue();
        overlayDiv.find('.cancelButton').click(function(){
            dialog.dialog('close');
        });
        
        if (!finishedHandler) {
            jQuery("input#tricia-on-success-url").val(window.location.href);
        }
    };
    
    this.openEditUrlInDialog = function(dialogEditUrl){
        jQuery.ajax({
            dataType: "json",
            url: dialogEditUrl,
            success: function(data){
                if (data.code == "success") {
                    var width = "auto";
                    if (data.width) {
                        width = parseInt(data.width);
                    }
                    overlayDiv.empty();
                    overlayDiv.append(data.html);
                    self.initForm();
                    
                    dialog = overlayDiv.dialog({
                        width: width,
                        modal: true,
                        beforeClose: function(ev, ui){
                            if (!finishedHandler) {
                                goToUrl(window.location.href);
                                return false;
                            }
                            else {
                                return true;
                            }
                        },
                        close: self.onClose,
                        title: data.title
                    });
                    var editInput;
                    if (triggeringElement.parents('.value:first').size()) {
                        editInput = overlayDiv.find('.hybridPropertyValue input:not(:hidden):first');
                    }
                    else {
                        editInput = overlayDiv.find('.hybridPropertyName:first');
                    }
                    //property is not hybrid
                    if (editInput.size() == 0) {
                        editInput = overlayDiv.find('input:not(:hidden):first');
                    }
                    editInput.focus();
                }
                else {
                    goToUrl(data.handleDraftUrl);
                }
            }
        });
    };
    this.openEditUrlInDialog(editUrl);
}

/* ------------------------- start tinymce dialog ----------------------------- */

function restoreSelection(ed){
    if (ed.isIE) {
        ed.selection.moveToBookmark(ed.windowManager.bookmark);
    }
}

function storeSelection(ed){
    ed.windowManager.bookmark = ed.selection.getBookmark('simple');
}

function insertLink(url, newLabel){
    var ed = jQuery("body").data("ed");
    ed.selection.setRng(jQuery("body").data("ed.selection.range"));
    
    if (newLabel == null || newLabel.length == 0) {
        newLabel = url;
    }
    
    var selectedText = null;
    if (!ed.selection.isCollapsed()) {
        selectedText = ed.selection.getContent();
    }
    ed.execCommand("mceBeginUndoLevel");
    ed.getDoc().execCommand('unlink', false, null);
    ed.getDoc().execCommand('RemoveFormat', false, null);
    var e = ed.dom.getParent(ed.selection.getNode(), 'A');
    
    // Create new anchor elements
    if (e == null) {
        var text = selectedText == null ? newLabel : selectedText;
        ed.execCommand('mceInsertContent', false, '<a href="' + url + '">' + text + '</a>');
    }
    else {
        if (url == null || url == '') {
            ed.selection.select(e);
            ed.execCommand('mceInsertContent', false, e.innerHTML);
        }
        ed.dom.setAttribs(e, {
            href: url
        });
    }
    
    ed.execCommand("mceEndUndoLevel");
    
    closeDialog();
    return;
}

function closeDialog(){
    jQuery.removeData("ed");
    jQuery("body").data("dialog").dialog("close");
}

function insertImage(url, text, title, alt){
    var ed = jQuery("body").data("ed");
    ed.selection.setRng(jQuery("body").data("ed.selection.range"));
    var f = document.forms[0], nl = f.elements, args = {}, el;
    
    restoreSelection(ed);
    
    if (url === '') {
        if (ed.selection.getNode().nodeName == 'IMG') {
            ed.dom.remove(ed.selection.getNode());
            ed.execCommand('mceRepaint');
        }
        closeDialog();
        return;
    }
    
    tinymce.extend(args, {
        src: url,
        alt: alt
    });
    
    el = ed.selection.getNode();
    
    if (el && el.nodeName == 'IMG') {
        ed.dom.setAttribs(el, args);
    }
    else {
        ed.execCommand('mceInsertContent', false, '<img id="__mce_tmp" />', {
            skip_undo: 1
        });
        ed.dom.setAttribs('__mce_tmp', args);
        ed.dom.setAttrib('__mce_tmp', 'id', '');
        ed.undoManager.add();
    }
    
    closeDialog();
    return;
}

function submitImage(idPrefix){
    var url = jQuery("#" + idPrefix + "url").val();
    if (url != null && url.length > 0) {
        insertImage(url, jQuery("#" + idPrefix + "name").val());
    }
}

function submitEmbeddedSearch(idPrefix){
    var ed = jQuery("body").data("ed");
    ed.selection.setRng(jQuery("body").data("ed.selection.range"));
    var text = jQuery("#hiddenUidInput").val();
    var url = jQuery("#" + idPrefix + "url").val();
    if (url != null && url.length > 0) {
        ed.execCommand("mceBeginUndoLevel");
        
        ed.execCommand('mceInsertContent', false, '$embeddedSearch(uid="' + text + '")$');
        
        ed.execCommand("mceEndUndoLevel");
    }
    closeDialog();
    return;
}

/* ------------------------- end tinymce dialog ----------------------------- */

jQuery.fn.setCursorPosition = function(pos){
    this.each(function(index, elem){
        if (elem.setSelectionRange) {
            elem.setSelectionRange(pos, pos);
        }
        else 
            if (elem.createTextRange) {
                var range = elem.createTextRange();
                range.collapse(true);
                range.moveEnd('character', pos);
                range.moveStart('character', pos);
                range.select();
            }
    });
    return this;
};

function findElementToRefresh(element){
    return element.parents('.tricia-refreshable:first');
}

function registerRefreshable(element, refreshHandler){
    element.data("refreshHandler", refreshHandler);
    element.addClass("tricia-refreshable");
}

function getOverlayDiv(divId){
    var overlayDiv = jQuery("#" + divId);
    if (overlayDiv.length == 0) {
        overlayDiv = jQuery('<div id="' + divId + '"></div>');
        jQuery("body").append(overlayDiv);
    }
    else {
        overlayDiv.empty();
    }
    return overlayDiv;
}

function getColor(elem, attr){
    var color;
    do {
        color = elem.css(attr);
        // Keep going until we find an element that has color, or we hit the body
        if (color != '' && color != 'transparent' || elem.nodeName == 'body') {
            break;
        }
    }
    while (elem = elem.parent());
    return color;
}

function registerValidateForm(form){
    form.validate({
        highlight: function(element, errorClass){
            jQuery(element).addClass(errorClass);
        },
        unhighlight: function(element, errorClass){
            jQuery(element).removeClass(errorClass);
        },
        errorClass: "tricia-error"
    });
}

function registerChangeValue(){
    jQuery("div.tricia-edit-manyRoleControl").each(function(){
        handleManyRoleLabel(jQuery(this));
    });
    jQuery("div.tricia-edit-oneRoleControl").each(function(){
        handleOneRoleControl(jQuery(this));
    });
    jQuery('form.tricia-edit-form input.tricia-edit-input').keyup(function(){
        changeValue(jQuery(this));
    });
    jQuery('form.tricia-edit-form input.tricia-edit-input').change(function(){
        changeValue(jQuery(this));
    });
    jQuery('form.tricia-edit-form textarea.tricia-edit-input').change(function(){
        changeValue(jQuery(this));
    });
    jQuery('form.tricia-edit-form select.tricia-edit-input').change(function(){
        changeValue(jQuery(this));
    });
    jQuery('form.tricia-edit-form input.tricia-edit-input').keyup(function(e){
        if (e.keyCode == 13) {
            changeValue(jQuery(this));
            return false;
        }
    });
    jQuery('form.tricia-edit-form').keypress(function(e){
        if (e.which == 115 && e.ctrlKey) {
            e.preventDefault();
            e.stopPropagation();
            jQuery(this).find('input').blur(); // autocomplete menu might open otherwise
            jQuery(this).submit();
        }
    });
    jQuery('form.tricia-edit-form input.tricia-edit-additional-choice').change(function(){
        changeControlValue(jQuery(this));
    });
    jQuery('.tricia-edit-form').each(function(){
        var parent = jQuery(this).parent();
        registerValidateForm(jQuery(this));
        if (parent.find(".overlay-after-search").length == 0) {
            var overlayDiv = jQuery("<div class='overlay-after-save before-save'></div>");
            parent.append(overlayDiv);
            jQuery(this).submit(function(){
                if (jQuery(this).valid()) {
                    overlayDiv.removeClass('before-save').addClass('overlayBG');
                }
                else {
                    return false;
                }
            });
        }
    });
}

function handleOneRoleControl(container){
    var uid = container.attr("uid");
    var noReplaceButton = container.attr("noReplaceButton") == "true";
    if (uid == null) {
        addOneRoleInput(container);
    }
    else {
        setOneRoleItemWithRemoveButton(container, uid, container.attr("title"), container.html(), false);
    }
}

function addOneRoleInput(container){
    if (container.find("input.tricia-autocomplete-input").length == 0) {
        container.empty();
        var input = getJQueryAutoCompleteInput();
        container.append(input);
        
        input.triciaautocomplete({
            minLength: 1,
            source: function(request, response){
                jQuery.ajax({
                    url: "/functions/findAsset",
                    dataType: "json",
                    data: {
                        query: request.term,
                        otherKind: container.attr("otherKind")
                    },
                    success: function(data){
                        response(data, request.term);
                    }
                });
            },
            select: function(event, ui){
                container.attr("uid", ui.item.uid);
                setOneRoleItemWithRemoveButton(container, ui.item.uid, ui.item.label, ui.item.imageTag, true);
            }
        }).data("triciaautocomplete")._renderItem = autoCompleteRenderItemfunction;
    }
}

function setOneRoleItemWithRemoveButton(container, uid, title, imageTag, doChangeValueNow){
    if (container.find(".tricia-one-role-asset").length == 0) {
        var div = jQuery("<div class='tricia-one-role-asset'>" + imageTag + "&nbsp;<label>" + title + "</label></div>");
        if (container.parents().find(".tricia-edit-role-compoundValues").length == 0) {
            div.append(jQuery("<a href='#' class='tricia-remove-action tricia-remove-from-one-role'><img width='16' height='16' title='Remove value' src='/__cacheBreakerFake/icons/list-remove.png' /></a>"));
        }
        div.attr("uid", uid);
        container.empty();
        if (doChangeValueNow) {
            changeOneRoleValue(container, uid);
        }
        container.append(div);
    }
}

function changeOneRoleValue(container, uid){
    var input = container.parent().find("input.tricia-edit-parameter-submit");
    changeValue(input.get());
    input.val(uid);
}

function getJQueryAutoCompleteInput(){
    return jQuery("<input class='tricia-autocomplete-input' type='text' style='width:100%'/>");
}

function handleManyRoleLabel(container){
    if (container.find("input.tricia-autocomplete-input").length == 0) {
        var input = getJQueryAutoCompleteInput();
        container.append(input);
        input.triciaautocomplete({
            minLength: 1,
            source: function(request, response){
                jQuery.ajax({
                    url: "/functions/findAsset",
                    dataType: "json",
                    data: {
                        query: request.term,
                        otherKind: container.attr("otherKind")
                    },
                    success: function(data){
                        response(data, request.term);
                    }
                });
            },
            select: function(event, ui){
                var uid = ui.item.uid;
                if (!contains(container, uid)) {
                    var newLi = jQuery("<li>" + ui.item.imageTag + "&nbsp;<label></label></li>");
                    newLi.attr("uid", uid);
                    var label = newLi.find("label");
                    label.text(ui.item.label);
                    var uls = container.find("ul.tricia-associations");
                    var ul;
                    if (uls.length == 0) {
                        ul = jQuery('<ul class="tricia-associations"></ul>');
                        container.append(ul);
                    }
                    else {
                        ul = container.find("ul").eq(0);
                    }
                    var overrideReaders = container.find("input.tricia-edit-override-readers-overrides");
                    if (overrideReaders.length > 0) {
                        overrideReaders.eq(0).attr("checked", true);
                        changeValue(overrideReaders);
                    }
                    ul.append(newLi);
                    handleLi(label);
                    input.remove();
                    changeManyRoleValue(container);
                    handleManyRoleLabel(container);
                }
            }
        }).data("triciaautocomplete")._renderItem = autoCompleteRenderItemfunction;
        
        container.find("ul > li > label").each(function(){
            handleLi(jQuery(this));
        });
    }
}

function handleLi(label){
    if (label.find(".tricia-remove-from-many-role").length == 0) {
        label.append(jQuery("<a href='#' class='tricia-remove-action tricia-remove-from-many-role'><img width='16' height='16' class='actionIcon' title='Remove value' src='/__cacheBreakerFake/icons/list-remove.png' /></a>"));
    }
}

function contains(container, uid){
    var result = false;
    container.find("li").each(function(){
        if (uid == jQuery(this).attr("uid")) {
            result = true;
        }
    });
    return result;
}

function changeManyRoleValue(container){
    var listenerName = container.attr("listener");
    if (listenerName != null) {
        eval(listenerName + "()");
    }
    var input = container.find("input.tricia-edit-parameter-submit");
    changeValue(input.get());
    var value = "";
    container.find("ul > li").each(function(){
        value += jQuery(this).attr("uid") + " ";
    });
    input.val(value);
}

function changeControlValue(control){
    var controlWrapper = jQuery(control).parents(".tricia-edit-control");
    if (controlWrapper.length == 0) {
        alert("Cannot change control value!");
    }
    var manyRoleContainer = controlWrapper.find(".tricia-edit-manyRoleControl");
    if (manyRoleContainer.length == 1) {
        changeManyRoleValue(manyRoleContainer);
    }
    else {
        changeValue(controlWrapper.find(".tricia-edit-input"));
    }
}

function autoCompleteRenderItemfunction(ul, item){
    jQuery("<li></li>").data("item.autocomplete", item).append(item.html).appendTo(ul);
}

// --------------------------------------------------------

function debugJQueryElement(e){
    var result = "";
    jQuery.each(e, function(){
        var e = jQuery(this);
        result += "html: " + e.eq(0).get().nodeName + "\n";
        result += getCssProperty(e, "visibility");
        result += getCssProperty(e, "z-index");
        result += getCssProperty(e, "position");
        result += getCssProperty(e, "display");
        //e.css("visibility", "visible");
        e.css("z-index", "0");
    });
    return result;
}

function getCssProperty(e, name){
    return name + ": " + e.css(name) + "\n";
}

function setToNulls(clearInput){
    var length = clearInput.val().length;
    var nulls = "";
    for (var i = 0; i < length; i++) {
        nulls = nulls + "0";
    }
    clearInput.val(nulls);
}

function changeValue(input, parameterName){
    var jInput = jQuery(input);
    changeNonCompoundValue(jInput, parameterName);
    if (jInput.length > 0) {
        var parents = jInput.parents("table.tricia-show-compoundValues");
        if (parents.size() > 0) {
            parents.parent().find("> input").each(function(){
                changeNonCompoundValue(jQuery(this));
            });
        }
    }
}

function changeNonCompoundValue(input, parameterName){
    jQuery(".changes-hidden").each(function(){
        var changesField = jQuery(this);
        var val = changesField.val();
        if (parameterName == null) {
            parameterName = input.attr("name");
        }
        // in case of a DomainValueMatrixProperty the parameterName has to be stripped, but not if it belongs to a hybrid property
        if (parameterName.indexOf("-") >= 0 && parameterName.indexOf("'") < 0) {
            parameterName = parameterName.substring(0, parameterName.indexOf("-"));
        }
        if (val.indexOf(parameterName) < 0) {
            changesField.val(val += "," + parameterName);
        }
    });
}

// ---------------------------------------------------

function cancel(cancelUrl){
    if (cancelUrl.length > 0) {
        goToUrl(cancelUrl);
    }
    else {
        returnBack();
    }
}

// Return back to the last visited page
function returnBack(){
    if (window.history.length > 1) {
        window.history.back();
    }
    else {
        alert("close");
        window.open('', '_parent', '');
        window.close();
    }
}

function goToUrl(url){
    window.location.href = url;
}

function appendToUrl(query){
    var url = window.location.href;
    return appendParametersToURL(url, query);
}

function appendParametersToURL(url, query){
    if (url.indexOf('?') > 0) {
        url = url + "&" + query;
    }
    else {
        url = url + "?" + query;
    }
    return url;
}

function bugReport(){
    jQuery.ajax({
        dataType: "json",
        url: "/feedback/createIssue?location=" + encodeURIComponent(window.location.href),
        success: function(data){
            var overlayDiv = getOverlayDiv("tricia-feedback-overlay");
            overlayDiv.empty();
            overlayDiv.append(data.html);
            dialog = overlayDiv.dialog({
                modal: true,
                width: 600,
                height: 500
            });
            registerChangeValue();
        }
    });
}


// ----------- link control ----------------------------------------

function linkOrImageControl(element){
    if (element.parents("#file-link-form").length == 1) {
        return "linkControl";
    }
    else {
        return "imageControl";
    }
}

function directoryLoaded(){
    jQuery('div#tricia-linkControl-directory a').click(function(e){
        if (jQuery(this).hasClass('tricia-popup-go-into')) {
            var href = jQuery(this).attr("href");
            jQuery('#document-name').val(jQuery(this).text());
            jQuery("#tricia-linkControl-directory").load("/" + linkOrImageControl(jQuery(this)) + "/directoryView?url=" + href, directoryLoaded);
        }
        else {
            var url = jQuery(this).attr('href');
            if (jQuery(this).parents(".tricia-popup-create-link").length == 1) {
				// link to a folder
                insertLink(url, jQuery(this).attr("name"));
			} else if (jQuery(this).parents("#file-link-form").length == 1) {
                insertLink(url, jQuery(this).text());
            } else {
                insertImage(url);
            }
        }
        return false;
    });
}

function handleJQueryAutoCompletion(container, onSelect, value){
    var input = getJQueryAutoCompleteInput();
    container.empty();
    container.append(input);
    
    input.triciaautocomplete({
        minLength: 1,
        maxWidth: 300,
        source: function(request, response){
            jQuery.ajax({
                url: "/functions/findAsset",
                dataType: "json",
                data: {
                    query: request.term,
                    otherKind: container.attr("otherKind")
                },
                success: function(data){
                    response(data, request.term);
                }
            });
        },
        select: function(event, ui){
            onSelect(ui.item);
        }
    }).data("triciaautocomplete")._renderItem = autoCompleteRenderItemfunction;
}

function createNewWikiPage(){
    var wikiUrl = jQuery('.tricia-choose-wiki').eq(0).attr('wikiUrl');
    var name = jQuery('.tricia-choose-wikiPage').find('input').val();
    if (name && name.length > 2) {
        jQuery.getJSON("/wikiPage/createStub", {
            name: name,
            wikiUrl: wikiUrl
        }, function(json){
            if (json.invalid != null) {
                alert("There already exists a page with this name.");
            }
            else {
                insertLink(json.url, name);
            }
        });
    }
    else {
        alert("Provide a name with at least 2 characters.");
    }
}

function loadCss(cssUrl){
    jQuery('head').each(function(){
        jQuery(this).append("<link rel='stylesheet' type='text/css' href='" + cssUrl + "' />");
    });
}


function loadCaptchaForm(submitForm){
    var overlayDiv = getOverlayDiv("tricia-captcha-overlay");
    overlayDiv.load("/captcha/new", function(){
        initCaptchaForm(submitForm);
    });
    jQuery.modal(overlayDiv, {
        close: false
    });
}

function initCaptchaForm(submitForm){
    registerChangeValue();
    jQuery('#tricia-captcha-edit .tricia-cancel').click(function(){
        jQuery.modal.close();
    });
    jQuery('#tricia-captcha-edit').submit(function(){
        jQuery(this).ajaxSubmit({
            dataType: "json",
            success: function(json){
                if (json.isValid) {
                    jQuery.modal.close();
                    jQuery(submitForm).unbind('submit').submit();
                }
                else {
                    // is not valid
                    var overlayDiv = getOverlayDiv("tricia-captcha-overlay");
                    overlayDiv.load("/captcha/edit?captchaId=" + json.captchaId + "&showValidationMessage", function(){
                        initCaptchaForm(submitForm);
                    });
                }
            }
        });
        // return false to prevent normal browser submit and page navigation
        return false;
    });
}

// ---------------------------------------------------

function randomString(){
    var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
    var string_length = 8;
    var randomstring = '';
    for (var i = 0; i < string_length; i++) {
        var rnum = Math.floor(Math.random() * chars.length);
        randomstring += chars.substring(rnum, rnum + 1);
    }
    return randomstring;
}

// ------------------- foldable table rows ------------------------------

jQuery(function(){
    jQuery("tr.tricia-heading-row-with-collapsing").each(function(){
        var tr = jQuery(this);
        if (isCollapsable(tr)) {
            tr.addClass("tricia-heading-row-closed");
            tr.next("tr").each(function(){
                hideIfNoHeadingRow(jQuery(this));
            });
            tr.click(function(){
                tr.toggleClass("tricia-heading-row-closed");
                tr.toggleClass("tricia-heading-row-open");
                tr.next("tr").each(function(){
                    toggleIfNoHeadingRow(jQuery(this));
                });
            });
        }
    });
});

function isCollapsable(tr){
    var nextTr = tr.next("tr");
    if (nextTr.length == 0) {
        return false;
    }
    else {
        return collapse(nextTr);
    }
}

function collapse(tr){
    return !tr.hasClass("tricia-heading-row-with-collapsing") && !tr.hasClass("tricia-heading-row-stop-collapsing") && !tr.hasClass("tricia-heading-row-without-collapsing");
}

function hideIfNoHeadingRow(tr){
    if (collapse(tr)) {
        tr.hide();
        tr.next("tr").each(function(){
            hideIfNoHeadingRow(jQuery(this));
        });
    }
}

function toggleIfNoHeadingRow(tr){
    if (!tr.hasClass("tricia-heading-row-with-collapsing")) {
        if (tr.filter(":hidden").size() > 0) {
            showIfNoHeadingRow(tr);
        }
        else {
            hideIfNoHeadingRow(tr);
        }
    }
}

function showIfNoHeadingRow(tr){
    if (!tr.hasClass("tricia-heading-row-with-collapsing")) {
        tr.show();
        tr.next("tr").each(function(){
            showIfNoHeadingRow(jQuery(this));
        });
    }
}

//-- MD5 Algorithm

/*
 *  md5.jvs 1.0b 27/06/96
 *
 * Javascript implementation of the RSA Data Security, Inc. MD5
 * Message-Digest Algorithm.
 *
 * Copyright (c) 1996 Henri Torgemane. All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for any purposes and without
 * fee is hereby granted provided that this copyright notice
 * appears in all copies.
 *
 * Of course, this soft is provided "as is" without express or implied
 * warranty of any kind.
 *
 * $Id: md5.js,v 1.1.1.1 2000/04/17 16:40:07 kk Exp $
 *
 */
function array(n){
    for (i = 0; i < n; i++) 
        this[i] = 0;
    this.length = n;
}

/* Some basic logical functions had to be rewritten because of a bug in
 * Javascript.. Just try to compute 0xffffffff >> 4 with it..
 * Of course, these functions are slower than the original would be, but
 * at least, they work!
 */
function integer(n){
    return n % (0xffffffff + 1);
}

function shr(a, b){
    a = integer(a);
    b = integer(b);
    if (a - 0x80000000 >= 0) {
        a = a % 0x80000000;
        a >>= b;
        a += 0x40000000 >> (b - 1);
    }
    else 
        a >>= b;
    return a;
}

function shl1(a){
    a = a % 0x80000000;
    if (a & 0x40000000 == 0x40000000) {
        a -= 0x40000000;
        a *= 2;
        a += 0x80000000;
    }
    else 
        a *= 2;
    return a;
}

function shl(a, b){
    a = integer(a);
    b = integer(b);
    for (var i = 0; i < b; i++) 
        a = shl1(a);
    return a;
}

function and(a, b){
    a = integer(a);
    b = integer(b);
    var t1 = (a - 0x80000000);
    var t2 = (b - 0x80000000);
    if (t1 >= 0) 
        if (t2 >= 0) 
            return ((t1 & t2) + 0x80000000);
        else 
            return (t1 & b);
    else 
        if (t2 >= 0) 
            return (a & t2);
        else 
            return (a & b);
}

function or(a, b){
    a = integer(a);
    b = integer(b);
    var t1 = (a - 0x80000000);
    var t2 = (b - 0x80000000);
    if (t1 >= 0) 
        if (t2 >= 0) 
            return ((t1 | t2) + 0x80000000);
        else 
            return ((t1 | b) + 0x80000000);
    else 
        if (t2 >= 0) 
            return ((a | t2) + 0x80000000);
        else 
            return (a | b);
}

function xor(a, b){
    a = integer(a);
    b = integer(b);
    var t1 = (a - 0x80000000);
    var t2 = (b - 0x80000000);
    if (t1 >= 0) 
        if (t2 >= 0) 
            return (t1 ^ t2);
        else 
            return ((t1 ^ b) + 0x80000000);
    else 
        if (t2 >= 0) 
            return ((a ^ t2) + 0x80000000);
        else 
            return (a ^ b);
}

function not(a){
    a = integer(a);
    return (0xffffffff - a);
}

// Here begin the real algorithm

var state = new array(4);
var count = new array(2);
var buffer = new array(64);
var transformBuffer = new array(16);
var digestBits = new array(16);

var S11 = 7;
var S12 = 12;
var S13 = 17;
var S14 = 22;
var S21 = 5;
var S22 = 9;
var S23 = 14;
var S24 = 20;
var S31 = 4;
var S32 = 11;
var S33 = 16;
var S34 = 23;
var S41 = 6;
var S42 = 10;
var S43 = 15;
var S44 = 21;

function F(x, y, z){
    return or(and(x, y), and(not(x), z));
}

function G(x, y, z){
    return or(and(x, z), and(y, not(z)));
}

function H(x, y, z){
    return xor(xor(x, y), z);
}

function I(x, y, z){
    return xor(y, or(x, not(z)));
}

function rotateLeft(a, n){
    return or(shl(a, n), (shr(a, (32 - n))));
}

function FF(a, b, c, d, x, s, ac){
    a = a + F(b, c, d) + x + ac;
    a = rotateLeft(a, s);
    a = a + b;
    return a;
}

function GG(a, b, c, d, x, s, ac){
    a = a + G(b, c, d) + x + ac;
    a = rotateLeft(a, s);
    a = a + b;
    return a;
}

function HH(a, b, c, d, x, s, ac){
    a = a + H(b, c, d) + x + ac;
    a = rotateLeft(a, s);
    a = a + b;
    return a;
}

function II(a, b, c, d, x, s, ac){
    a = a + I(b, c, d) + x + ac;
    a = rotateLeft(a, s);
    a = a + b;
    return a;
}

function transform(buf, offset){
    var a = 0, b = 0, c = 0, d = 0;
    var x = transformBuffer;
    
    a = state[0];
    b = state[1];
    c = state[2];
    d = state[3];
    
    for (i = 0; i < 16; i++) {
        x[i] = and(buf[i * 4 + offset], 0xff);
        for (j = 1; j < 4; j++) {
            x[i] += shl(and(buf[i * 4 + j + offset], 0xff), j * 8);
        }
    }
    
    // Round 1
    a = FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
    d = FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
    c = FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
    b = FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
    a = FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
    d = FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
    c = FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
    b = FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
    a = FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
    d = FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
    c = FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
    b = FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
    a = FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
    d = FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
    c = FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
    b = FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
    // Round 2
    a = GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
    d = GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
    c = GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
    b = GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
    a = GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
    d = GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
    c = GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
    b = GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
    a = GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
    d = GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
    c = GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
    b = GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
    a = GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
    d = GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
    c = GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
    b = GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
    // Round 3
    a = HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
    d = HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
    c = HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
    b = HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
    a = HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
    d = HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
    c = HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
    b = HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
    a = HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
    d = HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
    c = HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
    b = HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
    a = HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
    d = HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
    c = HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
    b = HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
    // Round 4
    a = II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
    d = II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
    c = II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
    b = II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
    a = II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
    d = II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
    c = II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
    b = II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
    a = II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
    d = II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
    c = II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
    b = II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
    a = II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
    d = II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
    c = II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
    b = II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
    state[0] += a;
    state[1] += b;
    state[2] += c;
    state[3] += d;
    
}

function init(){
    count[0] = count[1] = 0;
    state[0] = 0x67452301;
    state[1] = 0xefcdab89;
    state[2] = 0x98badcfe;
    state[3] = 0x10325476;
    for (i = 0; i < digestBits.length; i++) 
        digestBits[i] = 0;
}

function update(b){
    var index, i;
    
    index = and(shr(count[0], 3), 0x3f);
    if (count[0] < 0xffffffff - 7) 
        count[0] += 8;
    else {
        count[1]++;
        count[0] -= 0xffffffff + 1;
        count[0] += 8;
    }
    buffer[index] = and(b, 0xff);
    if (index >= 63) {
        transform(buffer, 0);
    }
}

function finish(){
    var bits = new array(8);
    var padding;
    var i = 0, index = 0, padLen = 0;
    
    for (i = 0; i < 4; i++) {
        bits[i] = and(shr(count[0], (i * 8)), 0xff);
    }
    for (i = 0; i < 4; i++) {
        bits[i + 4] = and(shr(count[1], (i * 8)), 0xff);
    }
    index = and(shr(count[0], 3), 0x3f);
    padLen = (index < 56) ? (56 - index) : (120 - index);
    padding = new array(64);
    padding[0] = 0x80;
    for (i = 0; i < padLen; i++) 
        update(padding[i]);
    for (i = 0; i < 8; i++) 
        update(bits[i]);
    
    for (i = 0; i < 4; i++) {
        for (j = 0; j < 4; j++) {
            digestBits[i * 4 + j] = and(shr(state[i], (j * 8)), 0xff);
        }
    }
}

function hexa(n){
    var hexa_h = "0123456789abcdef";
    var hexa_c = "";
    var hexa_m = n;
    for (hexa_i = 0; hexa_i < 8; hexa_i++) {
        hexa_c = hexa_h.charAt(Math.abs(hexa_m) % 16) + hexa_c;
        hexa_m = Math.floor(hexa_m / 16);
    }
    return hexa_c;
}


var ascii = "01234567890123456789012345678901" +
" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";

function MD5(entree){
    var l, s, k, ka, kb, kc, kd;
    
    init();
    for (k = 0; k < entree.length; k++) {
        l = entree.charAt(k);
        update(ascii.lastIndexOf(l));
    }
    finish();
    ka = kb = kc = kd = 0;
    for (i = 0; i < 4; i++) 
        ka += shl(digestBits[15 - i], (i * 8));
    for (i = 4; i < 8; i++) 
        kb += shl(digestBits[15 - i], ((i - 4) * 8));
    for (i = 8; i < 12; i++) 
        kc += shl(digestBits[15 - i], ((i - 8) * 8));
    for (i = 12; i < 16; i++) 
        kd += shl(digestBits[15 - i], ((i - 12) * 8));
    s = hexa(kd) + hexa(kc) + hexa(kb) + hexa(ka);
    return s;
}

// End of the MD5 algorithm

/*
 * A JavaScript implementation of the RSA Data Security, Inc. MD4 Message
 * Digest Algorithm, as defined in RFC 1320.
 * Version 2.1 Copyright (C) Jerrad Pierce, Paul Johnston 1999 - 2002.
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for more info.
 */
/*
 * Configurable variables. You may need to tweak these to be compatible with
 * the server-side, but the defaults work in most cases.
 */
var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase        */
var b64pad = "-"; /* base-64 pad character. "=" for strict RFC compliance   */
var chrsz = 16; /* bits per input character. 8 - ASCII; 16 - Unicode      */
/*
 * These are the functions you'll usually want to call
 */
function hex_md4(s){
    return binl2hex(core_md4(str2binl(s), s.length * chrsz));
}

function b64_md4(s){
    return binl2b64(core_md4(str2binl(s), s.length * chrsz));
}

function str_md4(s){
    return binl2str(core_md4(str2binl(s), s.length * chrsz));
}

function hex_hmac_md4(key, data){
    return binl2hex(core_hmac_md4(key, data));
}

function b64_hmac_md4(key, data){
    return binl2b64(core_hmac_md4(key, data));
}

function str_hmac_md4(key, data){
    return binl2str(core_hmac_md4(key, data));
}

/* 
 * Perform a simple self-test to see if the VM is working
 */
function md4_vm_test(){
    return hex_md4("abc") == "a448017aaf21d8525fc10ae87aa6729d";
}

/*
 * Calculate the MD4 of an array of little-endian words, and a bit length
 */
function core_md4(x, len){
    /* append padding */
    x[len >> 5] |= 0x80 << (len % 32);
    x[(((len + 64) >>> 9) << 4) + 14] = len;
    
    var a = 1732584193;
    var b = -271733879;
    var c = -1732584194;
    var d = 271733878;
    
    for (var i = 0; i < x.length; i += 16) {
        var olda = a;
        var oldb = b;
        var oldc = c;
        var oldd = d;
        
        a = md4_ff(a, b, c, d, x[i + 0], 3);
        d = md4_ff(d, a, b, c, x[i + 1], 7);
        c = md4_ff(c, d, a, b, x[i + 2], 11);
        b = md4_ff(b, c, d, a, x[i + 3], 19);
        a = md4_ff(a, b, c, d, x[i + 4], 3);
        d = md4_ff(d, a, b, c, x[i + 5], 7);
        c = md4_ff(c, d, a, b, x[i + 6], 11);
        b = md4_ff(b, c, d, a, x[i + 7], 19);
        a = md4_ff(a, b, c, d, x[i + 8], 3);
        d = md4_ff(d, a, b, c, x[i + 9], 7);
        c = md4_ff(c, d, a, b, x[i + 10], 11);
        b = md4_ff(b, c, d, a, x[i + 11], 19);
        a = md4_ff(a, b, c, d, x[i + 12], 3);
        d = md4_ff(d, a, b, c, x[i + 13], 7);
        c = md4_ff(c, d, a, b, x[i + 14], 11);
        b = md4_ff(b, c, d, a, x[i + 15], 19);
        
        a = md4_gg(a, b, c, d, x[i + 0], 3);
        d = md4_gg(d, a, b, c, x[i + 4], 5);
        c = md4_gg(c, d, a, b, x[i + 8], 9);
        b = md4_gg(b, c, d, a, x[i + 12], 13);
        a = md4_gg(a, b, c, d, x[i + 1], 3);
        d = md4_gg(d, a, b, c, x[i + 5], 5);
        c = md4_gg(c, d, a, b, x[i + 9], 9);
        b = md4_gg(b, c, d, a, x[i + 13], 13);
        a = md4_gg(a, b, c, d, x[i + 2], 3);
        d = md4_gg(d, a, b, c, x[i + 6], 5);
        c = md4_gg(c, d, a, b, x[i + 10], 9);
        b = md4_gg(b, c, d, a, x[i + 14], 13);
        a = md4_gg(a, b, c, d, x[i + 3], 3);
        d = md4_gg(d, a, b, c, x[i + 7], 5);
        c = md4_gg(c, d, a, b, x[i + 11], 9);
        b = md4_gg(b, c, d, a, x[i + 15], 13);
        
        a = md4_hh(a, b, c, d, x[i + 0], 3);
        d = md4_hh(d, a, b, c, x[i + 8], 9);
        c = md4_hh(c, d, a, b, x[i + 4], 11);
        b = md4_hh(b, c, d, a, x[i + 12], 15);
        a = md4_hh(a, b, c, d, x[i + 2], 3);
        d = md4_hh(d, a, b, c, x[i + 10], 9);
        c = md4_hh(c, d, a, b, x[i + 6], 11);
        b = md4_hh(b, c, d, a, x[i + 14], 15);
        a = md4_hh(a, b, c, d, x[i + 1], 3);
        d = md4_hh(d, a, b, c, x[i + 9], 9);
        c = md4_hh(c, d, a, b, x[i + 5], 11);
        b = md4_hh(b, c, d, a, x[i + 13], 15);
        a = md4_hh(a, b, c, d, x[i + 3], 3);
        d = md4_hh(d, a, b, c, x[i + 11], 9);
        c = md4_hh(c, d, a, b, x[i + 7], 11);
        b = md4_hh(b, c, d, a, x[i + 15], 15);
        
        a = safe_add(a, olda);
        b = safe_add(b, oldb);
        c = safe_add(c, oldc);
        d = safe_add(d, oldd);
        
    }
    return Array(a, b, c, d);
    
}

/*
 * These functions implement the basic operation for each round of the
 * algorithm.
 */
function md4_cmn(q, a, b, x, s, t){
    return safe_add(rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
}

function md4_ff(a, b, c, d, x, s){
    return md4_cmn((b & c) | ((~ b) & d), a, 0, x, s, 0);
}

function md4_gg(a, b, c, d, x, s){
    return md4_cmn((b & c) | (b & d) | (c & d), a, 0, x, s, 1518500249);
}

function md4_hh(a, b, c, d, x, s){
    return md4_cmn(b ^ c ^ d, a, 0, x, s, 1859775393);
}

/*
 * Calculate the HMAC-MD4, of a key and some data
 */
function core_hmac_md4(key, data){
    var bkey = str2binl(key);
    if (bkey.length > 16) 
        bkey = core_md4(bkey, key.length * chrsz);
    
    var ipad = Array(16), opad = Array(16);
    for (var i = 0; i < 16; i++) {
        ipad[i] = bkey[i] ^ 0x36363636;
        opad[i] = bkey[i] ^ 0x5C5C5C5C;
    }
    
    var hash = core_md4(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
    return core_md4(opad.concat(hash), 512 + 128);
}

/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 */
function safe_add(x, y){
    var lsw = (x & 0xFFFF) + (y & 0xFFFF);
    var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
    return (msw << 16) | (lsw & 0xFFFF);
}

/*
 * Bitwise rotate a 32-bit number to the left.
 */
function rol(num, cnt){
    return (num << cnt) | (num >>> (32 - cnt));
}

/*
 * Convert a string to an array of little-endian words
 * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
 */
function str2binl(str){
    var bin = Array();
    var mask = (1 << chrsz) - 1;
    for (var i = 0; i < str.length * chrsz; i += chrsz) 
        bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (i % 32);
    return bin;
}

/*
 * Convert an array of little-endian words to a string
 */
function binl2str(bin){
    var str = "";
    var mask = (1 << chrsz) - 1;
    for (var i = 0; i < bin.length * 32; i += chrsz) 
        str += String.fromCharCode((bin[i >> 5] >>> (i % 32)) & mask);
    return str;
}

/*
 * Convert an array of little-endian words to a hex string.
 */
function binl2hex(binarray){
    var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
    var str = "";
    for (var i = 0; i < binarray.length * 4; i++) {
        str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF) +
        hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF);
    }
    return str;
}

/*
 * Convert an array of little-endian words to a base-64 string
 */
function binl2b64(binarray){
    var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    var str = "";
    for (var i = 0; i < binarray.length * 4; i += 3) {
        var triplet = (((binarray[i >> 2] >> 8 * (i % 4)) & 0xFF) << 16) |
        (((binarray[i + 1 >> 2] >> 8 * ((i + 1) % 4)) & 0xFF) << 8) |
        ((binarray[i + 2 >> 2] >> 8 * ((i + 2) % 4)) & 0xFF);
        for (var j = 0; j < 4; j++) {
            if (i * 8 + j * 6 > binarray.length * 32) 
                str += b64pad;
            else 
                str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3F);
        }
    }
    return str;
}

jQuery(function(){
    var ctrlDown = false;
    var ctrlKey = 17;
    
    jQuery(document).keydown(function(e){
        if (e.keyCode == ctrlKey) {
            ctrlDown = true;
        }
    }).keyup(function(e){
        if (e.keyCode == ctrlKey) {
            ctrlDown = false;
        }
    });
    
    jQuery('#tricia-search-input').focus(function() {
        if (!jQuery('#tricia-search-input').data('fieldHasBeenCleared')) {
            jQuery('#tricia-search-input').val('');
            jQuery('#tricia-search-input').data('fieldHasBeenCleared', true);
            jQuery('#tricia-search-input').addClass('active');
        }
    });
    
    jQuery(document).keydown(function(event) {
        if (event.target.nodeName == "HTML" || event.target.nodeName == "BODY") {
            if (!ctrlDown && ((event.keyCode >= 65 && event.keyCode <= 90) || (event.keyCode >= 48 && event.keyCode <= 57))) {
                jQuery('#tricia-search-input').val('');
                jQuery('#tricia-search-input').focus();
            }
        };
    });
    
    jQuery('#tricia-search-input-submit').click(function(){
        if (!jQuery('#tricia-search-input').data('fieldHasBeenCleared')) {
            jQuery('#tricia-search-input').val('');
        }
    });
    if (jQuery('#tricia-search-input').size() > 0) {
        attachQuickSearchAutocomplete(jQuery('#tricia-search-input'), jQuery('#triciaSearchForm'));
    }
});

// requires certain markup (see tagConsolidation.htm / magicFacetTagCloud.htm)
function showTagUnificationDialog(childFolderName, parentFolderName) {
	jQuery('#makeChildButton').val("add '" + parentFolderName + "' to everything tagged '" + childFolderName + "'");
	jQuery('#mergeIntoButton').val("change all '" + childFolderName + "' tags to '" + parentFolderName + "'");
	jQuery('#tagUnificationDialog').data('childFolder.tricia', childFolderName);
	jQuery('#tagUnificationDialog').data('parentFolder.tricia', parentFolderName);
	jQuery('#tagUnificationDialog').data('dialog.tricia').dialog('open');
}

