/*
 * HTMLとJavaScriptによる、編集可能なテーブルコンポーネント
 * デフォルト実装
 */

function ListAndDetailsInit() {
//    AppUtil.EXECUTION = AppUtil.DEBUGLOG;
//    AppUtil.applcationInit();
try {
    var targetTableA = document.getElementById("app3_table1_a");
    var controllerA = document.getElementById("app3_table1_a_controller");
    var targetTableB = document.getElementById("app3_table1_b");
    var controllerB = document.getElementById("app3_table1_b_controller");

    var shellA = document.getElementById("app3_a");
    var shellB = document.getElementById("app3_b");

    var viewA = new  ListView(targetTableA, controllerA);
    var viewB = new  DetailsView(targetTableB, controllerB);
//    viewB.selectedColumn = 2;
//    viewA.addSelectionListener(viewB);
//    viewB.addSelectionListener(viewA);

    var model = new ListAndDetailsModel();

    var filterA = new ListViewFilterModel(model);
    viewA.setModel(filterA);

    var filterB = new DetailsViewFilterModel(model);
    viewB.setModel(filterB);
    viewA.addSelectionListener(filterB);

    controllerA.onfocus = function (e) {

        HtmlUtil.addClassValue(shellA, "onfocus");
        var h2 = document.getElementById("title_003");
        HtmlUtil.scrollTo(h2, 10);
    }
    controllerA.onblur = function (e) {

        HtmlUtil.removeClassValue(shellA, "onfocus");
    }
    controllerB.onfocus = function (e) {

        HtmlUtil.addClassValue(shellB, "onfocus");
//        var h2 = document.getElementById("title_003");
//        HtmlUtil.scrollTo(h2, 10);
//        viewB.selectedRow = 1;
//        viewB.selectedColumn = 1;
//        viewB.selectRow();
//        viewB.selectColumn();
    }
    controllerB.onblur = function (e) {

        HtmlUtil.removeClassValue(shellB, "onfocus");
    }
}
catch (e) {
    AppUtil.printExceptionLog(e);
}
}


/**
 * ビュー
 */
/**
 * 一覧表示を行うビュー
 */
ListView.prototype = new DefaultTableView();
function  ListView(targetTable, controller) {
    this.initTableView(targetTable, controller, 0);
    this.selectedColumn = 1;
}

/*
 * ビューの選択行が変化した時に呼ばれる。
 * @param rowIndex 新しく選択された行のインデックス。
 * @param columnIndex 新しく選択された列のインデックス。
 * @param view イベントを発行したビュー
 */
ListView.prototype.selectionChanged = function (rowIndex,
                                                columnIndex,
                                                view) {
    if (rowIndex != this.selectedRow) {

        this.selectRowAt(rowIndex);
        this.fireSelectionChanged(this.selectedRow, this.selectedColumn);
    }
}


/**
 * 詳細表示を行うビュー
 */
DetailsView.prototype = new DefaultTableView();
function  DetailsView(targetTable, controller) {
    this.initTableView(targetTable, controller, 0);
    this.selectedRow = 1;
    this.selectedColumn = 1;
}

/*
 * 選択行を一行上げる。
 * 選択行が変更された場合に、必ず先頭の編集可能セルを選択するようにする。
 * 編集可能セルが存在しない行の場合は、その上の行を選択する。
 */
DetailsView.prototype.goUp = function (evnt) {

    for (var i = this.selectedRow - 1; i >= 0; i --) {

        for (var j = 0; j < this.model.getColumnCountAt(i); j ++) {

            if (this.model.isCellEditable(i, j)) {

                this.selectRowAt(i);
                this.selectColumnAt(j);
                this.fireSelectionChanged(this.selectedRow, this.selectedColumn);
                return;
            }
        }
    }
}

/*
 * 選択行を一行下げる。
 */
DetailsView.prototype.goDown = function (evnt) {

    for (var i = this.selectedRow + 1; i < this.model.getRowCount(); i ++) {

        for (var j = 0; j < this.model.getColumnCountAt(i); j ++) {

            if (this.model.isCellEditable(i, j)) {

                this.selectRowAt(i);
                this.selectColumnAt(j);
                this.fireSelectionChanged(this.selectedRow, this.selectedColumn);
                return;
            }
        }
    }
//    this.selectRowAt(this.selectedRow + 1);
//    this.fireSelectionChanged(this.selectedRow, this.selectedColumn);
}

