/*
 * JavaScriptによる、スプレッドシートコンポーネント
 *
 * Copyright (C) 2004 Y System Create Corporation. All Rights Reserved.
 * $Id: table.js,v 1.4 2004/10/30 06:21:06 bison Exp $
 */
/*
 * キーボードによる、選択セルの移動と、入力フィールドへの
 * 入力フォーカス移動をコントロールするサンプル。
 * イベント内でフォーカス移動や、入力フィールドの消滅などを行う場合は、
 * onkeypress イベントで処理する。
 *
 */
TableEventController.eventControllerList = null;
var controllerId = "_eventController";
var cellInputId = "_cellInput";
/*
 * イニシャライザ
 * 唯一のHTMLドキュメントとのインターフェイス
 * このメソッドを通して、HTMLドキュメント内のエレメントに対し、
 * イベントハンドラを設定する。
 * このメソッドは、bodyエレメントの、onloadイベントで実行するよう
 * 設定されなければならない。
 */
TableEventController.evhOnloadInit = function (tableId) {

  var tbl = document.getElementById(tableId);
  var table1 = new TableEventController(tbl);

  var inpt = document.getElementById(tableId + controllerId);

  if (null == TableEventController.eventControllerList) {

    TableEventController.eventControllerList = new Object();
  }
  TableEventController.eventControllerList[inpt.form.id] = table1;

  inpt.onfocus    = TableEventController.evhControllerOnfocus;
  inpt.onblur     = TableEventController.evhControllerOnblur;
  inpt.onkeydown  = TableEventController.evhOnkeydown;
  inpt.onkeypress = TableEventController.evhOnkeypress;
}

/*
 * コンストラクタ
 */
function TableEventController(tbl) {

  this.row = 0;
  this.column = 0;
  this.isFout = true;
  this.tableId = tbl.id;
  this.controllerId = tbl.id + controllerId;
  this.cellInputId = tbl.id + cellInputId;
  this.targetTable = new ComYscjp_TableWrapper(tbl);

  /*
   * テーブル内の全てのinput要素をリストし、
   * フォーカス取得／喪失時のイベントハンドラをセットする。
   */
  var inputList = tbl.getElementsByTagName("input");
  for (var i = 0; i < inputList.length; i ++) {

    inputList.item(i).onblur = TableEventController.evhCellOnblur;
    inputList.item(i).onfocus = TableEventController.evhCellOnfocus;
    inputList.item(i).onkeypress = TableEventController.evhEnterClose;
  }
}

/*
 * セルの入力フィールドが、フォーカスを取得した時のイベントハンドラ。
 * 編集可能とし、自分自身の行数と列数で、カレントの選択行と選択列を
 * 設定する。
 * マウスにより、フォーカスを取得した場合の処理。
 */
TableEventController.evhCellOnfocus = function (ev) {

  var evntSrc = JsUtil.getEventSource(ev);
  var controller = TableEventController.searchInstance(ev);

  var cellElement = evntSrc.parentNode;
  var rowElement = cellElement.parentNode;
  controller.row = rowElement.sectionRowIndex;
  controller.column = cellElement.cellIndex;
  evntSrc.readOnly = false;
  evntSrc.focus();
  evntSrc.select();
}

/*
 * セルの入力フィールドが、フォーカスを喪失した時のイベントハンドラ。
 * 編集不可とする。
 */
TableEventController.evhCellOnblur = function (ev) {

  var evntSrc = JsUtil.getEventSource(ev);
  evntSrc.readOnly = true;
  var value = evntSrc.value;
  evntSrc.value = "";
  evntSrc.value = value;
}

/*
 * テーブルの現在行と現在列の背景色を変更し、
 * カレントセルの背景色も変更する。
 */
TableEventController.evhControllerOnfocus = function (ev) {

  var controller = TableEventController.searchInstance(ev);

  controller.selectRowColumn("#fafafa", "#fafafa", "#afafaf");
}

/*
 * テーブルの現在行と現在列の背景色を元に戻す。
 */
TableEventController.evhControllerOnblur = function (ev) {

  var controller = TableEventController.searchInstance(ev);

  controller.selectRowColumn("", "", "");
}

TableEventController.prototype.selectRowColumn =
  function(rowBgColor, columnBgColor, cellBgColor) {

  var length = this.targetTable.getBodiesRowCount();

  for (var i = 0; i < length; i ++) {

    var rowItem = this.targetTable.getBodiesRowAt(i);
    var cells = rowItem.cells;
    cells.item(this.column).style.background = columnBgColor;
    if (i == this.row) {
      var cellLength = cells.length;
      for (var j = 0; j < cellLength; j ++) {
        if (j == this.column) {
          cells.item(j).style.background = cellBgColor;
        }
        else {
          cells.item(j).style.background = rowBgColor;
        }
      }
    }
  }
}

