//
// $Date: 2005-11-28 15:02:58 +0900 (Mon, 28 Nov 2005) $
//

// type='Wiki';
// title='本棚TODO';
// style='WikiPage';
// id='20060723164801';
// utfurl='/~masui/PIM/2006/7/23/20060723164801.utf';
// filter='listedit';

var editline = -1;
var eline = -1;
//var elinesave = -1;
var timeout;

var headchar = '';
var data = [];
var dt = []
var doi = [];
var zoomlevel = 0;

var query = null;
var timemachine = false;
var datestr = '';

//var TOP = "http://localhost/~masui/Tangocho";
var TOP = "http://tangocho.org";

var KC = {
  tab:9, enter:13, left:37, up:38, right:39, down:40
};

// keypressを定義しておかないとFireFox上で矢印キーを押してときカーソルが動いてしまう
document.onkeypress = keypress;
//document.addEventListener('keypress', keypress, true); 

function keypress(event){
  var kc = keycode(event);
  if(kc == KC.enter)  event.preventDefault();
  if(kc == KC.enter){
    // 1行追加 
    // IME確定でもkeydownイベントが出てしまうのでここで定義が必要!
    if(editline >= 0){
      addblankline(editline+1,indent(editline));
      zoomlevel = 0;
      calcdoi();
      display();
    }
    return false;
  }
  // カーソルキーやタブを無効化
  if(kc == KC.down || kc == KC.up || kc == KC.tab){
    return false;
  }
}

// これは普通のやり方
//body.onload = onload;
//function onload(){
//  setup();
//  getdata();
//}

// SafariとかIEとかでaddEventListenerが動かない
document.onkeydown = keydown;
//document.addEventListener('keydown', keydown, true); 

document.onkeyup = keyup;
//document.addEventListener('keyup', keyup, true); 
document.onmousedown = mousedown;
document.onmouseup = mouseup;

function keycode(event)
{
  if(document.all)                       //e4,e5,e6用
    return window.event.keyCode;
  if(document.layers||document.getElementById){ // NS, FF
    a = event.keyCode
    if(a != 0){ return a }
    return event.which
  }
}

function shiftkey(event)
{
  if(document.all)                       //e4,e5,e6用
    return window.event.shiftKey;
  if(document.layers||document.getElementById) // NS, FF
    return event.shiftKey;
}

function ctrlkey(event)
{
  if(document.all)                       //e4,e5,e6用
    return window.event.ctrlKey;
  if(document.layers||document.getElementById) // NS, FF
    return event.ctrlKey;
}

function getMouseX(e){
  if(window.opera)                            //o6用
      return e.clientX
  else if(document.all)                       //e4,e5,e6用
      return document.body.scrollLeft+event.clientX
  else if(document.layers||document.getElementById)
      return e.pageX                          //n4,n6,m1用
}

function getMouseY(e){
  if(window.opera)                            //o6用
      return e.clientY
  else if(document.all)                       //e4,e5,e6用
      return document.body.scrollTop+event.clientY
  else if(document.layers||document.getElementById)
      return e.pageY                          //n4,n6,m1用
}

function bgcol_simple(t){
  if(t < 1000) return '#ffffff';
  if(t < 3000) return '#eeeeee';
  if(t < 10000) return '#cccccc';
  if(t < 30000) return '#bbbbbb';
  if(t < 100000) return '#aaaaaa';
  if(t < 300000) return '#999999';
  return '#888888';
}

function hex2(v){
  return ("0" + v.toString(16)).slice(-2);
}

