var commentLengthLimit = 2500;
var commentResultsPerPage = 5;

if (isIE())
    document.execCommand("BackgroundImageCache", false, true);

function setAuthoringEditParameters() {
    window.gT = null;
    var base = document.getElementsByTagName("base");
    if (base.length == 1) {
        var baseHref = base.item(0).href;
        window.bU = baseHref.substring(0, baseHref.length - 1);
    } else {
        window.bU = location.href;
        window.bU = window.bU.substring(0, window.bU.lastIndexOf('/'));
    }
    window.__com_jumpblue_editMode = true;
}

function getDotContainerById(id) {
    return $("dot" + id);
}

function iframeEdit(id,
                    title,
                    note,
                    tags,
                    permissionsLevel,
                    starRating,
                    category,
                    url,
                    imageUrl,
                    imageWidth,
                    imageHeight) {

    setAuthoringEditParameters();

    var dot = new Dot();

    dot.setId(id);
    dot.setSubject(unescape(title));
    dot.setContent(unescape(note));
    dot.setTags(unescape(tags));
    dot.setPermissions(permissionsLevel);
    dot.setRating(starRating);
    dot.setCategory(category);
    dot.setUrl(unescape(url));
    dot.setImageUrl(unescape(imageUrl));
    dot.setImageWidth(imageWidth);
    dot.setImageHeight(imageHeight);

    showInlineAuthoringDialog(dot);

}

function edit(id) {

    setAuthoringEditParameters();

    var dotContainer = getDotContainerById(id);

    var dot = loadDotFromContainer(dotContainer);

    showInlineAuthoringDialog(dot);

}

function deleteDot(id) {

    // Prevent duplicate clicks.
    this.onclick = Prototype.emptyFunction;

    if (confirm("Are you sure you want to delete this Fave?")) {

        new Ajax.Request("DeleteDot.ashx?id=" + id,
                         { method: "post",
                           onComplete: deleteComplete });

    }

    return false;
}

function deleteComplete(request) {
    refreshPagePreserveContext(true);
}

function refreshPagePreserveContext(force) {

    var clusteredPagingForm = getClusteredPagingForm(document);

    // This is messy because it deals with legacy paths.
    if (force && clusteredPagingForm) {
        clusteredPagingForm.submit();
    } else if (clusteredPagingForm &&
               clusteredPagingForm.action.indexOf("/friends") == -1 &&
               (clusteredPagingForm.action.indexOf("/dots") != -1 ||
                (clusteredPagingForm.action.toLowerCase().indexOf("default.aspx") != -1 &&
                 clusteredPagingForm.action.indexOf("mode=stream") != -1))) {
        // Keep page.
        clusteredPagingForm.submit();
    } else if (location.href.indexOf("/dot/") != -1) {
        // Back to the top.
        location.href =
            location.href.substr(0, location.href.indexOf("/dot/"));
    }
}

function getClusteredPagingForm(doc) {

    var clusteredPagingForm = null;

    if (doc.forms) {
        for (var i = 0; i < doc.forms.length; i++) {
            var form = doc.forms.item(i);
            if (form.method == "post") {
                var inputs = form.getElementsByTagName("input");
                if (inputs.length >= 1 && inputs[0].name == "pi") {
                    clusteredPagingForm = form;
                    break;
                }
            }
        }
    }

    return clusteredPagingForm;
}

function dotThis(id) {

    setAuthoringEditParameters();

    var dotContainer = getDotContainerById(id);

    var dot = loadDotFromContainer(dotContainer);

    // Not editing.
    dot.setId(null);

    dot.setContent("");

    // No auto subject.
    if (dot.getSubject() == null) {
        dot.setSubject("");
    }

    // Use defaults for these fields.
    dot.setRating(0);
    dot.setPermissions(0);

    showInlineAuthoringDialog(dot);

}

function joinSwap(index) {
    var anchors = $("joinnow").getElementsByTagName("a");
    var messages = $("joinnow").getElementsByTagName("div");
    for (var i = 0; i < 4; i++) {
        anchors.item(i).className = (i == index ? "selected" : "");
        var message = messages.item(i + 1);
        if (i == index) {
            message.style.display = "";
            message.parentNode.style.backgroundPosition =
                "0 -" + (i * 220) + "px";
        } else {
            message.style.display = "none";
        }
    }
}

/**
 * Adds tooltips and clickthrough handlers to dots.
 */
function hookupDots() {

    var dotsContainer = document.getElementById("dots");
    if (dotsContainer) {

        var dotLists = dotsContainer.getElementsByTagName("ul");

        for (var i = 0; i < dotLists.length; i++) {

            var dotList = dotLists.item(i);

            // Add paging controls in friend view if applicable.
            var dotListParent = dotList.parentNode;
            if (dotListParent.className == "friendsDotListHeader") {

                var dotCountDiv =
                    findChildElementByClass(dotListParent, "div", "counts");

                var previous = document.createElement("a");
                previous.href = "JavaScript:previousDot()";
                previous.onclick = previousDot;
                previous.className = "previousDot";

                // Begin in disabled state.
                disableButton(previous);

                dotCountDiv.appendChild(previous);

                var next = document.createElement("a");
                next.href = "JavaScript:nextDot()";
                next.onclick = nextDot;
                next.className = "nextDot";

                // Only one fave? Parse the 'n of n Faves' string.
                if (dotCountDiv.firstChild.nodeValue.split(" ")[2] == "1") {
                    disableButton(next);
                }

                dotCountDiv.appendChild(next);
            }

            var dots = dotList.getElementsByTagName("li");
            for (var j = 0; j < dots.length; j++) {
                var dot = dots[j];
                if (dot) {
                    hookupDot(dot);
                }
            }
        }
    }
}