TableEventController.evhOnkeydown = function (ev) {

  ev = JsUtil.getTrueEvent(ev);
  var controller = TableEventController.searchInstance(ev);

  var rowUp = 0;
  var columnUp = 0;
  switch (ev.keyCode) {
    case 37 : // 左
      columnUp = -1;
      break;
    case 38 : // 上
      rowUp = -1;
      break;
    case 39 : // 右
      columnUp = 1;
      break;
    case 40 : // 下
      rowUp = 1;
      break;
    default :
      return true;
  }

  if (controller.targetTable.isValidIndex(controller.row + rowUp,
                                          controller.column + columnUp)) {

    controller.selectRowColumn("", "", "");
    controller.row += rowUp;
    controller.column += columnUp;
    controller.selectRowColumn("#fafafa", "#fafafa", "#afafaf");
  }
  return false;
}


TableEventController.evhOnkeypress = function (ev) {

  ev = JsUtil.getTrueEvent(ev);

  switch (ev.keyCode) {
    case 13 : // Enter
      var controller = TableEventController.searchInstance(ev);

      /*
       * 現在の選択セルを取得する。
       */
      var rowItem = controller.targetTable.getBodiesRowAt(controller.row);
      var curentCell = rowItem.cells.item(controller.column);
      curentCell.getElementsByTagName('input').item(0).focus();
      return false;
    default :
  }
}

TableEventController.searchInstance = function (ev) {

  if (null == TableEventController.eventControllerList) {

    AppUtil.printLog("TableEventController.eventControllerList is null.",
                     AppUtil.DEBUGLOG);
    return null;
  }

  var evntSrc = JsUtil.getEventSource(ev);

  var controller = TableEventController.eventControllerList[evntSrc.form.id];

  if (null == controller) {

    AppUtil.printLog("controller is null.", AppUtil.DEBUGLOG);
  }

  return controller;
}


TableEventController.evhEnterClose = function(ev) {

  ev = JsUtil.getTrueEvent(ev);
  var controller = TableEventController.searchInstance(ev);

  switch (ev.keyCode) {
    case 13 : // Enter
      document.getElementById(controller.controllerId).focus();
      return false;
      break;
    default :
      return true;
  }
}


/*
 * テーブルエレメントを、DOMで使いやすくするラッパクラス
 * コンストラクタ
 * 引数：
 * table : テーブルエレメント
 */
function ComYscjp_TableWrapper(table) {

  if (table) {

    if (table.tagName) {

      if (table.tagName.toLowerCase() == "table") {

        this.table = table;
        return;
      }
    }
  }

  throw "ComYscjp_TableWrapper:Illegal argment table is null";

}

/*
 * テーブルの総行数(ヘッダ・ボディ・フッタ含む)を返します。
 */
ComYscjp_TableWrapper.prototype.getRowCount = function() {

  return this.table.rows.length;
}

/*
 * テーブルのボディ部の合計行数を返します。
 */
ComYscjp_TableWrapper.prototype.getBodiesRowCount = function() {

  var bodies = this.table.tBodies;
  var length = bodies.length;
  var count = 0;
  for (var i = 0; i < length; i ++) {
    count += bodies.item(i).rows.length;
  }
  return count;
}

/*
 * 指定インデックスの行エレメントを、ボディ部から取得し返します。
 */
ComYscjp_TableWrapper.prototype.getBodiesRowAt = function(rowIndex) {

  var index = rowIndex;
  var bodies = this.table.tBodies;
  var bodiesLength = bodies.length;
  for (var i = 0; i < bodiesLength; i ++) {

    var body = bodies.item(i);
    var rowLength = body.rows.length;
    if (index < rowLength) {
      /*
       * このボディに該当行あり
       */
      return body.rows.item(index);
    }
    else {
      /*
       * このボディには該当行なし
       */
      index -= rowLength;
    }
  }
  /*
   * ここへ来てしまったら、引数不正
   * ボディにある総行数よりも、引数の方が大きい
   */
  throw "getBodiesRowAt:Illegal argment rowIndex("+rowIndex+")";
}

/*
 * 指定の行インデックスと列インッデクスが、有効かどうかをテストします。
 * 有効な場合true、無効な場合はfalseを返します。
 */
ComYscjp_TableWrapper.prototype.isValidIndex =
  function(rowIndex, columnIndex) {

  try {

    if (rowIndex < 0 || columnIndex < 0) {

      throw "";
    }

    var rowItem = this.getBodiesRowAt(rowIndex);

    if (columnIndex < rowItem.cells.length) {
      return true;
    }
  }
  catch (e) {
  }
  return false;
}