function bgcol(t){
  var table = [
           [0,                        256, 256,   0], 
           [24 * 60 * 60,             256, 100,  20],
           [7 * 24 * 60 * 60,         100, 100,  50],
           [30 * 24 * 60 * 60,         50, 100, 100],
           [180 * 24 * 60 * 60,        20, 100, 200],
           [365 * 24 * 60 * 60,         0,  60, 100],
           [2 * 365 * 24 * 60 * 60,     0,  30,  70],
           [4 * 365 * 24 * 60 * 60,     0,  10,  50],
           [8 * 365 * 24 * 60 * 60,     0,   0,  40],
           [100 * 365 * 24 * 60 * 60,   0,   0,   0],
          ];
  for(i=0;i<table.length-1;i++){
    var t1 = table[i][0];
    var t2 = table[i+1][0];
    if(t >= t1 && t <= t2){
      r = ((t - t1) * table[i+1][1] + (t2 - t) * table[i][1]) / (t2 - t1);
      r = Math.floor(r);
      if(r >= 256) r = 255;
      g = ((t - t1) * table[i+1][2] + (t2 - t) * table[i][2]) / (t2 - t1);
      g = Math.floor(g);
      if(g >= 256) g = 255;
      b = ((t - t1) * table[i+1][3] + (t2 - t) * table[i][3]) / (t2 - t1);
      b = Math.floor(b);
      if(b >= 256) b = 255;
      return "#" + hex2(r) + hex2(g) + hex2(b);
    }
  }
}

function addblankline(line,indent){
  editline = line;
  eline = line;
  deleteblankdata();
  for(var i=data.length-1;i>=editline;i--){
    data[i+1] = data[i];
  }
  var s = '';
  for(var i=0;i<indent;i++) s += ' ';
  data[editline] = s;
  search();
}

function mouseup(event){
  eline = -1;
}

function getMouseY(e){
  if(window.opera)                            //o6!)
      return e.clientY
  else if(document.all && document.getElementById && (document.compatMode=='CSS1Compat')) // e6
      return document.documentElement.scrollTop+event.clientY
  else if(document.all)                       //e4,e5,e6!)
      return document.body.scrollTop+event.clientY
  else if(document.layers||document.getElementById)
      return e.pageY                          //n4,n6,m1!)
}

var searchmode = false;

function mousedown(event){
  y = getMouseY(event);
  if(y < 40){
    searchmode = true;
    return true;
  }
  searchmode = false;
  timemachine = false;

  editline = eline;
  calcdoi();
  display(true);
}

function indent(line){
  var s = data[line]
  var i;
  for(i=0;i<s.length-1 && s.substring(i,i+1)==' ';i++);
  return i;
}

function movelines(line){ // 移動する行数
  var i;
  var ind = indent(line);
  for(i=line+1;i<data.length && indent(i) > ind;i++);
  return i-line;
}

function destline_up(){
  var i;
  var ind = indent(editline);
  var found = false;
  var line;
  // インデントが自分と同じか自分より深い行を捜す。
  // ひとつもなければ -1 を返す。
  i = editline-1;
  while(true){
    if(indent(i) > ind){
      found = true;
      line = i;
    }
    if(indent(i) == ind) return i;
    if(indent(i) < ind) return found ? line : -1;
    i -= 1;
    if(i < 0) return found ? line : -1;
  }
}

function destline_down(){
  var i;
  var ind = indent(editline);
  var line;
  // インデントが自分と同じ行を捜す。
  // ひとつもなければ -1 を返す。
  i = editline+1;
  while(true){
    if(indent(i) == ind) return i;
    if(indent(i) < ind) return -1;
    i += 1;
    if(i >= data.length) return -1;
  }
}

function keyup(event){
  var kc = keycode(event);
  var sk = shiftkey(event);

  // 入力途中の文字列を確定 
  data[editline] = document.getElementById("newtext").value

  // 数秒入力がなければデータ書き込み
  if(!timemachine && !ctrlkey(event)){
    if(sk || (kc != KC.down && kc != KC.up && kc != KC.left && kc != KC.right)){
      if(timeout) clearTimeout(timeout);
      timeout = setTimeout("writedata()",2000);
  
      // 書き込みが必要な状態になると背景を黄色くしていたが、
      // ウザい気もするのでやめてみる。
      // var input = document.getElementById("newtext");
      // input.style.backgroundColor = "#ffff80";
    }
  }
}