function hookupDot(dot) {

    if (dot.hookedUp) {
        return;
    }

    // Title clickthrough handler.
    var dotLink =
        findChildElementByClass(dot, "a", "d");
    if (dotLink) {
        dotLink.onmousedown = titleClickthroughHandler;
    }

    // Image clickthrough handler.
    var dotImage = getDotImageFromContainer(dot);
    if (dotImage && !(dotImage.parentNode.className == "ctp")) {
        dotImage.parentNode.onmousedown = imageClickthroughHandler;
    }

    // Permissions.
    var permissionsElement =
        findChildElementByClass(dot, "input", "p");
    if (permissionsElement != null) {
        // Found permissions element.
        var permissions = permissionsElement.value;
        if (permissions && dotLink) {
            dotLink.title = buildPermissionsTooltip(permissions);
        }
    }

    dot.hookedUp = true;
}

function nextDot(evt) {
    return handleDotScroll(evt, 1);
}

function previousDot(evt) {
    return handleDotScroll(evt, -1);
}

function handleDotScroll(evt, direction) {

    var src = evt ? evt.currentTarget : (window.event ? window.event.srcElement : null);
    if (!src || src.disabled) {
        return;
    }

    var container =
        src.parentNode.parentNode.parentNode.getElementsByTagName("ul")[0];

    // Initialize to the first element.
    if (!container.index) {
        container.index = 0;
    }

    container.index += direction;

    var children =
        $A(container.getElementsByTagName("li")).findAll(isDotListItem);

    if (container.index < 0) {
        container.index = 0;
    }

    if (container.index < children.length) {
        updateCurrentDotDisplay(container);
    } else {

        var handler = new DotScrollRequestHandler(container);

        var login = getLoginFromDotContainer(container);

        var lastDotId =
            loadDotFromContainer(children[children.length - 1]).getId();

        src.className = "nextDotLoading";
        src.disabled = true;

        var currentSearch = null;

        var qsIndex = document.location.href.indexOf("?");
        if (qsIndex != -1) {
            currentSearch =
                document.location.href.substring(qsIndex).toQueryParams().st;
        }

        new Ajax.Request("UserDotList.ashx?user=" + login +
                         "&lastDotId=" + lastDotId +
                         (currentSearch ? "&st=" + currentSearch : ""),
                         { method: "post",
                           onComplete: handler.onComplete,
                           onException: exceptionHandler });
    }

    return false;
}

function isDotListItem(item) {
    // Dot containers have ID attributes.
    return Element.hasClassName(item.parentNode, "dotList");
}

function findNextButton(container) {
    return findButton(container, /^next/);
}

function findPreviousButton(container) {
    return findButton(container, /^prev/);
}

function findButton(container, rx) {
    var buttons = container.getElementsByTagName("a");
    for (var i = 0; i < buttons.length; i++) {
        if (buttons.item(i).className.search(rx) == 0) {
            return buttons.item(i);
        }
    }
}

function updateCurrentDotDisplay(container) {

    var friendViewDiv = container.parentNode;

    var nextButton = findNextButton(friendViewDiv);

    var children =
        $A(container.getElementsByTagName("li")).findAll(isDotListItem);

    var countDiv =
        findChildElementByClass(friendViewDiv, "div", "counts");

    var countParsed = countDiv.firstChild.nodeValue.split(" ");

    // If we couldn't get enough dots to reach the count, get out.
    if (container.index >= children.length) {
        disableButton(nextButton);
        return;
    }

    countParsed[0] = container.index + 1;
    countDiv.firstChild.nodeValue = countParsed.join(" ");

    var isLastDot = false;

    // Strip commas and parse number.
    var topCount = parseInt(countParsed[2].split(",").join(""));
    if (container.index > 0 &&
        ((container.index + 1) == topCount)) {
        isLastDot = true;
    }

    var previousButton = findPreviousButton(container.parentNode);
    if (container.index == 0) {
        disableButton(previousButton);
    } else {
        enableButton(previousButton);
    }

    if (container.index > 0) {
        Element.hide(children[container.index - 1]);
    }

    for (var i = container.index + 1; i < children.length; i++) {
        Element.hide(children[i]);
    }

    var dotContainer = children[container.index];
    if (!dotContainer.hookedUp) {
        hookupDot(dotContainer);
    }

    // If a video was playing, and we go back, it restarts. Somewhat
    // annoying.
    destroyInlineVideoPlayer(dotContainer);

    Element.show(dotContainer);

    if (isLastDot) {
        disableButton(nextButton);
    } else {
        enableButton(nextButton);
    }
}

function destroyInlineVideoPlayer(container) {
    var videoBucket =
        findChildElementByClass(container, "div", "videoBucket");
    if (videoBucket) {
        Element.remove(videoBucket);
        Element.show(findChildElementByClass(container, "a", "ctp"));
    }
}

function removeDescendants(element, predicate) {
    if (element.hasChildNodes()) {
        for (var i = 0; i < element.childNodes; i++) {
            var child = element.childNodes.item(i);
            if (!predicate || predicate(element)) {
                element.removeChild(child);
            } else {
                removeDescendants(child, predicate);
            }
        }
    }
}