/*
 * テーブルの内容が変更されたことを、通知します。
 * TableModelから呼び出される。
 * セル単位の編集可否を、セルのclassに設定する機能を実装。
 * フッタの合計処理を呼び出す機能を追加。
 */
DetailsView.prototype.tableChanged = function (tableModelEvent) {

    if (null == this.model) {

        return;
    }

    var startRow;
    var endRow;
    var startColumn;
    var endColumn;

    /*
     * イベントが指定されていないか、スタート行がマイナス指定の場合は、
     * テーブルを全面的に書き換える。
     */
    if (! tableModelEvent || 0 > tableModelEvent.startRow) {

        this.initializeView();
        startRow = 0;
        endRow = this.jsTable.getBodiesRowCount() - 1;
        startColumn = 0;
        endColumn = 99999;
    }
    else {

        startRow    = tableModelEvent.startRow;
        endRow      = tableModelEvent.endRow;
        startColumn = tableModelEvent.startColumn;
        endColumn   = tableModelEvent.endColumn;
    }

    for (var i = startRow; i <= endRow; i ++) {

        var row = this.jsTable.getRowFromBodiesAt(i);
        var cellCount = (endColumn < row.cells.length) ?
                            endColumn : (row.cells.length - 1);
        for (var j = startColumn; j <= cellCount; j ++) {

            if (-1 == this.model.changeIndexViewToModel(i, j)) {

                continue;
            }

            this.setViewValue(i, j);

            if (this.model.isCellEditable(i, j)) {

                this.setEditableValue(i, j);
                var cell = this.getCellAt(i, j);
                HtmlUtil.removeClassValue(cell, "nonEditableCell");
                HtmlUtil.addClassValue(cell, "editableCell");
            }
        }
    }

    /*
     * フッタの合計欄を再表示させる。
     */
//    this.setViewValue(99999, 4);
}

/*
 * ビューの選択行が変化した時に呼ばれる。
 * @param rowIndex 新しく選択された行のインデックス。
 * @param columnIndex 新しく選択された列のインデックス。
 * @param view イベントを発行したビュー
 */
DetailsView.prototype.selectionChanged = function (rowIndex,
                                                   columnIndex,
                                                   view) {
    if (rowIndex != this.selectedRow) {

        this.selectRowAt(rowIndex);
        this.fireSelectionChanged(this.selectedRow, this.selectedColumn);
    }
}


/**
 * テーブルモデル
 */
ListAndDetailsModel.prototype = new DefaultAppModel();
/**
 * 列インデックスの定義
 * インデックスがソース中に散らばると、仕変に弱くなる。
 */
ListAndDetailsModel.MEMBER_CODE     =  0;   // 会員コード
ListAndDetailsModel.SEI_KANJI       =  1;   // 姓（漢字）
ListAndDetailsModel.MEI_KANJI       =  2;   // 名（漢字）
ListAndDetailsModel.SEI_KANA        =  3;   // 姓（カナ）
ListAndDetailsModel.MEI_KANA        =  4;   // 名（カナ）
ListAndDetailsModel.MAIL            =  5;   // メールアドレス
ListAndDetailsModel.POINT           =  6;   // 現在ポイント
ListAndDetailsModel.POINT_TOTAL     =  7;   // ポイント総計
ListAndDetailsModel.TRUST           =  8;   // 信用度
ListAndDetailsModel.SEX             =  9;   // 男女区分
ListAndDetailsModel.ADMISSION_DATE  = 10;   // 入会年月日
ListAndDetailsModel.SECESSION_DATE  = 11;   // 退会年月日
ListAndDetailsModel.STOP_FLG        = 12;   // 休止区分
ListAndDetailsModel.STOP_BIGIN_DATE = 13;   // 休止開始年月日
ListAndDetailsModel.STOP_END_DATE   = 14;   // 休止終了年月日
ListAndDetailsModel.ZIPCODE         = 15;   // 郵便番号
ListAndDetailsModel.ADDRESS1        = 16;   // 住所１
ListAndDetailsModel.ADDRESS2        = 17;   // 住所２
/**
 * コンストラクタ
 */