function keydown(event){
  var kc = keycode(event);
if(kc == KC.enter) event.preventDefault();
  var sk = shiftkey(event);
  var i;
  var m,m2;
  var dst;
  var tmp = [];

  if(searchmode) return true;

  // 入力途中の文字列を確定 
  // data[editline] = document.getElementById("newtext").value
  //
  if(kc == KC.enter){
    query = document.getElementById("query");
    if(query) query.value = '';
    //
    // GM_POBoxが動いているときでも何故かEnterイベントが来てしまうので
    // このときは無視するようにしたい。
    // 苦しい解法だがなんとか動いている。
    //
// 単語帳ではEnterで行追加を行なわない
//    cand = document.getElementById('lexierra_cand_win');
//    if(!cand || cand.style.visibility != 'visible'){
//      addblankline(editline+1,indent(editline));
//      zoomlevel = 0;
//      calcdoi();
//      display();
//    }
  }
  if(kc == KC.down && sk){
    if(editline >= 0 && editline < data.length-1){
      m = movelines(editline);
      dst = destline_down();
      if(dst >= 0){
        m2 = movelines(dst);
        for(i=0;i<m;i++)  tmp[i] = data[editline+i];
        for(i=0;i<m2;i++) data[editline+i] = data[dst+i];
        for(i=0;i<m;i++)  data[editline+m2+i] = tmp[i];
	editline = editline + m2;
        deleteblankdata();
        display();
      }
    }
  }
  if(kc == KC.down && !sk){
    if(editline >= 0 && editline < data.length-1){
      var i;
      for(i=editline+1;i<data.length;i++){
        if(doi[i] >= -zoomlevel){
          editline = i;
          deleteblankdata();
          display();
          break;
        }
      }
    }
  }
  if(kc == KC.up && sk){
    if(editline > 0){
      m = movelines(editline);
      dst = destline_up();
      if(dst >= 0){
        m2 = editline-dst;
        for(i=0;i<m2;i++) tmp[i] = data[dst+i];
        for(i=0;i<m;i++)  data[dst+i] = data[editline+i]
        for(i=0;i<m2;i++) data[dst+m+i] = tmp[i];
        editline = dst;
        deleteblankdata();
        display();
      }
    }
  }
  if(kc == KC.up && !sk){
    if(editline > 0){
      var i;
      for(i=editline-1;i>=0;i--){
        if(doi[i] >= -zoomlevel){
          editline = i;
          deleteblankdata();
          display();
          break;
        }
      }
    }
  }
  if(kc == KC.tab && !sk || kc == KC.right && sk){
    if(editline >= 0 && editline < data.length){
      data[editline] = ' ' + data[editline];
      display();
    }
  }
  if(kc == KC.tab && sk || kc == KC.left && sk){
    if(editline >= 0 && editline < data.length){
      var s = data[editline]
      if(s.substring(0,1) == ' '){
        data[editline] = s.substring(1,s.length)
      }
      display();
    }
  }
  if(kc == KC.left && !sk && editline < 0){
    if(-zoomlevel < maxindent()){
      zoomlevel -= 1;
      display();
    }
  }
  if(kc == KC.right && !sk && editline < 0){
    if(zoomlevel < maxindent()){
      zoomlevel += 1;
      display();
    }
  }
  if(ctrlkey(event) && (kc == 0x56 || kc ==0x50 || kc == KC.left)){
    timemachine = true;
    version += 1;
    //location.href = TOP + "/" + word + "/" + version;
    getdata();
  }
  else if(ctrlkey(event) && (kc == 0x4e || kc == KC.right)){
    if(version > 0){
      version -= 1;
      if(version > 0){
        timemachine = true;
      }
      //location.href = TOP + "/" + word + "/" + version;
      getdata();
    }
  }
  else if(kc >= 0x41 && kc <= 0x5A && editline < 0){
    if(!query){
      var querydiv = document.getElementById('querydiv');
      querydiv.innerHTML = 'Search: <input type="text" id="query" autocomplete="off" onkeyup="search(event)" style="font-size:10pt;border:none;padding:1px;margin:0;background-color:#f0f0ff;"><p>';
      query = document.getElementById("query");
    }
    
    query.style.visibility = 'visible';
    query.focus();
  }
}