function enableButton(button) {

    var isPrevious =
        button.className.search(/^previous/) == 0;

    // IE has trouble with two class selectors, hence this mess
    // (vs. add "disabled").
    if (isPrevious) {
        button.className = "previousDot";
    } else {
        button.className = "nextDot";
    }

    button.disabled = false;
}

function disableButton(button) {

    var isPrevious =
        button.className.search(/^previous/) == 0;

    if (isPrevious) {
        button.className = "previousDotDisabled";
    } else {
        button.className = "nextDotDisabled";
    }

    button.disabled = true;
}

function exceptionHandler(element, exception) {
    if (document.location.href.indexOf("http://localhost") == 0) {
        alert(exception);
        throw exception;
    }
}

function DotScrollRequestHandler(container) {

    this.onComplete = function(request) {

        var pseudoDiv = document.createElement("div");
        pseudoDiv.innerHTML = request.responseText;

        // Copy the HTML-ized items.
        var listItems = pseudoDiv.getElementsByTagName("li");
        var dotId;

        for (var i = 0; i < listItems.length; i++) {
            container.appendChild(listItems.item(i).cloneNode(true));

            dotId = listItems.item(i).id.substring(3);
            eval($("script:" + dotId).innerText);
        }

        // Enable the next button again.
        var nextButton = findNextButton(container.parentNode);
        enableButton(nextButton);
        nextButton.className =
            nextButton.className.replace(/Loading/, "");

        updateCurrentDotDisplay(container);
    }

}

function showDots(id, useWaterfall) {

    var dotContainer = getDotContainerById(id);

    updateShowHideDotsLink(dotContainer);

    var dot = loadDotFromContainer(dotContainer);

    var iframe = document.createElement("iframe");
    var iframeSrc = "UrlDotsMini.aspx?u=" + encodeURIComponent(dot.getUrl());

    if (useWaterfall) {
        iframeSrc += "&w=1";
    }

    // Pass the search text.
    var searchText = getSearchTermsFromMetaSection();

    if (searchText) {
        iframeSrc += "&st=" + searchText;
    }
    iframe.src = iframeSrc;
    iframe.frameBorder = "no"; // IE

    dotContainer.appendChild(iframe);
}

function hideDots(id) {

    var dotContainer = getDotContainerById(id);

    updateShowHideDotsLink(dotContainer);

    dotContainer.removeChild(dotContainer.getElementsByTagName("iframe")[0]);
}

function getSearchTermsFromMetaSection() {
    var searchTerms = "";
    var metas = document.getElementsByTagName("meta");
    for (var i = 0; i < metas.length; i++) {
        var meta = metas.item(i);
        if (meta.name == "searchTerms") {
            searchTerms = meta.content;
            break;
        }
    }

    return searchTerms;
}

function updateShowHideDotsLink(dotContainer) {

    // Change the button.
    var linksContainer =
        findChildElementByClass(dotContainer, "div", "links");

    var link = $A(linksContainer.getElementsByTagName("a")).detect(function(l) {
        return l.href.indexOf("Dots") != -1;
    });

    var linkText = link.firstChild;

    // Update link and link text.
    if (link.href.indexOf("show") >= 0) {
        link.href = link.href.replace(/show/, "hide");
        linkText.nodeValue = linkText.nodeValue.replace(/Show/, "Hide");
    } else {
        link.href = link.href.replace(/hide/, "show");
        linkText.nodeValue = linkText.nodeValue.replace(/Hide/, "Show");
    }
}

function updateCommentLink(dotContainer) {

    var linksContainer =
        findChildElementByClass(dotContainer, "div", "links");

    var links = linksContainer.getElementsByTagName("a");
    for (var i = 0; i < links.length; i++) {
        var link = links.item(i);
        if (link.href.indexOf("showComments") >= 0) {
            link.href = link.href.replace(/show/, "hide");
            link.firstChild.nodeValue =
                link.firstChild.nodeValue.replace(/Show/, "Hide");
            break;
        } else if (link.href.indexOf("hideComments") >= 0) {
            link.href = link.href.replace(/hide/, "show");
            link.firstChild.nodeValue =
                link.firstChild.nodeValue.replace(/Hide/, "Show");
            break;
        }
    }
}

function showComments(id) {

    var container = getDotContainerById(id);
    var o;

    updateCommentLink(container);

    // If there's already a comment div, show, otherwise fetch.
    var commentDiv =
        findChildElementByClass(container,
                                "div",
                                "comments");

    if (commentDiv != null) {

        if (isIE()) {
            o = container.nextSibling;

            while (o) {
                o.style.position = "static";
                o = o.nextSibling;
            }
        }

        Element.show(commentDiv);

        if (isIE()) {
            o = container.nextSibling;
            
            while (o) {
                o.style.position = "relative";
                o = o.nextSibling;
            }
        }

    } else {

        // Fetch the comment list.
        new Ajax.Request("GetComments.ashx?" +
                         "login=" + getLoginFromDotContainer(container) +
                         "&results=" + commentResultsPerPage +
                         "&id=" + id,
                         { method: "post",
                           onComplete: gotComments });
    }
}

