/*
 * HTMLとJavaScriptによる、編集可能なテーブルコンポーネント
 * テーブルモデルのデフォルト実装
 */
/**
 * デフォルトテーブルモデル
 */
function DefaultTableModel() {}

DefaultTableModel.prototype.initTableModel = function () {

    this.listenerList = new Array();
    this.rows = new Array();
    this.columnCount = -1;
}

/**
 * 行数を返す。
 */
DefaultTableModel.prototype.getRowCount = function () {

    return this.rows.length;
}

/**
 * 列数を返す。
 * このメソッドが-1を返すと、テーブルビューは、
 * 行毎に異なる列数で、テーブルを作成する。
 */
DefaultTableModel.prototype.getColumnCount = function () {

    return this.columnCount;
}

/**
 * 指定行の列数を返す。
 * @param rowIndex : 数値 : 行インデックス。
 */
DefaultTableModel.prototype.getColumnCountAt = function (rowIndex) {

    if (-1 != this.columnCount) {

        return this.columnCount;
    }

    var values = this.rows[rowIndex];

    if (values) {

        return values.length;
    }

    return 0;
}

/**
 * 列のタイトルを返す。
 * @param columnIndex : 数値 : 列インデックス。
 * @return 文字列 : 指定カラムのタイトル。
 */
DefaultTableModel.prototype.getColumnTitleAt = function (columnIndex) {

    return "" + columnIndex;
}

/**
 * リスナの登録
 * モデルの内容が変更されたことを通知する、リスナを登録する。
 * リスナは、以下のメソッドを実装している必要がある。
 *  tableChanged(TableModelEvent)
 * @param view : Object : リスナ
 */
DefaultTableModel.prototype.addTableModelListener = function (view) {

    if (! view) {

        throw WebApplyUtil.createException(
                new Error(),
                "DefaultTableModel#addTableModelListener:"+
                "IllegalArgument:"+
                "view is null.");
    }

    if (! view.tableChanged) {

        throw WebApplyUtil.createException(
                new Error(),
                "DefaultTableModel#addTableModelListener:"+
                "NoSuchMethod:"+
                "view.tableChanged");
    }

    this.listenerList.push(view);

    this.fireTableStructureChanged();
}

/**
 * モデルの内容が変更されたことを、全てのリスナーに通知する。
 * @param rowIndex : 数値 : 値が変更された行インデックス。
 * @param columnIndex : 数値 : 値が変更された列インデックス。
 */
DefaultTableModel.prototype.fireTableChanged = function (modelEvent) {

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

        var view = this.listenerList[i];

        if (view) {

            var newEvent = null;

            if (null != modelEvent) {

                newEvent = new TableModelEvent(modelEvent.model,
                                               modelEvent.startRow,
                                               modelEvent.endRow,
                                               modelEvent.startColumn,
                                               modelEvent.endColumn,
                                               modelEvent.type);
            }

            view.tableChanged(newEvent);
        }
    }
}

/**
 * 指定のセルの内容が変更されたことを、全てのリスナーに通知する。
 * @param rowIndex : 数値 : 値が変更された行インデックス。
 * @param columnIndex : 数値 : 値が変更された列インデックス。
 */
DefaultTableModel.prototype.fireTableCellUpdated = function (rowIndex, columnIndex) {

    var modelEvent = new TableModelEvent(this,
                                         rowIndex,
                                         rowIndex,
                                         columnIndex,
                                         columnIndex,
                                         TableModelEvent.CELL_UPDATE);

    this.fireTableChanged(modelEvent);
}

/**
 * 指定の行が追加されたことを、全てのリスナーに通知する。
 * @param rowIndex : 数値 : 追加された行インデックス。
 */
DefaultTableModel.prototype.fireTableRowInserted = function (rowIndex) {

    var modelEvent = new TableModelEvent(this,
                                         rowIndex,
                                         -1,
                                         -1,
                                         -1,
                                         TableModelEvent.ROW_INSERT);

    this.fireTableChanged(modelEvent);
}

/**
 * 指定の行が削除されたことを、全てのリスナーに通知する。
 * @param rowIndex : 数値 : 削除された行インデックス。
 */
DefaultTableModel.prototype.fireTableRowDeleted = function (rowIndex) {

    var modelEvent = new TableModelEvent(this,
                                         rowIndex,
                                         -1,
                                         -1,
                                         -1,
                                         TableModelEvent.ROW_DELETE);

    this.fireTableChanged(modelEvent);
}

/**
 * モデルの構造が変更されたことを、全てのリスナーに通知する。
 */
DefaultTableModel.prototype.fireTableStructureChanged = function () {

    this.fireTableChanged(null);
}

/**
 * 指定セルの表示用の値を取得する。
 * @param rowIndex : 数値 : 値を取得するセルの行インデックス。
 * @param columnIndex : 数値 : 値を取得するセルの列インデックス。
 * @return モデルが格納している値
 */
DefaultTableModel.prototype.getValueAt = function (rowIndex, columnIndex) {

    return this.getEditableValueAt(rowIndex, columnIndex);
}

/**
 * 指定セルの編集用の値を取得する。
 * @param rowIndex : 数値 : 値を取得するセルの行インデックス。
 * @param columnIndex : 数値 : 値を取得するセルの列インデックス。
 * @return モデルが格納している値。
 */
DefaultTableModel.prototype.getEditableValueAt = function (rowIndex, columnIndex) {

    var values = this.rows[rowIndex];

    if (values) {

        var value = values[columnIndex];
        if (value) {

            return value;
        }
    }

    return "";
}

/**
 * 指定の値を、モデルにセットする。
 * @param value : Object : セットする値。
 * @param rowIndex : 数値 : 値をセットする行数。
 * @param columnIndex : 数値 : 値をセットする列数。
 */
DefaultTableModel.prototype.setValueAt = function (value, rowIndex, columnIndex) {

    var values = this.rows[rowIndex];
    var date = values[columnIndex] = value;

    this.fireTableCellUpdated(rowIndex, columnIndex);
}

/**
 * 編集可否判定
 * 指定セルが編集可能かどうかを返す。
 * @param rowIndex : 数値 : 行インデックス。
 * @param columnIndex : 数値 : 列インデックス。
 * @return 必ずtrue
 */
DefaultTableModel.prototype.isCellEditable = function (rowIndex, columnIndex) {

    return true;
}

/**
 * 指定の行に、空の行を挿入する。
 * @param rowIndex : 数値 : 挿入する行インデックス。
 *                   -1を指定すると、最期に行を追加する。
 * @param values : 配列 : 新規行の内容の配列。
 */
DefaultTableModel.prototype.insertRow = function (rowIndex) {

    var values = new Array();
    this.rows.splice(rowIndex, 0, values);
    this.fireTableRowInserted(rowIndex);
}

/**
 * 指定のインッデクスの行を削除する。
 * @param rowIndex : 数値 : 削除する行インデックス。
 */
DefaultTableModel.prototype.deleteRow = function (rowIndex) {

    var values = new Array();
    this.rows.splice(rowIndex, 1);
    this.fireTableRowDeleted(rowIndex);
}