function deleteblankdata(){ // 空白行を削除
  var reg = new RegExp('^ *$');
  for(i=0;i<data.length;i++){
    if(reg.exec(data[i])){
      data.splice(i,1);
    }
  }
  calcdoi();
}

// こうすると動的に関数を定義できるようだ
function linefunc(n){
  return function(event){
    seteditline(event,n);
  }
}

function setup(){
  var contents = document.getElementById('contents');
  var x,y;
  var i;
  for(i=0;i<300;i++){
    y = document.createElement('div');
    y.id = "listbg" + i;
    x = document.createElement('span');
    x.id = "list" + i;
    x.onmousedown = linefunc(i);
    y.appendChild(x);
    contents.appendChild(y);
  }
}

function display(delay){
  // zoomlevelに応じてバックグラウンドの色を変える
  bgcolor = zoomlevel == 0 ? '#ffffcc' :
            zoomlevel == -1 ? '#e0e0c0' :
            zoomlevel == -2 ? '#c0c0a0' : '#a0a080';
  document.body.style.backgroundColor = bgcolor;
  if(version != 0){ // 古いページを表示する場合はバックグラウンド変更?
    // document.body.style.backgroundColor = '#c0c0c0';
  }

  var i;
  if(delay){ // ちょっと待ってもう一度呼び出す!
    setTimeout("display()",200);
    return;
  }

  var input = document.getElementById("newtext");
//  input.style.visibility = (editline == -1 ? 'hidden' : 'visible');
  if(editline == -1){
    deleteblankdata();

    input = document.getElementById("newtext");
    input.style.left = 0;
    input.style.top = 0;
    input.blur(); // フォーカスを解除

    // 何故かinputのフォーカスを解除するとqueryのフォーカスまで解除されてしまうので。
    query = document.getElementById("query");
    if(query) query.focus();

  }

  for(i=0;i<data.length;i++){
//  for(i=data.length-1;i>=0;i--){
    var x;
    var ind;
    ind = indent(i);
    xmargin = ind * 30;
    var s;
    var head;
    head = headchar[indent(i)];
    if(!head) head = '';
    else head += ' ';
    s = head + data[i];

    var t = document.getElementById("list"+i);
    t.style.position = '';
    t.innerHTML = '&nbsp;'; // 何故かこういうのを入れないと、下向き矢印で項目移動したときレイアウトがずれる。
    if(doi[i] >= -zoomlevel){
      if(i == editline){
        t.style.lineHeight = input.offsetHeight + 'px';
        t.style.visibility = 'hidden';
        t.parentNode.style.visibility = 'hidden';

        input.style.left = xmargin+25;
        input.style.top = t.offsetTop-1;
        input.value = data[i];
        input.onmousedown = linefunc(i);
//        input.focus(); IEで動かない
      }
      else {
        t.style.visibility = 'visible';
        t.style.lineHeight = '';
        t.innerHTML = tag(data[i]);
        t.style.margin.x = xmargin;

        p = t.parentNode;
        p.className = 'listedit' + ind;
        p.style.visibility = 'visible';
        p.style.position = '';
        p.style.lineHeight = '';
        p.style.margin.x = xmargin;
      }
    }
    else {
      t.style.visibility = 'hidden';
      t.innerHTML = '';
      t.style.position = 'absolute';
      t.style.left = 0;
      t.style.top = 0;

      p = t.parentNode;
      p.style.visibility = 'hidden';
      p.style.position = 'absolute';
      p.style.left = 0;
      p.style.top = 0;
    }

    t = document.getElementById("listbg"+i);
    if(version > 0){
      t.style.backgroundColor = bgcol(dt[i]);
    }
    else {
      t.style.background = 'transparent';
    }
  }
  for(i=data.length;i<300;i++){
    var t = document.getElementById("list"+i);
    t.style.visibility = 'hidden';
    t = document.getElementById("listbg"+i);
    t.style.visibility = 'hidden';
  }

  for(i=data.length;i<300;i++){
    t = document.getElementById("list"+i);
    t.innerHTML = '';
    t.style.position = 'absolute';
    t.style.left = 0;
    t.style.top = 0;
    t.style.visibility = 'hidden';
  }

  input.style.visibility = (editline == -1 ? 'hidden' : 'visible');
}