function gotComments(request) {

    if (request.status == 200) {

        var responseXml = request.responseXML;

        var userCanComment =
            responseXml.firstChild.getAttribute("userCanComment") == "true";

        var id =
            responseXml.firstChild.getAttribute("uid") + '.' +
            responseXml.firstChild.getAttribute("id");

        var container = getDotContainerById(id);
        var o;

        var commentDiv =
            findChildElementByClass(container, "div", "comments");

        if (isIE()) {
            o = container.nextSibling;

            while (o) {
                o.style.position = "static";
                o = o.nextSibling;
            }
        }

        if (commentDiv) {
            Element.remove(commentDiv);
        }

        commentDiv = document.createElement("div");
        commentDiv.className = "comments";

        var currentPage =
            parseInt(responseXml.firstChild.getAttribute("page"));

        commentDiv.page = currentPage;

        var commentCount =
            parseInt(responseXml.firstChild.getAttribute("count"));

        var linksContainer =
            findChildElementByClass(container, "div", "links");

        var showingMin = Math.max((currentPage * commentResultsPerPage) -
                                  (commentResultsPerPage - 1), 0);
        var showingMax = Math.min(currentPage * commentResultsPerPage,
                                  commentCount);

        // Update the link, e.g. Add Comment -> 1 Comment (Hide), 2
        // Comments (Hide) -> 3 Comments (Hide).
        var showHideCommentsLink = $A(linksContainer.getElementsByTagName("a")).detect(function(l) {
            return l.href.indexOf("Comments") != -1;
        });

        if (commentCount == 0 && showHideCommentsLink) {
            showHideCommentsLink.firstChild.nodeValue = "Add Comment";
        } else {
            if (showHideCommentsLink) {
                showHideCommentsLink.firstChild.nodeValue =
                    commentCount + " Comment" + (commentCount > 1 ? "s" : "") + " (Hide)";
            }

            // Paging.
            if (commentCount > commentResultsPerPage) {

                var paging = commentDiv.appendChild(document.createElement("div"));
                paging.className = "paging";

                var previous = paging.appendChild(document.createElement("a"));
                previous.href = "#";
                previous.className = "previousComments";
                Event.observe(previous, "click", previousComments.bindAsEventListener());
                if (showingMin == 1) {
                    previous.className += "Disabled";
                }

                var next = paging.appendChild(document.createElement("a"));
                next.href = "#";
                next.className = "nextComments";
                Event.observe(next, "click", nextComments.bindAsEventListener());
                if (commentCount <= showingMax) {
                    next.className += "Disabled";
                }

            }

            if (commentCount > 0) {
                var showing = responseXml.firstChild.getAttribute("pagingLabel");
                commentDiv.appendChild(document.createElement("strong")).appendChild(document.createTextNode(showing));
            }
        }

        container.appendChild(commentDiv);

        if (responseXml.firstChild.firstChild) {
            // No comments means no data.
            new Insertion.Bottom(commentDiv, getElementText(responseXml.firstChild));
        }

        if (showingMax == commentCount) {
            if (userCanComment) {
                appendAddCommentWidgets(commentDiv, commentCount == 0);
            }
        }

        if (isIE()) {
            o = container.nextSibling;

            while (o) {
                o.style.position = "relative";
                o = o.nextSibling;
            }
        }        
    } else {
        alert("Failed to retrieve comments.");
    }

}

function previousComments(event) {

    var e = Event.element(event);

    if (e.className != "previousCommentsDisabled" &&
        e.className != "previousCommentsLoading") {

        e.className = "previousCommentsLoading";

        scrollComments(e, -1);
    }

    Event.stop(event);

    return false;
}

function nextComments(event) {

    var e = Event.element(event);

    if (e.className != "nextCommentsDisabled"&&
        e.className != "nextCommentsLoading") {

        e.className = "nextCommentsLoading";

        scrollComments(e, 1);
    }

    Event.stop(event);

    return false;
}

function scrollComments(e, direction) {

    var commentDiv = e;
    while (commentDiv = commentDiv.parentNode) {
        if (commentDiv.nodeName.toUpperCase() == "DIV" &&
            commentDiv.className == "comments") {
            break;
        }
    }

    commentDiv.page = parseInt(commentDiv.page) + direction;

    var id = getDotIdForElement(commentDiv);
    var container = getDotContainerById(id);

    new Ajax.Request("GetComments.ashx?" +
                     "login=" + getLoginFromDotContainer(container) +
                     "&id=" + id +
                     "&results=" + commentResultsPerPage +
                     "&page=" + commentDiv.page,
                     { method: "post",
                       onComplete: gotComments });
}

function hideComments(id) {

    var container = getDotContainerById(id);
    var o;

    var commentDiv =
        findChildElementByClass(container,
                                "div",
                                "comments");

    if (isIE()) {
        o = container.nextSibling;

        while (o) {
            o.style.position = "static";
            o = o.nextSibling;
        }
    }

    if (commentDiv) {
        updateCommentLink(container);
        Element.hide(commentDiv);
    }

    if (isIE()) {
        o = container.nextSibling;
        
        while (o) {
            o.style.position = "relative";
            o = o.nextSibling;
        }
    }
}

function appendAddCommentWidgets(parent, focus) {

    var form = parent.appendChild(document.createElement("form"));
    form.action = "#";

    var fieldset = form.appendChild(document.createElement("fieldset"));

    var id = "addComment" + getDotIdForElement(parent);

    var title = fieldset.appendChild(document.createElement("label"));
    title.appendChild(document.createTextNode("Add Comment"));
    title.setAttribute("for", id);

    var textArea = fieldset.appendChild(document.createElement("textarea"));
    textArea.id = id;
    textArea.className = "addComment";

    var submit = document.createElement("input");
    submit.type = "submit";
    submit.value = "Add Comment";

    Event.observe(submit, "click", addComment.bindAsEventListener());

    fieldset.appendChild(submit);

    if (focus) {
        textArea.focus();
    }
}

