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

function MultiInit() {
//    AppUtil.EXECUTION = AppUtil.DEBUGLOG;
//    AppUtil.applcationInit();
    var targetTableA = document.getElementById("app2_table1_a");
    var controllerA = document.getElementById("app2_table1_a_controller");
    var targetTableB = document.getElementById("app2_table1_b");
    var controllerB = document.getElementById("app2_table1_b_controller");

    var shellA = document.getElementById("app2_a");
    var shellB = document.getElementById("app2_b");

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

    var model = new MultiViewModel();

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

    var filterB = new FilterModelB(model);
    viewB.setModel(filterB);

    controllerA.onfocus = function (e) {

        HtmlUtil.addClassValue(shellA, "onfocus");
        var h2 = document.getElementById("title_002");
        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_002");
//        HtmlUtil.scrollTo(h2, 10);
    }
    controllerB.onblur = function (e) {

        HtmlUtil.removeClassValue(shellB, "onfocus");
    }
}


/**
 * ビュー
 */
MultiTableView.prototype = new DefaultTableView();
function MultiTableView(targetTable, controller) {
    this.initTableView(targetTable, controller, 0);
    this.selectedColumn = 1;
}

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

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


/**
 * テーブルモデル
 */
MultiViewModel.prototype = new DefaultAppModel();

/**
 * 列インデックスの定義
 * インデックスがソース中に散らばると、仕変に弱くなる。
 */
MultiViewModel.SLIPNUMBER   = 0;    // 伝票番号
MultiViewModel.ITEMNAME     = 1;    // 商品名
MultiViewModel.DATE         = 2;    // 日付
MultiViewModel.PRICE        = 3;    // 単価
MultiViewModel.NUMBER       = 4;    // 個数
MultiViewModel.TOTAL        = 5;    // 合計
MultiViewModel.SCHEDULED    = 6;    // 発送予定日
MultiViewModel.COMPLETION   = 7;    // 発送完了日
MultiViewModel.DESTINATION  = 8;    // 発送先番号
MultiViewModel.REMARKS      = 9;    // 備考

/**
 * コンストラクタ
 */
function MultiViewModel() {
    this.initTableModel();
    this.columnCount = 10;
    this.rows = [["ASC-01244", "エクスカリバー", "21450403",  12000,  6, 0, "21450518", null, "A119", ""],
                 ["AKK-08700", "黒猫の呪い", "21450408", 180000,  2, 0, "21450518", null, "A119", "取り扱い注意"],
                 ["AZD-00080", "?", "21450413",   2500000,  1, 0, "21450518", null, "A119", "魔導師以外取り扱い禁止"],
                 ["AGM-98001", "魔人", "21450413",    800, 14, 0, "21450526", "21450511", "F204", "火気厳禁"],
                 ["BAA-00002", "精霊の炎", "21450425",    725,  5, 0, "21450526", null, "F204", "水塗れ注意"]];
}

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

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

    if (null == value) {

        return "";
    }

    switch (columnIndex) {

        case MultiViewModel.SLIPNUMBER :    // 伝票番号
        case MultiViewModel.ITEMNAME :      // 商品名
        case MultiViewModel.NUMBER :        // 個数
        case MultiViewModel.DESTINATION :   // 発送先番号
        case MultiViewModel.REMARKS :       // 備考

            break;

        case MultiViewModel.DATE :          // 日付
        case MultiViewModel.SCHEDULED :     // 発送予定日
        case MultiViewModel.COMPLETION :    // 発送完了日

            value = this.formatDate(value);
            break;

        case MultiViewModel.PRICE :    // 単価

            value = this.formatMoney("" + value);
            break;

        case MultiViewModel.TOTAL :    // 合計

            var price = this.getEditableValueAt(rowIndex, MultiViewModel.PRICE);
            var number = this.getEditableValueAt(rowIndex, MultiViewModel.NUMBER);
            value = "" + (price * number);
            value = this.formatMoney(value);
            break;

        default :
    }

    return value;
}

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

    if (MultiViewModel.SLIPNUMBER == columnIndex ||
        MultiViewModel.TOTAL == columnIndex ||
        MultiViewModel.COMPLETION == columnIndex ||
        MultiViewModel.DESTINATION == columnIndex) {

        return false;
    }

    return true;
}

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

    var startColumn = columnIndex;
    var endColumn = columnIndex;
    if (MultiViewModel.PRICE == columnIndex ||
        MultiViewModel.NUMBER == columnIndex) {
        startColumn = MultiViewModel.PRICE;
        endColumn = MultiViewModel.TOTAL;
    }
    var modelEvent = new TableModelEvent(this,
                                         rowIndex,
                                         rowIndex,
                                         startColumn,
                                         endColumn,
                                         TableModelEvent.CELL_UPDATE);

    this.fireTableChanged(modelEvent);
}