function seteditline(event,i){
  eline = i;
  var sk = shiftkey(event)
  if(sk){
    addblankline(i+1,indent(i));  // 単語帳の場合下に行を追加
  }
  else {
//    deleteblankdata();
  }
}

function tag(s){
  var s1,s2,s3;
  s = s.replace(/[\r\n]+/,'');
  while(s.match(/^(.*)<(.*)$/)){
    s1 = RegExp.$1;
    s2 = RegExp.$2;
    s = s1 + '&lt;' + s2;
  }
  while(s.match(/^(.*)\[\[\[([^\]]*)\]\]\](.*)$/)){
    s1 = RegExp.$1;
    s2 = RegExp.$2;
    s3 = RegExp.$3;
    s = s1 + '<b>' + s2 + '</b>' + s3;
  }
  while(a = s.match(/^(.*)\[\[(([^\]]|\][^\]]|[^\]]\])*)\]\](.*)$/)){
    s1 = RegExp.$1;
    s2 = RegExp.$2;
    s3 = RegExp.$4;
    if(s2.match(/^(http[^ ]+) (.*)\.(jpg|jpeg|jpe|png|gif)$/i)){
      s4 = RegExp.$1;
      s5 = RegExp.$2;
      s6 = RegExp.$3;
      s = s1 + '<a href="' + s4 + '"><img src="' + s5 + '.' + s6 + '" border="none"></a>' + s3;
    }
    else if(s2.match(/^(http.+)\.(jpg|jpeg|jpe|png|gif)$/i)){
      s4 = RegExp.$1;
      s5 = RegExp.$2;
      s = s1 + '<img src="' + s4 + '.' + s5 + '">' + s3;
    }
    else if(s2.match(/^(http[^ ]+) (.*)$/)){
      s4 = RegExp.$1;
      s5 = RegExp.$2;
      s = s1 + '<a href="' + s4 + '">' + s5 + '</a>' + s3;
    }
    else if(s2.match(/^(http[^ ]+)$/)){
      s4 = RegExp.$1;
      s = s1 + '<a href="' + s4 + '" class="link">' + s4 + '</a>' + s3;
    }
    else if(s2.match(/^([^/]*)\/ (.*)$/)){
      s4 = RegExp.$1;
      s5 = RegExp.$2;
      s = s1 + '<a href="' + TOP + '/' + s4 + '/" class="memo">' + s5 + '</a>' + s3;
      addtag(s2);
    }
    else if(s2.match(/^([^/]*)\/$/)){
      s4 = RegExp.$1;
      s = s1 + '<a href="' + TOP + '/' + s4 + '/" class="memo">' + s4 + '</a>' + s3;
      addtag(s2);
    }
    else if(s2.match(/^(.*)\/(.*)$/)){
      s4 = RegExp.$1;
      s5 = RegExp.$2;
      s = s1 + '<a href="' + TOP + '/' + s4 + '/' + s5 + '" class="tag">' + s5 + '</a>' + s3;
      addtag(s2);
    }
    else { // タグ/リンク
      s = s1 + '<a href="' + TOP + '/' + encodeURIComponent(s2) + '" class="tag">' + s2 + '</a>' + s3;
      addtag(s2);
    }
  }
  return s;
}