function addComment(event) {

    var form = Event.findElement(event, "form");

    // Get trimmed comment text.
    var commentInput = form.getElementsByTagName("textarea").item(0);
    var commentText = commentInput.value.trim();

    if (commentText.length == 0) {
        alert("Please enter a comment.");
        commentInput.focus();
    } else {

        if (commentText.length <= commentLengthLimit ||
            confirm("The comment text is too long, click OK to publish a partial comment.")) {

            var src = Event.element(event);

            src.disabled = true;

            var id = getDotIdForElement(src);
            var container = getDotContainerById(id);

            var postBody =
                "login=" + getLoginFromDotContainer(container) +
                "&id=" + id +
                "&results=" + commentResultsPerPage +
                "&commentText=" +
                encodeURIComponent(commentText.substring(0,
                                                         Math.min(commentText.length, commentLengthLimit)));

            // Kick it off.
            new Ajax.Request("AddComment.ashx",
                             { method: "post",
                               onComplete: gotComments,
                               postBody: postBody });
        }
    }

    Event.stop(event);

    return false;
}

function editComment(link) {

    var commentListItem = link;
    while (commentListItem.nodeName.toUpperCase() != "LI") {
        commentListItem = commentListItem.parentNode;
    }

    var forms = commentListItem.getElementsByTagName("form");
    if (forms.length == 0) {

        var commentDiv = findChildElementByClass(commentListItem, "div", "comment");
        $A(commentDiv.childNodes).each(function(c) {
            Element.hide(c);
        });

        // Translate comment text to form field.
        var textarea = commentDiv.appendChild(document.createElement("textarea"));
        textarea.appendChild(document.createTextNode(getCommentText(commentListItem)));

        var submitEdit = document.createElement("input");
        submitEdit.type = "button";
        submitEdit.value = "Save";
        Event.observe(submitEdit, "click", function() {
            var commentText = textarea.value.trim();
            if (commentText.length == 0) {
                alert("Please enter a comment.");
                textarea.focus();
            } else {

                if (commentText.length <= commentLengthLimit ||
                    confirm("The comment text is too long, click OK to publish a partial comment.")) {

                    var dotId = getDotIdForElement(commentDiv);
                    var container = getDotContainerById(dotId);
                    var postBody =
                        "login=" + getLoginFromDotContainer(container) +
                        "&id=" + dotId +
                        "&commentId=" + commentListItem.id.substring(commentListItem.id.indexOf('.') + 1) +
                        "&page=" + commentListItem.parentNode.parentNode.page +
                        "&results=" + commentResultsPerPage +
                        "&commentText=" + encodeURIComponent(commentText.substring(0,
                                                                                   Math.min(commentText.length, commentLengthLimit)));

                    new Ajax.Request("EditComment.ashx",
                                     { method: "post",
                                       onComplete: gotComments,
                                       postBody: postBody });
                }
            }
        });

        var cancel = document.createElement("input");
        cancel.type = "button";
        cancel.value = "Cancel";
        Event.observe(cancel, "click", function() {
            $A(commentDiv.childNodes).each(function(c) {
                var nn = c.nodeName.toUpperCase();
                if (nn == "P" || nn == "BLOCKQUOTE") {
                    Element.show(c);
                } else {
                    Element.remove(c);
                }
            });
        });

        commentDiv.appendChild(submitEdit);
        commentDiv.appendChild(cancel);
    }

    return false;
}

function getCommentText(commentContainer) {
    var commentText = "";
    var ps = commentContainer.getElementsByTagName("p");
    for (var i = 0; i < ps.length; i++) {
        commentText += getNoteNodeValue(ps.item(i));
        if (i < ps.length - 1) {
            commentText += "\r\r";
        }
    }
    return commentText;
}

function deleteComment(link) {

    if (confirm("Are you sure you want to delete this comment?")) {

        var dotId = getDotIdForElement(link);
        var container = getDotContainerById(dotId);
        var login = getLoginFromDotContainer(container);

        var commentContainer = getCommentContainerForElement(link);

        var commentId =
            commentContainer.id.substring(commentContainer.id.indexOf('.') + 1);

        var postBody =
            "login=" + login +
            "&id=" + dotId +
            "&commentId=" + commentId +
            "&results=" + commentResultsPerPage;

        new Ajax.Request("DeleteComment.ashx",
                         { method: "post",
                           onComplete: gotComments,
                           postBody: postBody });
    }

    return false;
}

function getCommentContainerForElement(element) {

    var e = element;
    while (e = e.parentNode) {
        if (e.nodeName.toUpperCase() == "LI") {
            break;
        }
    }

    return e;
}

function buildPermissionsTooltip(permissions) {

    var tooltip = null;

    if (permissions == "0") {
        tooltip = "This Fave is available to all Fave users.";
    } else if (permissions == "1") {
        tooltip = "This Fave is available to your friends.";
    } else if (permissions == "2") {
        tooltip = "This Fave is private.";
    } else {
        // Subcommunity.
        var subgroup = permissions.substring(2, permissions.length);
        var groupName = getGroupName(subgroup);
        if (groupName == null) {
            // Deleted group.
            tooltip = "This Fave is private.";
        } else {
            tooltip =
                "This Fave is available to members of the " +
                groupName + " friend list.";
        }
    }

    return tooltip;
}

