// Enhancements for the Achewood assetbar.com forum user interface
// version 1.0 alpha 2
// 2009-08-15
// Copyright (c) 2008-2009 Brian Pane
// Released under the Apache License, version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
//
// ==UserScript==
// @name         Assetbarista
// @namespace    http://www.brianp.net/
// @description  Enhancements for the Achewood assetbar.com forum UI
// @include      http://m.assetbar.com/achewood/*
// ==/UserScript==

function findFirst(node, type) {
  return findNth(node, type, 1);
}

function findNth(node, type, n) {
  if (node == null) {
    return null;
  }
  var matches = 0;
  var child = node.firstChild;
  while (child != null) {
    if (child.tagName == type) {
      matches++;
      if (matches == n) {
        return child;
      }
    }
    child = child.nextSibling;
  }
  return null;
}

function findAncestorWithClass(node, className) {
  while (node != null) {
    if (hasClass(node, className)) {
      return node;
    }
    node = node.parentNode;
  }
  return null;
}

var lastIndent = 0;
function addAnchors(node, commentNumber, indentToParentMap) {
  var spacerCell = node.parentNode.previousSibling;
  if (spacerCell == null) {
    return;
  }
  var spacerWidth = spacerCell.getAttribute("width");
  if (spacerWidth == null) {
    // work around an extraneous "<td>" in ignored comments
    spacerCell = spacerCell.previousSibling;
    if (spacerCell == null) {
      return;
    }
    spacerWidth = spacerCell.getAttribute("width");
  }
  if (spacerWidth != null) {
    var myAnchorName;
    if ((node.id != null) && (node.id != "")) {
      myAnchorName = node.id;
    }
    else {
      myAnchorName = "AB-comment-" + commentNumber;
      var anchor = document.createElement("a");
      anchor.setAttribute("name", myAnchorName);
      spacerCell.appendChild(anchor);
    }
    var indent = parseInt(spacerWidth) / 30;
    indentToParentMap[indent] = myAnchorName;
    if ((indent > 0) && (indent != lastIndent + 1)) {
      var parentAnchorName = indentToParentMap[indent - 1];
      spacerCell.setAttribute("vAlign", "top");
      spacerCell.setAttribute("align", "right");
      var link = document.createElement("a");
      var linkText = document.createTextNode("^");
      link.appendChild(linkText);
      link.setAttribute("href", "#" + parentAnchorName);
      spacerCell.appendChild(link);
    }
    lastIndent = indent;
  }
}

function hasClass(element, class) {
  if (element != null) {
    var className = element.className;
    if (className != null) {
      var classes = className.split(" ");
      for (var i = 0; i < classes.length; i++) {
        if (classes[i] == class) {
          return true;
        }
      }
    }
  }
  return false;
}

function annotateUnread(comment) {
  if (hasClass(comment, "unread")) {
    var node = findFirst(comment, "TBODY");
    node = findFirst(node, "TR");
    node = findFirst(node, "TD");
    node = findNth(node, "DIV", 3);
    if (hasClass(node, "footer")) {
      var span = document.createElement("span");
      span.appendChild(document.createTextNode("[unread]"));
      node.appendChild(span);
    }
  }
}

var ESCAPE_REGEX = /%u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]/;

function fixUnicode(node) {
  if (hasClass(node, "text")) {
    if (node.innerHTML != null) {
      var text = node.innerHTML;
      var index = text.search(ESCAPE_REGEX);
      if (index >= 0) {
        var newText = "";
        do {
          newText += text.substring(0, index);
          var codePoint = text.substring(index + 2, index + 6);
          newText += "&#";
          newText += parseInt(codePoint, 16);
          newText += ";";
          text = text.substring(index + 6);
        } while ((index = text.search(ESCAPE_REGEX)) >= 0);
        newText += text;
        node.innerHTML = newText;
      }
    }
  }
}

function recursiveFixUnicode(node) {
  if (node != null) {
    var child = node.firstChild;
    while (child != null) {
      recursiveFixUnicode(child);
      child = child.nextSibling;
    }
    fixUnicode(node);
  }
}

function fixCommentBlock(comment) {
  var node = findFirst(comment, "TBODY");
  node = findFirst(node, "TR");
  node = findFirst(node, "TD");
  node = findNth(node, "DIV", 2);
  fixUnicode(node);
}

function fixCSS() {
  var headers = document.getElementsByTagName("head");
  if ((headers == null) || (headers.size == 0)) {
    return;
  }
  var header = headers[0];
  var style = document.createElement("style");
  style.type = "text/css";
  style.innerHTML = ".comment .img_container { width: 380px; }";
  header.appendChild(style);
}

function fixStatusMouseovers() {
  if (typeof(unsafeWindow.popStatusMessage) == "function") {
    var originalPopStatusMessage = unsafeWindow.popStatusMessage;
    unsafeWindow.popStatusMessage = function(event, asset) {
      if (event.type == "mouseover") {
        originalPopStatusMessage(event, asset);
      }
    }
  }
}

var indentToParentMap = new Array();
var commentCount = 0;

function modifyComment(node) {
  commentCount++;
  addAnchors(node, commentCount, indentToParentMap);
  fixCommentBlock(node);
  annotateUnread(node);
}

