/*
 * Trigger class.
 *
 * Copyright (C) 2007 SATOH Takayuki All Rights Reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package ts.util.table;

import java.io.Serializable;
import java.util.Collection;
import java.util.Map;

/**
 * トリガ・クラス。
 * <br>
 * トリガは、登録先のテーブルが変更される直前及び直後に呼び出され、変更の種類
 * と変更の前後に応じたメソッドが実行される。
 * <br>
 * 実行されるメソッドは、以下の通りである：
 * <table>
 * <tr>
 *  <th>メソッド名</th>
 *  <th>変更の種類</th>
 *  <th>変更の前後</th>
 * </tr>
 * <tr>
 *  <td>preAppend</td>
 *  <td>レコードの追加</td>
 *  <td>変更前</td>
 * </tr>
 * <tr>
 *  <td>postAppend</td>
 *  <td>レコードの追加</td>
 *  <td>変更後</td>
 * </tr>
 * <tr>
 *  <td>preUpdate</td>
 *  <td>レコードの更新</td>
 *  <td>変更前</td>
 * </tr>
 * <tr>
 *  <td>postUpdate</td>
 *  <td>レコードの更新</td>
 *  <td>変更後</td>
 * </tr>
 * <tr>
 *  <td>preDelete</td>
 *  <td>レコードの削除</td>
 *  <td>変更前</td>
 * </tr>
 * <tr>
 *  <td>postDelete</td>
 *  <td>レコードの削除</td>
 *  <td>変更後</td>
 * </tr>
 * </table>
 * <br>
 * 実行されるメソッドに渡される引数は共通しており、以下のものが渡される：
 * <ul>
 *  <li>テーブル・オブジェクト</li>
 *  <li>変更対象のレコード・オブジェクト</li>
 *  <li>変更するカラム・キーとその値を格納したマップ・オブジェクト（変更の種類
 *      が更新の場合のみ）</li>
 * </ul>
 * <br>
 * トリガ・オブジェクトは、
 * {@link ts.util.table.Table#addTrigger(ts.util.table.Trigger)}メソッドを
 * 使って追加されるが、テーブルの変更時に呼び出されるトリガ・オブジェクトは
 * 追加されたオブジェクトそのものではなく、そのクローン・オブジェクトである。
 * そのため、フィールド変数を持たせて変更前と変更後で利用するようにしたトリガ
 * を、複数のテーブルやマルチ・スレッドで利用しても支障はない。
 *
 * @param <C> カラム・キーのタイプ。 
 * @param <V> カラムの値のタイプ。
 *
 * @author  佐藤隆之.
 * @version $Revision: 1.2 $, $Date: 2011-08-01 15:29:33 $
 */
public abstract class Trigger<C,V> implements Cloneable, Serializable
{
  /** テーブル変更の種類を示す列挙クラス。 */
  public enum Action 
  {
    Append,  /* 空レコードの追加。 */
    Update,  /* レコードの更新。 */
    Delete,  /* レコードの削除。 */
  }

  /**
   * デフォルト・コンストラクタ。
   */
  public Trigger()
  {}

  /**
   * レコードの追加の直前に呼び出されるメソッド。
   * <br>
   * 変更対象のレコード・オブジェクトの内容は空である。
   * <br>
   * <br>
   * このクラスでは、このメソッドは何もしない。
   *
   * @param  table テーブル・オブジェクト。
   * @param  record 追加されるレコード・オブジェクト。
   */
  protected void preAppend(Table<C,V> table, Map<C,V> record)
  {}

  /**
   * レコードの追加の直後に呼び出されるメソッド。
   * <br>
   * <br>
   * このクラスでは、このメソッドは何もしない。
   *
   * @param  table テーブル・オブジェクト。
   * @param  record 追加されたレコード・オブジェクト。
   */
  protected void postAppend(Table<C,V> table, Map<C,V> record)
  {}

  /**
   * レコードの更新の直前に呼び出されるメソッド。
   * <br>
   * 変更対象のレコード・オブジェクトは、変更前の状態で渡される。
   * <br>
   * <br>
   * このクラスでは、このメソッドは何もしない。
   *
   * @param  table テーブル・オブジェクト。
   * @param  record 変更対象のレコード・オブジェクト。
   * @param  destination 更新するカラム・キーとその値を格納したマップ。
   */
  protected void preUpdate(
    Table<C,V> table, Map<C,V> record, Map<C,V> destination)
  {}

  /**
   * レコードの更新の直後に呼び出されるメソッド。
   * <br>
   * 変更対象のレコード・オブジェクトは、変更後の状態で渡される。
   * <br>
   * <br>
   * このクラスでは、このメソッドは何もしない。
   *
   * @param  table テーブル・オブジェクト。
   * @param  record 変更対象のレコード・オブジェクト。
   * @param  destination 更新するカラム・キーとその値を格納したマップ。
   */
  protected void postUpdate(
    Table<C,V> table, Map<C,V> record, Map<C,V> destination)
  {}

  /**
   * レコードの削除の直前に呼び出されるメソッド。
   * <br>
   * <br>
   * このクラスでは、このメソッドは何もしない。
   *
   * @param  table テーブル・オブジェクト。
   * @param  record 変更対象のレコード・オブジェクト。
   */
  protected void preDelete(Table<C,V> table, Map<C,V> record)
  {}

  /**
   * レコードの削除の直後に呼び出されるメソッド。
   * <br>
   * <br>
   * このクラスでは、このメソッドは何もしない。
   *
   * @param  table テーブル・オブジェクト。
   * @param  record 変更対象のレコード・オブジェクト。
   */
  protected void postDelete(Table<C,V> table, Map<C,V> record)
  {}

  /**
   * 全てのレコードを削除する直前に呼び出されるメソッド。
   * <br>
   * 引数のレコード・コレクションからレコードを順に取り出して、{@link
   * #preDelete(ts.util.table.Table,java.util.Map)}メソッドを実行している。
   *
   * @param  table テーブル・オブジェクト。
   * @param  coll 削除対象のレコードを格納したコレクション。
   * @throws AssertionError 引数がヌルの場合（デバッグ・モードのみ）。
   */
  protected void preDeleteAll(Table<C,V> table, Collection<Map<C,V>> coll)
  {
    assert (table != null) : "@param:table is null.";
    assert (coll != null) : "@param:coll is null.";
    
    for (Map<C,V> rec : coll) {
      preDelete(table, rec);
    }
  }

  /**
   * 全てのレコードを削除した直後に呼び出されるメソッド。
   * <br>
   * 引数のレコード・コレクションからレコードを順に取り出して、
   * {@link #postDelete(ts.util.table.Table,java.util.Map)}メソッドを実行して
   * いる。
   *
   * @param  table テーブル・オブジェクト。
   * @param  coll 削除対象のレコードを格納したコレクション。
   * @throws AssertionError 引数がヌルの場合（デバッグ・モードのみ）。
   */
  protected void postDeleteAll(Table<C,V> table, Collection<Map<C,V>> coll)
  {
    assert (table != null) : "@param:table is null.";
    assert (coll != null) : "@param:coll is null.";

    for (Map<C,V> rec : coll) {
      postDelete(table, rec);
    }
  }

  /**
   * このオブジェクトのクローン・オブジェクトを作成する。
   *
   * @return このオブジェクトのクローン・オブジェクト。
   */
  @SuppressWarnings("unchecked")
  protected Trigger<C,V> createClone()
  {
    try {
      return (Trigger<C,V>) clone();
    }
    catch (CloneNotSupportedException e) {
      throw new InternalError();
    }
  }
}