function getGroupName(groupId) {

    var groupName = null;

    for (var i = 0; i < __com_jumpblue_groups.length; i++) {
        var currentGroup = __com_jumpblue_groups[i];
        if (currentGroup.id == groupId) {
            groupName = decodeURIComponent(currentGroup.name);
            break;
        }
    }

    return groupName;
}

/**
 * Loads dot information from its containing element.
 */
function loadDotFromContainer(container) {

    var dot = new Dot();

    // [uidfrom].[dotid].
    dot.setId(container.id.substring(container.id.indexOf('.') + 1));

    // <a class="d" href="...">title</a>
    var link = getDotLinkFromContainer(container);

    // It's important to use getAttribute here -- and in IE, it's
    // especially important to use this second argument (IE specific),
    // which instructs it to retrieve the _exact_ value (by default it
    // ignores DOM and retrieves the actual value). IE has a bug in
    // parsing the URL where %23 (decodes to '#') appears in the path
    // -- it's treated as a hash, even though it should not be
    // decoded. See bug 2245 for details.
    dot.setUrl(link.getAttribute("href", 2));

    // In some cases, the link may have been modified by the
    // clickthrough magic before we suck it up here. Fix it.
    var url = dot.getUrl();
    if (url.length > 11 &&
        url.substring(0, 11) == "Out.ashx?u=") {
        dot.setUrl(unescape(url.substring(11, url.lastIndexOf("&d="))));
    }

    // Check for original URL, if present the URL we picked up is
    // actually an affiliate URL.
    var originalUrlElement =
        findChildElementByClass(container, "input", "ou");
    if (originalUrlElement != null) {
        dot.setAffiliateUrl(dot.getUrl());
        dot.setUrl(originalUrlElement.value);
    }

    dot.setSubject(link.firstChild.nodeValue);
    if (dot.getSubject() == dot.getUrl()) {
        dot.setSubject("");
    }

    // Permissions.
    var permissionsElement =
        getPermissionsElementFromContainer(container);
    if (permissionsElement) {
        dot.setPermissions(permissionsElement.value);
    }

    var images = container.getElementsByTagName("img");

    // Stars.
    var starImage = getStarImageFromContainer(container);

    if (starImage) {
        dot.setRating(starImage.alt.substring(0, 1));
    }
    
    // find the tags anchor, tags are siblings of the user link
    var tagsAnchor = findChildElementByClass(container, "a", "g");

    // if there isn't an a there will be an em
    if (tagsAnchor == null) {
        tagsAnchor = findChildElementByClass(container, "em", "g");
    }

    if (tagsAnchor) {
        var tags = [];
        for (var node = tagsAnchor.nextSibling; node; node = node.nextSibling) {
            if (node.nodeName.toUpperCase() == "A") {
                tags.push(node.firstChild.nodeValue);
            }
        }

        dot.setTags(tags.join(", "));
    }

    var dotImage = getDotImageFromContainer(container);
    if (dotImage) {
        // Dot has image.
        dot.setImageUrl(dotImage.src);
        dot.setImageWidth(dotImage.width);
        dot.setImageHeight(dotImage.height);
    }

    // Load content.
    var noteDiv = findChildElementByClass(container, "div", "note");

    if (noteDiv) {

        // May not have a note text node.
        var content = getNoteText(noteDiv);
        if (content) {
            if (content.length > 7 && content.substring(0, 7).toUpperCase() == "QUOTED:") {
                content = "\r\n\r\n" + content;
            }
            dot.setContent(content);
        }
    }

    return dot;
}

function getDotLinkFromContainer(container) {
    return findChildElementByClass(container, "a", "d");
}

function getLoginFromDotContainer(container) {
    return findChildElementByClass(container, "a", "user").firstChild.nodeValue;
}

function getPermissionsElementFromContainer(container) {
    return findChildElementByClass(container, "input", "p");
}

function getStarImageFromContainer(container) {
    return findChildElementByClass(container, "img", "stars");
}

/**
 * Load note text from div.
 */
function getNoteText(noteDiv) {

    var noteText = "";

    // note: object? (p|quoted)+
    // quoted: blockquote p
    var noteChildren = noteDiv.childNodes;
    for (var i = 0; i < noteChildren.length; i++) {
        // Skip the links, image.
        var noteChild = noteChildren[i];
        var nodeName = noteChild.nodeName.toUpperCase();
        if (nodeName != "P" && nodeName != "BLOCKQUOTE") {
            continue;
        }
        for (var node = noteChildren[i].firstChild; node; node = node.nextSibling) {
            // Look for text node or break, ignore all others
            // (e.g. affiliate images).
            noteText += getNoteNodeValue(node);
        }
        if (i < noteChildren.length - 1) {
            noteText += "\r\n\r\n";
        }
    }

    return noteText;
}

function getNoteNodeValue(node) {

    var nodeValue;

    var upperCaseNode = node.nodeName.toUpperCase();

    if (node.nodeType == 3) {
        nodeValue = node.nodeValue;
    } else if (upperCaseNode == "BR") {
        // <br/>
        nodeValue = "\r";
    } else if (upperCaseNode == "P" || upperCaseNode == "A") {
        // <blockquote><p>...
        nodeValue = "";
        for (var childNode = node.firstChild; childNode; childNode = childNode.nextSibling) {
            nodeValue += getNoteNodeValue(childNode);
        }
    }

    return nodeValue;
}

