/*
 * SyetemUtil.java
 * 
 * Author: http://www.hrtdotnet.jp/
 * 
 */
package jp.hrtdotnet.java.util;

/**
 * 時間を計測します。
 * 開始から終了までの時間を取得・計測し、指定した時間の範囲内で処理されるか
 * どうか判定することができます。
 * またこのクラスを拡張することで判定した結果によって特定の処理をさせることができます。
 * 
 * @version 2.0
 * @author hrtdotnet.jp
 * <br>http://www.hrtdotnet.jp/
 * @since 2.0
 */
public class TimeUtil {
    
    private long start;
    private long stop;
    private long diff;
    private long maxMilliSecond;
    private long minMilliSecond;

    /**
     * コンストラクタ。
     * このコンストラクタで作成されたオブジェクトは時間チェックを行いません。
     * 
     * @since 2.0
     */
    public TimeUtil() {        
        this(-1L, -1L);
    }
    
    /**
     * コンストラクタ。
     * このコンストラクタで作成されたオブジェクトは時間チェックを行います。
     * <br><br>
     * 開始時間と終了時間の差を実行時間とし、
     * コンストラクタ作成の際に実行時間の上限値と下限値を指定します。
     * 時間計測を終了したときやチェックメソッドを呼び出したときに
     * 指定した限界値を元にチェックを行います。
     * <br>
     * なお上限値・下限値に 0L 未満を指定するとチェックは行われません。
     * また上限に1ミリ秒より少ない値を指定したい場合は0Lを指定します。
     * 
     * @param maxMilliSecond 上限（ミリ秒）
     * @param minMilliSecond 下限（ミリ秒）
     * @since 2.0
     */
    public TimeUtil(long maxMilliSecond, long minMilliSecond) {        
        if (maxMilliSecond >= 0L && minMilliSecond >= 0L && maxMilliSecond < minMilliSecond) {
            throw new IllegalArgumentException();
        }
        this.maxMilliSecond = maxMilliSecond;
        this.minMilliSecond = minMilliSecond;
        this.clear();
    }

    /**
     * 開始時間を記録します。
     * 開始時間を記録中にこのメソッドを呼び出してしまうと過去の開始時間はリセットされ、
     * 呼び出した時点を基点として新しく記録します。
     * <br>
     * また開始時間記録中であるなしに関わらず過去の終了時間や実行時間はクリアされ0Lとなります。
     * 
     * @since 2.0
     */
    public synchronized void start() {
        this.clear();
        start = System.currentTimeMillis();
    }
    
    /**
     * 終了時間を記録し、実行時間が範囲内であるかどうかのチェックをします。
     * 実行時間はgetDiff()メソッドで取得することができます。
     * 
     * @return 範囲内であればtrue、そうでなければfalse
     * @since 2.0
     */
    public synchronized boolean stop() {
        stop = System.currentTimeMillis();
        diff = stop - start;
        return check();
    }
    
    /**
     * 実行時間が指定した時間の範囲内であるかどうかのチェックをします。
     * 指定した時間の範囲内であればcheckTrue()を実行し、
     * そうでなければcheckFalse()を実行します。
     * 
     * @return  範囲内であればtrue、そうでなければfalse
     * @since 2.0
     */
    public synchronized boolean check() {
        
        boolean b = true;

        try {
            if (maxMilliSecond >= 0L) {
                if (diff > maxMilliSecond) {
                    b = false;
                    return false;
                }
            }

            if (minMilliSecond >= 0L) {
                if (diff < minMilliSecond) {
                    b = false;
                    return false;
                }
            }            
            return true;
        } finally {
            if (b) {
                checkTrue();
            } else {
                checkFalse();
            }
        }
    }
    
    /**
     * 実行時間（終了時間と開始時間の差）を取得します。
     * 
     * @return 実行時間
     * @since 2.0
     */
    public synchronized long getDiff() {
        return diff;
    }
    
    /**
     * 時間チェックに利用した内部データをクリアします。
     * <br><br>
     * クリアされるのは以下の項目です。
     * <ul>
     * <li>開始時間</li>
     * <li>終了時間</li>
     * <li>終了時間と開始時間の差（実行時間）</li>
     * </ul>
     * 
     * @since 2.0
     */
    public synchronized void clear() {
        start = 0L;
        stop = 0L;
        diff = 0L;
    }


    /**
     * 実行時間のチェック時({@link #check() check()})に実行時間が指定した
     * 時間の範囲内であったときにこのメソッドが実行されます。
     * デフォルトでは何も行われません。
     * <br>
     * 特定の処理をさせる場合はメソッドをオーバーライドさせる必要があります。
     * 
     * @since 2.0
     */
    protected void checkTrue() {
    }

    /**
     * 実行時間のチェック時({@link #check() check()})に実行時間が指定した
     * 時間の範囲外であったときにこのメソッドが実行されます。
     * デフォルトでは何も行われません。
     * <br>
     * 特定の処理をさせる場合はメソッドをオーバーライドさせる必要があります。
     * 
     * @since 2.0
     */
    protected void checkFalse() {
    }
}
