/*
 * Copyright (c) 2006 Ichro Maruta
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 * */

var overlay_proc = {
  db_service: null,
  lookup_statement: null,
  laststr: null,

  initialize: function() {
    this.db_service = Components.classes["@nori090.org/english/sqlite-service;1"].getService(Components.interfaces.modicIEnglishDB);
    this.lookup_statement = this.db_service.createStatement("SELECT * FROM dict WHERE key = ?1");
    var content = document.getElementById("content");
    content.addEventListener("mousemove", function(e){overlay_proc.handle(e);}, false);
  },

  handle: function(evt) {
    this.do(evt);
  },

  previousexecdate: new Date,

  do: function(evt) {
    if((new Date) - this.previousexecdate < 50) return;
    var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
    var sidebar = top.document.getElementById("sidebar");
    var result = sidebar.contentDocument.getElementById("result");
    if(result == null) return;
    var words = this.catchWords(evt);
    if (words.length == 0) return;
    if (this.laststr == words[0]) return;
    this.laststr = words[0];
    if (/^[a-zA-Z]{3,}$/.test(words[0])) {
      var data = this.search(words,prefs);
      var doc = result.contentDocument;
      doc.open();
      doc.write(data);
      doc.close();
    }
    this.previousexecdate = new Date;
  },
  
  catchWords: function(evt) {
    var onmousenode, onmousetext, mouseoffset, startoffset, endoffset, i;
    var word = "";
    var words = new Array();
    onmousenode = evt.rangeParent;
    if(onmousenode.nodeType == Node.TEXT_NODE) {
      onmousetext = onmousenode.nodeValue;
      mouseoffset = evt.rangeOffset;
      if(mouseoffset < onmousetext.length && /[a-zA-Z]/.test(onmousetext[mouseoffset])) {
        for(startoffset=mouseoffset; startoffset>0; startoffset--) {
          if(/[^a-zA-Z]/.test(onmousetext[startoffset - 1])) break;
        }
        for(endoffset=mouseoffset; endoffset<onmousetext.length-1; endoffset++) {
          if(/[^a-zA-Z]/.test(onmousetext[endoffset + 1])) break;
        }
        for(i=startoffset; i<=endoffset; i++) word += onmousetext[i];
        words.push(word);
        words = words.concat(this.nextWords(endoffset, onmousetext));
      }
    }
    return words;
  },
  
  nextWords: function(e_offset, text) {
    e_offset+=1;
    var start, end, i;
    var word = "";
    var words = new Array();
    for (var c=0;c<4;c++) {
      for(start=e_offset; start<text.length; start++) {
        if(/[a-zA-Z]/.test(text[start])) break;
      }
      if (start==text.length-1) break;
      for(end=start; end<text.length-1; end++) {
        if(/[^a-zA-Z]/.test(text[end+1])) break;
      }
      if(start==end) break;
      for(i=start; i<=end; i++) word += text[i];
      words.push(word);
      word = "";
      if(end+1>=text.length) break;
      e_offset = end+1;
    }
    return words;
  },
  
  search: function(words,prefs) {
    var data = '<style type=text/css>div.key{color:#000088;font-weight:bold;}div.error{color:red;font-weight:bold;}div.desc{font-size:small;}span.annote{color:green;}span.ex{color:orange;}</style>';
    var fontsize = prefs.getIntPref("extensions.mouseoverdictionary.sidebar_font_size");
    fontsize = (fontsize < 0) ? fontsize + "" : "+" + fontsize;
    data+='<font size=' + fontsize + '>';
    var list = this.organizeAndSearchWord(words);
    for (var i in list) {
      data+= (this.display_format(list[i]) + "<hr>");
    }
    if (list.length == 0) {
      data+='<div class="key">' + words[0] + '</div>';
      data+='<div class="error">No match in dictionary.</div>';
    }
    data+='</font>';
    return data;
  },
  
  display_format: function(w) {
    var ret = '<div class="key">' + w["name"] + '</div><div class="desc">';
    var dat = w["desc"].replace(/・[a-zA-Z].+?(\\ |$)/gm, '');
    dat = dat.replace(/◆(.+?)\\ /gm, '<span class="annote">◆$1\\ </span>');
    dat = dat.replace(/【＠】.*$/gm, '');
    dat = dat.replace(/\\ /g, '<br>');
    return ret + dat + '</div>';
  },
  
  organizeAndSearchWord: function(words) {
    var list = new Array();
    var base = words[0].toLowerCase();
    var count = 0;
    if (words[0] != base) this._add(list, words[0]);
    this._add(list, base);
    if(/(.*)ies$/.test(base)) this._add(list, RegExp.$1 + "y");
    if(/(.*)ied$/.test(base)) this._add(list, RegExp.$1 + "y");
    if(/(.*)ier$/.test(base)) this._add(list, RegExp.$1 + "y");
    if(/(.*)iest$/.test(base)) this._add(list, RegExp.$1 + "y");
    if(/(.*)nning$/.test(base)) this._add(list, RegExp.$1 + "n");
    if(/(.*)ing$/.test(base)) this._add(list, RegExp.$1);
    if(/(.*)est$/.test(base)) this._add(list, RegExp.$1);
    if(/(.*)er$/.test(base)) this._add(list, RegExp.$1);
    if(/(.*ss)es$/.test(base)) this._add(list, RegExp.$1);
    if(/(.*ss)ed$/.test(base)) this._add(list, RegExp.$1);
    if(/(.*[cgstvz]e)s$/.test(base)) this._add(list, RegExp.$1);
    if(/(.*[cgstvz]e)d$/.test(base)) this._add(list, RegExp.$1);
    if(/(.*)es$/.test(base)) this._add(list, RegExp.$1);
    if(/(.*)ed$/.test(base)) this._add(list, RegExp.$1);
    if(/(.*[^aiuos])s$/.test(base)) this._add(list, RegExp.$1);
    var phrase = words[0];
    for (var i = 1; i < words.length; i++) {
      phrase += " "+words[i];
      this._add(list, phrase);
      if(phrase != phrase.toLowerCase()) this._add(list, phrase.toLowerCase());
    }
    return list;
  },
  
  _add: function(list,w) {
    var r = this.lookupDB(w);
    if (r != undefined) {
      var d = new Array();
      d["name"] = w;
      d["desc"] = r;
      list.push(d);
    }
  },
  
  lookupDB: function(word) {
    var data;
    try {
      this.lookup_statement.bindUTF8StringParameter(0, word);
      while(this.lookup_statement.executeStep()) {
        data = this.lookup_statement.getString(1);
      }
    } catch(err) {
      alert(err);
    } finally {
      this.lookup_statement.reset();
    }
    return data;
  },
}