function findChildElementByClass(parent, elementName, className) {

    var childElement = null;

    var children = parent.getElementsByTagName(elementName);
    inner: for (var i = 0; i < children.length; i++) {
        var currentElement = children.item(i);
        var classAttribute = currentElement.className;
        if (classAttribute) {
            var classes = classAttribute.split(" ");
            for (var j = 0; j < classes.length; j++) {
                if (classes[j] == className) {
                    childElement = currentElement;
                    break inner;
                }
            }
        }
    }

    return childElement;
}

function showInlineAuthoringDialog(dot) {

    // Show the standard dialog.
    var scriptLoader = new ScriptLoader();

    scriptLoader.beginLoad("js/Authoring.js");

    scriptLoader.onGlobalScriptElement("__com_jumpblue_authoring",
                                       showInlineAuthoringDialog2,
                                       dot);
}

function showInlineAuthoringDialog2(dot) {

    var authoringDialog = __com_jumpblue_dialog;

    var imageUrl = dot.getImageUrl();

    authoringDialog.setExistingPicture(
        isNullOrEmpty(imageUrl) ? null : unescape(imageUrl),
        dot.getImageWidth(),
        dot.getImageHeight());
    
    DotPublisher.addPublishCompleteListener(publishComplete);

    authoringDialog.main();

    // Set elements based on dot values.
    var dotId = dot.getId();
    if (dotId && dotId != 0) {
        authoringDialog.getElementById("dotId").value = dot.getId();
    }

    var title = dot.getSubject();
    if (title) {
        authoringDialog.getElementById("title").value = unescape(title);
    }

    var note = dot.getContent();
    if (note || note == "") {
        authoringDialog.getElementById("note").value = unescape(note);
    }

    var tags = dot.getTags();
    if (tags) {
        authoringDialog.getElementById("tags").value = unescape(tags);
    }

    var permissionsLevel = dot.getPermissions();
    if (permissionsLevel) {
        authoringDialog.getElementById("permissionsLevel").value = permissionsLevel;
    }

    var rating = dot.getRating();
    if (rating) {
        authoringDialog.setStarRating(rating);
    }

    var category = dot.getCategory();
    if (category) {
        authoringDialog.getElementById("category").value = category;
    }

    var url = dot.getUrl();
    if (url) {
        authoringDialog.setUrl(url);
    }

    // TODO: ?
    var from = null;
    if (from) {
        authoringDialog.setDotCreationFlag(from);
    }
}

function publishComplete(success, dotId, dotHtml) {

    if (success) {

        var dummy = document.createElement("div");
        dummy.innerHTML = decodeURIComponent(dotHtml);

        var container = getDotContainerById(dotId);

        if (container) {

            // Keep any ad frames.
            var ads = container.getElementsByTagName("div");
            for (var i = 0; i < ads.length; i++) {
                var ad = ads.item(i);
                if (ad.id && (ad.id == "adPlacement1" || ad.id == "adPlacement2")) {
                    dummy.insertBefore(ad, dummy.firstChild);
                }
            }

            // Copy user image if it exists ...
            var userImage = findChildElementByClass(container, "a", "pl");
            if (userImage) {
                dummy.insertBefore(userImage,
                                   dummy.firstChild);
            }

            container.innerHTML = dummy.innerHTML;

            // Reset.
            container.hookedUp = false;

            if ($("script:" + dotId)) {
                eval($("script:" + dotId).innerText);
            }

            hookupDot(container);
        }
    }

}

function getClusterLink(container) {
    var clusterLink = null;
    var links = container.getElementsByTagName("a");
    for (var i = 0; i < links.length; i++) {
        if (links.item(i).firstChild.nodeValue.charAt(2) == "D") {
            clusterLink = links.item(i);
            break;
        }
    }
    return clusterLink;
}

function getDotImageFromContainer(container) {

    var dotImage = null;
    var images = container.getElementsByTagName("img");
    
    for (var i = 0; i < images.length; i++) {

        var currentImage = images[i];
        
        if (currentImage.className == "thumbnail") {
            dotImage = currentImage;
            break;
        }
    }

    if (dotImage) {
        return dotImage;
    }

    var imageLink = findChildElementByClass(container, "a", "dot");

    if (imageLink == null) {
        return;
    }

    dotImage = new Image();
    dotImage.src = imageLink.style.backgroundImage.replace("url(", "").replace(")", "");

    return dotImage;
}

function titleClickthroughHandler() {
    return clickthroughHandler(this, "title");
}

function imageClickthroughHandler() {
    return clickthroughHandler(this, "img");
}

function destroyShareContainer() {
    var sc = $("shareContainer");
    if (sc) {
        sc.parentNode.removeChild(sc);
    }
    document.body.onmousedown = "";
}

function cancelDestroyShareContainer(e) {
    Event.stop(e);
}

function scheduleDestroyShareContainer(e) {
    setTimeout("destroyShareContainer();", 10);
}