/*
 * フィルターモデル
 * ビューとモデルの間で、列インデックスの変換などを行う。
 * ビューに対してはモデルとして、モデルに対してはビューとして
 * 見せかける。
 */
FilterModel.prototype = new DefaultTableModel();

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

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

    return this.orgModel.getRowCount();
}

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

    return this.orgModel.getColumnCount();
}

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

    return this.orgModel.getColumnCountAt(rowIndex);
}

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

    return this.orgModel.getColumnTitleAt(columnIndex);
}

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

    this.view = view;
    this.orgModel.addTableModelListener(this);
}

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

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

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

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

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

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

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

    var newColumnIndex = this.changeColumnIndex(columnIndex);
    return this.orgModel.isCellEditable(rowIndex, newColumnIndex);
}

/**
 * 列インデックス変換
 * ビューの列インデックスを、データモデルの列インデックスに変換する。
 * @param columnIndex : 数値 : ビューの列インデックス。
 * @return : 数値 : データモデルの列インデックス
 */
FilterModel.prototype.changeColumnIndex = function (columnIndex) {

    return columnIndex;
}

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

    this.fireTableChanged(modelEvent);
}


/*
 * 上の表のフィルタ
 */
FilterModelA.prototype = new FilterModel();
/*
 * 列インデックスの変換用テーブル
 */
FilterModelA.indexTable = [
    MultiViewModel.SLIPNUMBER,
    MultiViewModel.ITEMNAME,
    MultiViewModel.DATE,
    MultiViewModel.PRICE,
    MultiViewModel.NUMBER,
    MultiViewModel.TOTAL
];
FilterModelA.indexTable2 = [0, 1, 2, 3, 4, 5, -1, -1, -1, -1];

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

/**
 * 列インデックス変換
 * ビューの列インデックスを、データモデルの列インデックスに変換する。
 * @param columnIndex : 数値 : ビューの列インデックス。
 * @return : 数値 : データモデルの列インデックス
 */
FilterModelA.prototype.changeColumnIndex = function (columnIndex) {

    return FilterModelA.indexTable[columnIndex];
}

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

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

        var newStartColumn;
        var newEndColumn;

        newStartColumn = FilterModelA.indexTable2[modelEvent.startColumn];
        newEndColumn = FilterModelA.indexTable2[modelEvent.endColumn];

        if (-1 == newStartColumn) {

            /*
             * 合計より後ろの値が変更となった場合は、
             * 無視する。
             */
            return;
        }
        modelEvent.startColumn = newStartColumn;
        modelEvent.endColumn   = newEndColumn;
    }
    this.view.tableChanged(modelEvent);
}


/*
 * 下の表のフィルタ
 */
FilterModelB.prototype = new FilterModel();
/*
 * 列インデックスの変換用テーブル
 */
FilterModelB.indexTable = [
    MultiViewModel.SLIPNUMBER,
    MultiViewModel.ITEMNAME,
    MultiViewModel.SCHEDULED,
    MultiViewModel.COMPLETION,
    MultiViewModel.DESTINATION,
    MultiViewModel.REMARKS
];

FilterModelB.indexTable2 = [0, 1, -1, -1, -1, -1, 2, 3, 4, 5];

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

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

    if (MultiViewModel.ITEMNAME == columnIndex) {

        return false;
    }
    var newColumnIndex = this.changeColumnIndex(columnIndex);
    return this.orgModel.isCellEditable(rowIndex, newColumnIndex);
}

/**
 * 列インデックス変換
 * ビューの列インデックスを、データモデルの列インデックスに変換する。
 * @param columnIndex : 数値 : ビューの列インデックス。
 * @return : 数値 : データモデルの列インデックス
 */
FilterModelB.prototype.changeColumnIndex = function (columnIndex) {

    return FilterModelB.indexTable[columnIndex];
}

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

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

        var newStartColumn;
        var newEndColumn;

        newStartColumn = FilterModelB.indexTable2[modelEvent.startColumn];
        newEndColumn = FilterModelB.indexTable2[modelEvent.endColumn];

        if (-1 == newStartColumn) {

            /*
             * 合計より後ろの値が変更となった場合は、
             * 無視する。
             */
            return;
        }
        modelEvent.startColumn = newStartColumn;
        modelEvent.endColumn   = newEndColumn;
    }
    this.view.tableChanged(modelEvent);
}