function createXmlHttp(){
    if (window.ActiveXObject) {
        return new ActiveXObject("Microsoft.XMLHTTP");
    } else if (window.XMLHttpRequest) {
        return new XMLHttpRequest();
    } else {
        return null;
    }
}

function addtag(tag){
//  xmlhttp = createXmlHttp();
//  xmlhttp.open("POST", "/addtag/"+id , true);
//  xmlhttp.setRequestHeader("Content-Type" , "application/x-www-form-urlencoded");
//  xmlhttp.onreadystatechange=function() {
//    if (xmlhttp.readyState==4) {
//      xx = xmlhttp.responseText
//    }
//  }
//  postdata = "tag=" + encodeURIComponent(tag);
//  xmlhttp.send(postdata);
}

function writedata(){
  xmlhttp = createXmlHttp();
  xmlhttp.open("POST", TOP + "/programs/postdata.cgi" , true);
  xmlhttp.setRequestHeader("Content-Type" , "application/x-www-form-urlencoded");
  xmlhttp.setRequestHeader("Content-Type" , "text/html; charset=utf-8"); //2006/11/10追加 for Safari
//  xmlhttp.onreadystatechange=function() {
//    if (xmlhttp.readyState==4) {
//      xx = xmlhttp.responseText
//    }
//  }
  postdata = "data=" + encodeURIComponent(id + "\n" + user + "\n" + word + "\n" + data.join("\n"));
//  postdata = "data=" + escape(id + "\n" + data.join("\n"));
  xmlhttp.send(postdata);

  var input = document.getElementById("newtext");
  input.style.backgroundColor = "#f0f0ff";
}

function getdata(){ // 20050815123456.utf のようなテキストを読み出し
  data = [];
  xmlhttp = createXmlHttp();
  file = TOP + "/programs/getdata.cgi?id=" + id + "&version=" + version;
  xmlhttp.open("GET", file , true);
//  xmlhttp.setRequestHeader("Content-Type", "text/html; charset=euc-jp");
//  xmlhttp.setRequestHeader("Content-Type" , "application/x-www-form-urlencoded");

  xmlhttp.setRequestHeader("Content-Type" , "text/html; charset=utf-8"); //2006/11/10追加 for Safari
//  と思ったら無くても大丈夫じゃん

  xmlhttp.onreadystatechange=function() {
    if (xmlhttp.readyState==4) {
      //xx = xmlhttp.responseText;
      xx = decodeURIComponent(xmlhttp.responseText);
      d = xx.split(/\n/);
      if(version > 0){
        datestr = d.shift();
      }
      else {
        datestr = '';
      }
      document.getElementById('datestr').innerHTML = datestr;
      data = [];
      dt = [];
      for(var i=0;i<d.length;i++){
        s = d[i]
        if(s != ''){
          t = 0;
          if(version > 0){
            s.match(/^(.*) ([0-9]*)$/);
            s = RegExp.$1;
            t = RegExp.$2;
          }
          dt.push(Number(t));
          data.push(s);
        }
      }
      search();
    }
  }
  xmlhttp.send("");
}

function maxindent()
{
  var max = 0;
  var ind;
  for(var i=0;i<data.length;i++){
    ind = indent(i);
    if(ind > max) max = ind;
  }
  return max;
}

function calcdoi(){
  var q = document.getElementById("query");
  var pbs = new POBoxSearch(assocwiki_pobox_dict);
  var re = null;
  if(q && q.value != '') re = pbs.regexp(q.value,false);

  var maxind = maxindent();

  for(var i=0;i<data.length;i++){
    matched = (re ? re.exec(data[i]) : true);
    if(matched){
      doi[i] = maxind - indent(i);
    }
    else {
      doi[i] = 0 - indent(i) - 1;
    }
  }
}

function search(event)
{
  var kc;
  if(event) kc = keycode(event);
  if(event == null || kc != KC.down && kc != KC.up && kc != KC.left && kc != KC.right){
    calcdoi();
    zoomlevel = 0;
    display();
  }
  return false;
}

//setup();
//getdata();