function moreMenu(id) {

    var shareContainer = $("shareContainer");
    if (shareContainer) {
        shareContainer.parentNode.removeChild(shareContainer);
        return;
    }

    shareContainer = document.createElement("div");
    shareContainer.id = "shareContainer";
    shareContainer.className = "shareContainer";

    var dotThis = shareContainer.appendChild(createDotThisLink(id));
    dotThis.onclick = scheduleDestroyShareContainer;

    var container = getDotContainerById(id);
    ["email", "permalink"].each(function(className) {
            var e = findChildElementByClass(container, "a", className);
            if (e) {
                shareContainer.appendChild(e.cloneNode(true)).style.display = "";
            }
        });

    var moreLink = findChildElementByClass(container, "a", "more");
    var offset = Position.cumulativeOffset(moreLink);

    with (shareContainer.style) {
        left = offset[0] + "px";
        top = (offset[1] + moreLink.offsetHeight - 1) + "px";
    }

    document.body.onmousedown = destroyShareContainer;
    shareContainer.onmousedown = cancelDestroyShareContainer.bindAsEventListener();
    moreLink.onmousedown = cancelDestroyShareContainer.bindAsEventListener();

    document.body.appendChild(shareContainer);
}

function createDotThisLink(id) {
    var a = document.createElement("a");
    a.className = "dotthis";
    a.href = "JavaScript:dotThis('" + id + "')";
    a.appendChild(document.createTextNode("Fave It!"));
    return a;
}

function createEmailThisLink(id) {
    var a = document.createElement("a");
    a.className = "email";
    a.href = "EmailDot.aspx?id=" + id.substring(id.indexOf('.') + 1);
    a.appendChild(document.createTextNode("Email This"));
    return a;
}

function createTab(text) {
    var tab = document.createElement("div");
    tab.className = "tab";
    tab.appendChild(document.createTextNode(text));
    return tab;
}

function getShareLinkById(id) {
    var container = getDotContainerById(id);
    return findChildElementByClass(container, "a", "share") || findChildElementByClass(container, "a", "shared");
}

function unshare(id) {

    var shareLink = getShareLinkById(id);

    if (shareLink && -1 != shareLink.className.indexOf("shared")) {
        new Ajax.Request("Share.ashx?mode=remove&id=" + id,
                         { onComplete: shareComplete });
    }
}

function share(id) {

    var shareLink = getShareLinkById(id);

    if (shareLink && Element.hasClassName(shareLink, "share")) {

        new Ajax.Request("Share.ashx?id=" + id,
                         { onComplete: shareComplete });
    }
}

function shareComplete(request) {
    if (request.status == 200) {

        var responseXml = request.responseXML;

        var sharedLink = getShareLinkById(responseXml.firstChild.getAttribute("id"));

        if (Element.hasClassName(sharedLink, "shared")) {
            sharedLink.href = sharedLink.href.replace(/unshare/, "share");
            Element.removeClassName(sharedLink, "shared");
            Element.addClassName(sharedLink, "share");
            sharedLink.innerHTML = "Save to Votes";
        } else {
            sharedLink.href = sharedLink.href.replace(/share/, "unshare");
            Element.removeClassName(sharedLink, "share");
            Element.addClassName(sharedLink, "shared");
            sharedLink.innerHTML = "Remove";
        }

    } else {
        alert("Failure to share / unshare item.");
    }

}

function clickToPlay(id, url, width, height, rawLink, title) {

    var link = decodeURIComponent(rawLink);
    var container = getDotContainerById(id);
    var clickthrough =
        "Out.ashx?u=" + encodeURIComponent(link) +
        "&d=" + id + "&ls=clicktoplay&noredir=t";

    new Ajax.Request(clickthrough);

    var minVersion = "7";
    var so = new SWFObject(url, null, width, height, minVersion);
    so.addParam("menu", "false");
    so.addParam("wmode", "opaque");

    // GV
    if (url.match(/google\.com/i)) {
        so.addParam("flashvars", "autoPlay=true");
    } else if (url.match(/metacafe.com/i)) {
        so.addParam("flashVars", "altServerURL=http://www.metacafe.com&playerVars=videoTitle=" +
                    decodeURIComponent(title) +
                    "|showStats=yes|autoPlay=yes|blogName=Fave|blogURL=http://faves.com/");
    }

    var videoBucket = document.createElement("div");
    videoBucket.className = "videoBucket";

    var ctp = findChildElementByClass(container, "a", "ctp");

    ctp.parentNode.insertBefore(videoBucket, ctp);

    // Leave anchor / image in the DOM so edit() can pick up the
    // image.
    ctp.style.display = "none";

    var o;
    if (isIE()) {
        o = container.nextSibling;
    
        while (o) {
            o.style.position = "static";
            o = o.nextSibling;
        }
    }
 
    so.write(videoBucket);

    if (isIE()) {
        o = container.nextSibling;
    
        while (o) {
            o.style.position = "relative";
            o = o.nextSibling;
        }
    }
 
    if ($("markAsRead:dot" + id) != null) {
        enableReadTracking();
        onScrollDotList();
    }
}

function getDotIdForElement(element) {

    var dotId = null;

    for (var node = element.parentNode; node; node = node.parentNode) {
        if (node.id && node.id.match(/dot\d+\.\d+/)) {
            dotId = node.id.replace("_", "").substring(3);
            break;
        }
    }

    return dotId;
}

function clickthroughHandler(element, source) {
    // See loadDotFromContainer() for an explanation of the strange
    // getAttribute() argument below.
    var fullDotId = getDotIdForElement(element);
    element.href =
        "Out.ashx?u=" + encodeURIComponent(element.getAttribute("href", 2)) +
        "&d=" + fullDotId +
        "&ls=" + source;
    element.onmousedown = null;
    return true;
}

function isIE() {
    return !!window.attachEvent;
}

function hookupUserProfileNavTitle() {

    var dotLink;

    dotLink = $("upnDotTitle").childNodes[0];
    dotLink.onmousedown = titleClickthroughHandler;
}
    