function ListAndDetailsModel() {
    this.initTableModel();
    this.rows = [
        [ "A00007",
          "本村",
          "洋介",
          "モトムラ",
          "ヨウスケ",
          "y_motomura@skc.co.jp",
          "872",
          "4872",
          "AA",
          "1",
          "20031210",
          "",
          "1",
          "",
          "",
          "123-4567",
          "愛知県東小笠原市",
          "コーポ東1204"],
        [ "A00021",
          "川中島",
          "博士",
          "カワナカジマ",
          "ヒロシ",
          "hiro@mail.jjxpss.jp",
          "4",
          "10004",
          "AA",
          "1",
          "20010810",
          "",
          "1",
          "",
          "",
          "345-9999",
          "岐阜県大湊南市大湊",
          "ヴィラ大湊308"],
        [ "A00028",
          "阿田川",
          "奈美華",
          "アタガワ",
          "ナミカ",
          "namika@mail.uucs.jp",
          "2870",
          "24870",
          "AA",
          "2",
          "20031210",
          "",
          "2",
          "20050401",
          "20051130",
          "333-4444",
          "静岡県夢想市夢想",
          "夢想パレス128-304"]
    ];
    this.columnCount = this.rows[0].length;
}

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

    var value = this.getEditableValueAt(rowIndex, columnIndex);

    if (null == value) {

        return "";
    }

    switch (columnIndex) {

        case ListAndDetailsModel.ADMISSION_DATE  :   // 入会年月日
        case ListAndDetailsModel.SECESSION_DATE  :   // 退会年月日
        case ListAndDetailsModel.STOP_BIGIN_DATE :   // 休止開始年月日
        case ListAndDetailsModel.STOP_END_DATE   :   // 休止終了年月日

            value = this.formatDate(value);
            break;

        default :
    }

    return value;
}

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

    if (ListAndDetailsModel.MEMBER_CODE == columnIndex ||
        ListAndDetailsModel.POINT == columnIndex ||
        ListAndDetailsModel.POINT_TOTAL == columnIndex ||
        ListAndDetailsModel.TRUST == columnIndex) {

        return false;
    }

    return true;
}

/**
 * 指定のセルの内容が変更されたことを、全てのリスナーに通知する。
 * 計算処理に関係する列が変更された場合は、合計欄も再表示するように指示する。
 * @param rowIndex : 数値 : 値が変更された行インデックス。
 * @param columnIndex : 数値 : 値が変更された列インデックス。
 */
ListAndDetailsModel.prototype.fireTableCellUpdated = function (rowIndex, columnIndex) {

    /*
     * 祖先クラスのメソッドを呼び出す。
     */
    DefaultTableModel.prototype.fireTableCellUpdated.call(this,
                                                          rowIndex,
                                                          columnIndex);
}


/*
 * 上の表のフィルタ
 */
ListViewFilterModel.prototype = new FilterModel();

/*
 * コンストラクタ
 * @param model : テーブルモデル : 実際にデータを格納するモデル
 */
function ListViewFilterModel(model) {
    this.orgModel = model;
}

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

    if (0 == columnIndex) {

        return this.orgModel.getValueAt(rowIndex, columnIndex);
    }
    else if (1 == columnIndex) {

        var sei = this.orgModel.getValueAt(rowIndex,
                                           ListAndDetailsModel.SEI_KANJI);
        var mei = this.orgModel.getValueAt(rowIndex,
                                           ListAndDetailsModel.MEI_KANJI);
        return sei + "  " + mei;
    }
    else if (2 == columnIndex) {

        var sei = this.orgModel.getValueAt(rowIndex,
                                           ListAndDetailsModel.SEI_KANA);
        var mei = this.orgModel.getValueAt(rowIndex,
                                           ListAndDetailsModel.MEI_KANA);
        return sei + "  " + mei;
    }

    return "";
}

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

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

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

    return false;
}

/*
 * ビューとして、実装が必須のメソッド
 */
ListViewFilterModel.prototype.tableChanged = function (modelEvent) {

    if (null != modelEvent && 0 <= modelEvent.startRow) {

        if (1 == modelEvent.startColumn || 2 == modelEvent.startColumn) {

            modelEvent.startColumn = 1;
            modelEvent.endColumn = 1;
        }
        else if (3 == modelEvent.startColumn || 4 == modelEvent.startColumn) {

            modelEvent.startColumn = 2;
            modelEvent.endColumn = 2;
        }
    }
    this.view.tableChanged(modelEvent);
}


/*
 * 下の表のフィルタ
 */
DetailsViewFilterModel.prototype = new FilterModel();

DetailsViewFilterModel.columnCountTable = [2, 5, 5, 2, 8, 8, 8, 2, 2, 2];

/*
 * コンストラクタ
 * @param model : テーブルモデル : 実際にデータを格納するモデル
 */
function DetailsViewFilterModel(model) {
    this.orgModel = model;
    this.dispRow = 0;
}

/*
 * テーブルモデルとして、実装が必須のメソッド
 */
