// ==UserScript==
// @name         hatebu IncSearch
// @namespace    http://www.enjoyxstudy.com/
// @description  Hatena Bookmark incremental search.
// @include      http://www.enjoyxstudy.com/greasemonkey/incsearch/?mode=hatebu&id=*
// @version      1.1
// ==/UserScript==
//
// ver 0.1   2006/05/30
// ver 0.2   2006/07/16
// ver 0.3   2006/08/22
// ver 1.0   2006/09/16
// ver 1.0.1 2006/09/21
// ver 1.1   2006/11/30
//

(function(){
  var Hatebu = function(userId, callback) {
    this.userId   = userId;
    this.callback = callback;
    this.key      = 'id:' + userId;
  };

  Hatebu.prototype = {
    requestURI: 'http://b.hatena.ne.jp/',

    load: function() {
      this.callback.start.apply(this);

      this.bookmarks = new Array();
      this.total     = null;

      var atomfeedURI = this.requestURI + this.userId + '/atomfeed';

      this._load(atomfeedURI);
    },

    _load: function(url){

      var self = this;
      GM_xmlhttpRequest({
        method: 'get',
        url: url,
        onload: function(detail){
            if (detail.status != 200) {
              var errMsg = 'error :' + detail.status + ' :' + detail.statusText + ' :' + url;
              self.callback.error.apply(self, [errMsg, url]);
              return;
            }

            var wp = new XPCNativeWrapper(window, 'DOMParser()');
            var parser = new wp.DOMParser();

            var res = parser.parseFromString(detail.responseText.replace(/[\x00-\x1F]|\7F/g,""), 'text/xml');

            // entrys
            var entrys = res.getElementsByTagName('entry');

            if(entrys.length == 0){
              //alert(detail.responseText);
              var errMsg = 'atomfeed error!!  ' + url;
              self.callback.error.apply(self, [errMsg, url]);
              return;
            }

            // total result
            if (self.total == null) {
              self.total = res.evaluate('//*[local-name()="totalResults" and namespace-uri()="http://a9.com/-/spec/opensearchrss/1.0/"]',
                                    res, null, XPathResult.STRING_TYPE, null).stringValue;
              if (self.total == '') {
                self.total = entrys.length;
              }
            }

            var entrysLen = entrys.length;
            for (var i = 0; i < entrysLen; i++) {
              var entry = entrys[i];
              var post = {};

              // url
              var links = entry.getElementsByTagName('link');
              for (var j = 0; j < links.length; j++) {
                if (links[j].getAttribute('rel') == 'related') {
                  post.url = links[j].getAttribute('href');
                  break;
                }
              }

              // title
              post.title = entry.getElementsByTagName('title')[0].childNodes.item(0).nodeValue;

              // info
              if (entry.getElementsByTagName('summary')[0].childNodes.length > 0) {
                post.info = entry.getElementsByTagName('summary')[0].childNodes.item(0).nodeValue;
              }

              // tags
              post.tags = new Array();

              var tags = entry.getElementsByTagNameNS('http://purl.org/dc/elements/1.1/', 'subject');

              var tagsLen = tags.length;
              for (var j = 0; j < tagsLen; j++) {
                post.tags.push(tags[j].childNodes.item(0).nodeValue);
              }

              // others(time)
              post.others = new Array();
              post.others.push(entry.getElementsByTagName('issued')[0].childNodes.item(0).nodeValue);
              self.bookmarks.push(post);
            }

            self.callback.loading.apply(self);

            // next
            var next = res.evaluate('//*[local-name()="link" and namespace-uri()="http://purl.org/atom/ns#"][@rel="next"]/@href',
                                    res, null, XPathResult.STRING_TYPE, null).stringValue;

            if (next != '') {
              self._load(next);
            } else {
              self.callback.end.apply(self);
            }
          },
        onerror: function(detail){
            var errMsg = 'error :' + detail.status + ' :' + detail.statusText + ' :' + url;
            self.callback.error.apply(self, [errMsg, url]);
          }
      }); 
    },

    createIncSearch: function() {

      if (!this.incsearch) {
        this.incsearch = unsafeWindow.createBookmarkIncSearch(
                            this.bookmarks,
                            {
                              tagBracket: true,
                              header: '<tr><th width="60%">Description</th><th width="20%">Tags</th><th width="20%">Time</th>'
                            });
      } else {
        this.incsearch.searchValues = this.bookmarks;
        this.incsearch.oldInput = null;
      }

    },
    saveCache: function() {
      GM_setValue(this.key, this.bookmarks.toSource());
    },
    loadCache: function() {
      this.bookmarks = eval(GM_getValue(this.key));
    }
  };

  var href   = window.location.href;
  var userId = href.substr(href.indexOf('&id=') + '&id='.length);

  var callback = {
        start: function() {
          this.statusElm  = document.getElementById('status');
          this.loadingElm = document.getElementById('loading');

          this.statusElm.innerHTML = 'All Bookmarks Loading...';
          this.loadingElm.style.display = 'inline';
        },
        loading: function() {
          this.statusElm.innerHTML = 'All Bookmarks Loading... (' + this.bookmarks.length + '/' + this.total + ')';
        },
        end: function() {
          this.loadingElm.style.display = 'none';

          this.saveCache();
          this.createIncSearch();
        },
        error: function(errMsg, url) {
          this.loadingElm.style.display = 'none';
          this.statusElm.innerHTML = errMsg;

          if (confirm('retry?')) {
            this.statusElm.innerHTML = 'All Bookmarks Loading...';
            this.loadingElm.style.display = 'inline';

            this._load(url);
          }
        }
      };

  var hatebu = new Hatebu(userId, callback);

  document.getElementById('title').innerHTML =
      'hatebu IncSearch <span style="font-size: 80%;">(<a href="http://b.hatena.ne.jp/'
      + userId + '/">id:' + userId + '</a>)</span>';

  document.title = 'hatebu IncSearch (id:' + userId + ')';

  document.getElementById('option').innerHTML =
      '<a href="javascript:void(0)" id="update">update bookmark list</a>'
      + '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" name="cache" id="cache" />&nbsp;use cache';

  document.getElementById('cache').addEventListener(
      'click',
      function(){ GM_setValue('cache', document.getElementById('cache').checked); },
      false);
  document.getElementById('update').addEventListener(
      'click',
      function(){ hatebu.load(); },
      false);


  if (GM_getValue('cache')) {
    document.getElementById('cache').checked = true;
    hatebu.loadCache();
  }

  if (!hatebu.bookmarks) {
    hatebu.load();
  } else {
    hatebu.createIncSearch();
  }

})();