function wrapPostComment() {
  var originalPostComment = unsafeWindow.postComment;
  unsafeWindow.postComment = function(base, assetNum) {
    var result = originalPostComment(base, assetNum);
    var node = document.getElementById('comments_table_body');
    if (node != null) {
      // The newly posted comment has been appended as the
      // last child of comments_table_body by Assetbar's
      // postComment function
      recursiveFixUnicode(node.lastChild);
    }
    return result;
  }
}

function createButton(label) {
  var button = document.createElement("input");
  button.type = "button";
  button.value = label;
  button.style.margin = "10px";
  return button;
}

function detachPostButton(container, previewButton) {
  var inputs = container.getElementsByTagName("input");
  if (inputs != null) {
    for (i = 0; i < inputs.length; i++) {
      if ((inputs[i].type == "button") && (inputs[i].value == "Post")) {
        if (previewButton != null) {
          var sibling = inputs[i].nextSibling;
          inputs[i].parentNode.insertBefore(previewButton, sibling);
        }
        return inputs[i].parentNode.removeChild(inputs[i]);
      }
    }
  }
  return null;
}

function bbcodeToHTML(bbcode) {
  if (bbcode == null) {
    return "";
  }
  var text = bbcode;
  text = text.replace(/\n/g, "<br/>");
  text = text.replace(/\[(\/)*([bisu])\]/g, "<$1$2>");
  text = text.replace(/\[img\]([^\]]*)\[\/img\]/g, "<img src=\"$1\"/>");
  text = text.replace(/\[url=([^\]]*)\]([^\[]*)\[\/url\]/g, "<a href=\"$1\">$2</a>");
  text = text.replace(/\[url\]([^\]]*)\[\/url\]/g, "<a href=\"$1\">$1</a>");
  return text;
}

function generatePreview(textBox, previewDiv) {
  var bbcode = textBox.value;
  var html = bbcodeToHTML(bbcode);
  previewDiv.innerHTML = html;
}

function generatePreviewWrapper(container, postButton, previewButton, commentTextBox) {
  var parent = container.parentNode;
  var sibling = container.nextSibling;
  var previewWrapper = document.createElement("div");
  previewWrapper.style.display = "none";
  previewWrapper.style.padding = "10px";
  previewWrapper.style.border = "1px solid #999999";
  previewWrapper.style.backgroundColor = "#ffffcc";
  var message = document.createElement("span");
  message.appendChild(document.createTextNode("Please review your comment and click" +
                                              " Post to post it or Edit to make changes:"));
  message.style.fontWeight = "bold";
  message.style.fontSize = "1.2em";
  previewWrapper.appendChild(message);
  var preview = document.createElement("div");
  preview.style.padding = "10px";
  previewWrapper.appendChild(preview);
  previewWrapper.appendChild(postButton);
  var editButton = createButton("Edit");
  previewWrapper.appendChild(editButton);
  parent.insertBefore(previewWrapper, sibling);
  previewButton.addEventListener("click", function() {
    container.style.display = "none";
    generatePreview(commentTextBox, preview);
    previewWrapper.style.display = "block";
  }, false);
  editButton.addEventListener("click", function() {
    previewWrapper.style.display = "none";
    container.style.display = "block";
  }, false);
}

function addPreview(container) {
  var commentTextBox = document.getElementById("comment_text_static");
  if (commentTextBox == null) {
    GM_log("can't find comment text box");
    return;
  }
  var previewButton = createButton("Preview");
  var postButton = detachPostButton(container, previewButton);
  if (postButton == null) {
    return;
  }
  generatePreviewWrapper(container, postButton, previewButton, commentTextBox);
}

function addReplyPreview() {
  var commentTextBox = document.getElementById("comment_text");
  if (commentTextBox == null) {
    GM_log("can't find reply comment text box");
    return;
  }
  var container = findAncestorWithClass(commentTextBox, "quick_post");
  if (container == null) {
    GM_log("cant find expected div of class quick_post");
    return;
  }
  var previewButton = createButton("Preview");
  var postButton = detachPostButton(container, previewButton);
  if (postButton == null) {
    return;
  }
  generatePreviewWrapper(container, postButton, previewButton, commentTextBox);
}

function modifyCommentForms() {
  wrapPostComment();
  var quickPosts = document.getElementsByClassName("quick_post");
  if (quickPosts != null) {
    for (i = 0; i < quickPosts.length; i++) {
      addPreview(quickPosts[i]);
    }
  }

  var originalCommentDialog = unsafeWindow.commentDialog;
  unsafeWindow.commentDialog = function(event, asset, comment, arg) {
    var result = originalCommentDialog(event, asset, comment, arg);
    addReplyPreview();
    return result;
  }

  var originalCreatePD2Comment = unsafeWindow.createPD2Comment;
  unsafeWindow.createPD2Comment = function() {
    var commentObject = unsafeWindow.gCommentObject;
    var result = originalCreatePD2Comment();
    if ((commentObject != null) && (commentObject.popUp != null)) {
      recursiveFixUnicode(commentObject.popUp);
    }
    return result;
  }
}

function assetBarista() {
  var start = new Date().getTime();
  fixCSS();
  fixStatusMouseovers();
  modifyCommentForms();
  var tables = document.getElementsByTagName("table");
  for (var i = 0; i < tables.length; i++) {
    if (hasClass(tables[i], "comment")) {
      modifyComment(tables[i]);
    }
  }
  var duration = new Date().getTime() - start;
  GM_log(commentCount + " comment(s) updated in " + duration + "ms");
}

assetBarista();

