// ? Comment Linker, released under the GPL
// http://www.gnu.org/copyleft/gpl.html
//
// ==UserScript==
// @name           Hatena Comment Linker
// @description    Looks for text strings in comments that look like URLs, and converts them to clickable hyperlinks.
// @include        http://d.hatena.ne.jp/*
// @include        http://*.g.hatena.ne.jp/*
// @include        http://b.hatena.ne.jp/*
// @include        http://i.hatena.ne.jp/*
// @include        http://q.hatena.ne.jp/*
// ==/UserScript==
//
// 2006-05-01 (v0.4) Fixed a bug in processing ASIN/EAN syntax, changed the regular expression for URLs so that it does contain neither "(" nor ")", and made it case insensitive.
// 2006-03-20 (v0.3) Added support for "comment-content" and "tb_excerpt" (question).
// 2006-02-16 (v0.2) Added support for "icontent_*" (idea) and "commentbody" (diary).
// 2005-08-23 (v0.1) Initial Version.

(function(){
  const comments = document.evaluate('(/descendant::DIV[@class="commentshort" or @class="commentbody"]/P|/descendant::DIV[@class="bookmarklist"][1]/UL/LI|/descendant::TABLE[@class="icontent"]/TBODY/TR/TD/DIV[1]|/descendant::TABLE[@class="paymentlist"]/TBODY/TR/TD|/descendant::UL[@class="commentlist"]/LI|/descendant::DIV[@class="comment-content" or @class="tb_excerpt"])', document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
  const syntaxRE = /(?:(?:(a|b|d|f|i|r|graph):)?(id):([-_a-zA-Z0-9]{3,15})(?::(\w+)(?::(\w+)(?::[\w:]+)?)?)?|(g):([-_a-zA-Z0-9]{3,24})(?::id:([-_a-zA-Z0-9]{3,15})(?::(\w+)(?::(\w+))?)?)?|(question):(\d+)(?::[\w:]+)?|(idea):(\d+)(?::[\w:]+)?|(map):x([\d.]+)y([\d.]+)(?::[\w:]+)?|(isbn|asin):([\dX-]+)(?::[\w:]+)?|(jan|ean):([\dX-]+)(?::[\w:]+)?|(?:https?|ftp):\/\/[-_.!~*\'a-zA-Z0-9;\/?:@&=+$,%#]+|mailto:[-_.!~*\'a-zA-Z0-9\/?&=+$%#^`{|}]+@[-.a-zA-Z0-9]+)(?=[^>]*(?:<|$))/ig;
  
  for (var i = 0; i < comments.snapshotLength; ++i) {
    with (comments.snapshotItem(i)) {
      innerHTML = innerHTML.replace(syntaxRE, function (s, idName, id, idID, idDate, idTime, group, groupName, groupID, groupDate, groupTime, question, questionID, idea, ideaID, map, mapX, mapY, asin, asinID, ean, eanID) {
        if (id) {
          return s.link((idName ? 'http://' + idName + '.hatena.ne.jp/' : '/') + idID + '/' + (!idDate ? '' : idName == 'f' && idDate.match(/\d+/) ? RegExp.lastMatch : idDate + (!idTime ? '' : '/' + idTime)));
        }
        
        if (group) {
          return s.link('http://' + groupName + '.g.hatena.ne.jp/' + (!groupID ? '' : groupID + '/' + (!groupDate ? '' : groupDate + (!groupTime ? '' : '/' + groupTime))));
        }
        
        if (question) {
          return s.link('http://q.hatena.ne.jp/' + questionID);
        }
        
        if (idea) {
          return s.link('http://i.hatena.ne.jp/idea/' + ideaID);
        }
      
        if (map) {
          return s.link('http://map.hatena.ne.jp/?x=' + mapX + '&amp;y=' + mapY + '&amp;z=4');
        }
        
        if (asin) {
          return s.link('http://d.hatena.ne.jp/asin/' + asinID.replace(/-/g, ''));
        }
      
        if (ean) {
          return s.link('http://d.hatena.ne.jp/ean/' + eanID.replace(/-/g, ''));
        }
      
        try {
          return decodeURIComponent(s).link(s);
        }
        catch (e) {
          return s.link(s);
        }
      });
    }
  }
})()