/**
 * 行数を返す。
 */
DetailsViewFilterModel.prototype.getRowCount = function () {

    return 10;
}

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

    return -1;
}

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

    return DetailsViewFilterModel.columnCountTable[rowIndex];
}

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

    var newColumnIndex = this.changeIndexViewToModel(rowIndex, columnIndex);
    return this.orgModel.getValueAt(this.dispRow, newColumnIndex);
}

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

    var newColumnIndex = this.changeIndexViewToModel(rowIndex, columnIndex);
    return this.orgModel.getEditableValueAt(this.dispRow, newColumnIndex);
}

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

    var newColumnIndex = this.changeIndexViewToModel(rowIndex, columnIndex);
    this.orgModel.setValueAt(value, this.dispRow, newColumnIndex);
}

/**
 * 編集可否判定
 * 指定セルが編集可能かどうかを返す。
 * @param rowIndex : 数値 : 行インデックス。
 * @param columnIndex : 数値 : 列インデックス。
 * @return this.orgModel.isCellEditableの戻り値
 */
DetailsViewFilterModel.editableTable = [
    [false, true],
    [false, true, false, false, true],
    [false, true, false, false, true],
    [false, true],
    [false, true, false, false, true, false, false, true],
    [false, true, false, false, true, false, false, true],
    [false, true, false, false, true, false, false, true],
    [false, true],
    [false, true],
    [false, true]
];
DetailsViewFilterModel.prototype.isCellEditable = function (rowIndex, columnIndex) {

    var newColumnIndex = this.changeIndexViewToModel(rowIndex, columnIndex);

    if (-1 == newColumnIndex) {

        return false;
    }

    var rtn = DetailsViewFilterModel.editableTable[rowIndex][columnIndex];

    if (! rtn) {

        return false;
    }
    return this.orgModel.isCellEditable(this.dispRow, newColumnIndex);
}

/**
 * 列インデックス変換
 * ビューの列インデックスを、データモデルの列インデックスに変換する。
 * @param columnIndex : 数値 : ビューの列インデックス。
 * @return : 数値 : データモデルの列インデックス
 */
DetailsViewFilterModel.viewToModelTable = [
    [-1, 0],
    [-1, 1, -1, -1, 2],
    [-1, 3, -1, -1, 4],
    [-1, 5],
    [-1, 6, -1, -1, 7, -1, -1, 8],
    [-1, 9, -1, -1, 10, -1, -1, 11],
    [-1, 12, -1, -1, 13, -1, -1, 14],
    [-1, 15],
    [-1, 16],
    [-1, 17]
];

DetailsViewFilterModel.prototype.changeIndexViewToModel = function (rowIndex, columnIndex) {

    if (DetailsViewFilterModel.viewToModelTable.length <= rowIndex) {

        return -1;
    }

    var row = DetailsViewFilterModel.viewToModelTable[rowIndex];

    if (row.length <= columnIndex) {

        return -1;
    }

    return row[columnIndex];
}

/**
 * 列インデックス変換
 * データモデルの列インデックスを、ビューのインデックスに変換する。
 * @param columnIndex : 数値 : データモデルの列インデックス。
 * @return : 配列 : ビューの行インデックスと列インデックスのペア
 */
DetailsViewFilterModel.modelToViewTable = [
    [0, 1], [1, 1], [1, 4], [2, 1], [2, 4], [3, 1], [4, 1], [4, 4], [4, 7],
    [5, 1], [5, 4], [5, 7], [6, 1], [6, 4], [6, 7], [7, 1], [8, 1], [9, 1]
];

DetailsViewFilterModel.prototype.changeIndexModelToView = function (columnIndex) {

    return DetailsViewFilterModel.modelToViewTable[columnIndex];
}

/*
 * ビューとして、実装が必須のメソッド
 */
DetailsViewFilterModel.prototype.tableChanged = function (modelEvent) {

    if (null != modelEvent && 0 <= modelEvent.startRow) {

        var pair = this.changeIndexModelToView(modelEvent.startColumn);
        modelEvent.startColumn = pair[1];
        modelEvent.endColumn = pair[1];
        modelEvent.startRow = pair[0];
        modelEvent.endRow = pair[0];
    }
    this.view.tableChanged(modelEvent);
}

DetailsViewFilterModel.prototype.selectionChanged = function (rowIndex,
                                                              columnIndex,
                                                              view) {

    if (this.dispRow == rowIndex) {

        return;
    }

    this.dispRow = rowIndex;

    this.view.tableChanged(null);
}
