package com.android_mvc.framework.controller;
import android.app.Activity;
import com.android_mvc.framework.activities.IBaseActivity;
import com.android_mvc.framework.common.FWUtil;
import com.android_mvc.framework.controller.action.ActionResult;
import com.android_mvc.framework.controller.action.BLExecutor;
import com.android_mvc.framework.controller.routing.Router;
import com.android_mvc.framework.controller.routing.RoutingTable;
import com.android_mvc.framework.controller.validation.ValidationResult;
import com.android_mvc.framework.controller.validation.ValidationExecutor;
import com.android_mvc.framework.task.AsyncTasksRunner;
import com.android_mvc.framework.task.RunnerFollower;
import com.android_mvc.framework.task.SequentialAsyncTask;
/**
* 一つのコントロールフローの詳細記述
* @author id:language_and_engineering
*/
public class ControlFlowDetail<T_ActivityClass>
{
// NOTE: T_ActivityClass -> Activityへのキャストを許可する。
protected T_ActivityClass from_activity;
private ValidationExecutor validation_executor;
private BLExecutor bl_executor;
private RoutingTable routingTable;
protected ActionResult action_result;
private String dialogText = "処理中です・・・";
/**
* 初期化
*/
public ControlFlowDetail(T_ActivityClass fromActivity)
{
this.from_activity = fromActivity;
}
/**
* バリデーション処理の詳細をセット
*/
public ControlFlowDetail<T_ActivityClass> setValidation(
ValidationExecutor validationExecutor
)
{
this.validation_executor = validationExecutor;
return this;
}
/**
* BL実行の詳細をセット
*/
public ControlFlowDetail<T_ActivityClass> setBL(
BLExecutor blExecutor
)
{
this.bl_executor = blExecutor;
return this;
}
/**
* BL実行完了時のルーティングテーブルをセット。
* 引数によっては,画面遷移を抑止することも可能。
*/
public ControlFlowDetail<T_ActivityClass> onBLExecuted( RoutingTable routingTable )
{
this.routingTable = routingTable;
return this;
}
/**
* 処理中のダイアログの文言をセット。
* 呼び出さない場合は,デフォルトの文言が使用される。
*/
public ControlFlowDetail<T_ActivityClass> setDialogText(String s)
{
this.dialogText = s;
return this;
}
/**
* 制御フローを実行。
* このクラスの要であり,コントローラ層の要であり,このフレームワークの要でもある重要な部分。
*/
public void startControl()
{
// ActionResult格納用に
final ControlFlowDetail<T_ActivityClass> parentFlow = this;
// 一連の制御フローを開始
new AsyncTasksRunner( new SequentialAsyncTask[]{
// バリデーションを行なう非同期タスク。
new SequentialAsyncTask(){
public boolean main(){
ValidationResult vres;
// バリデータがセットされていれば
if( validation_executor != null )
{
// Activityのparamsをバリデート
validation_executor.execAndStoreValidationResult();
vres = validation_executor.validation_result;
}
else
{
// バリデを実行しないので成功とみなす
vres = new ValidationResult().setSuccess();
}
storeData( "validation_result", vres );
// バリデの成否に応じて動作を切り替え
if( vres.isSuccess() )
{
FWUtil.d("バリデーションが成功しました。BL実行フェーズに進みます。");
// BL実行フェーズに進む
return CONTINUE_TASKS;
}
else
{
FWUtil.d("バリデーションが失敗しました。BLの実行はキャンセルされます。");
// バリデ失敗時の処理を実行
validation_executor.from_activity = (Activity)from_activity;
validation_executor.onValidationFailed();
// 次以降のタスクはキャンセル
return BREAK_TASKS;
}
}
}
,
// もし可能ならBLを行なう非同期タスク。
// DB操作やNW通信などを想定。
new SequentialAsyncTask(){
public boolean main(){
// 前のバリデーション処理の結果を取りだす
ValidationResult vres = (ValidationResult)getDataFromRunner("validation_result");
// もしバリデ結果からしてBLを実行してよいのであれば
if( vres.permitsExecitionOfBL() )
{
FWUtil.d("BLの実行を開始します。");
// BLを実行
bl_executor.execAndStoreActionResult();
// BLの結果を格納
storeData( "action_result", bl_executor.action_result );
parentFlow.action_result = bl_executor.action_result;
FWUtil.d("ActionResultの格納が完了しました。");
}
// BLの実行結果の是非に関らずルーティングはするので必ずtrue
return CONTINUE_TASKS;
}
}
,
// ルーティングを行なう非同期タスク
new SequentialAsyncTask(){
public boolean main(){
// ルーティングが渡されているか
if( routingTable != null )
{
// BLが実行された場合
ActionResult ares = (ActionResult)getDataFromRunner("action_result");
// BL実行結果に応じて遷移先を分岐
Router.switchByActionResult( (Activity)from_activity, ares, routingTable );
}
else
{
// ルーティングテーブルを渡さなければ,画面遷移しない。
}
return CONTINUE_TASKS;
}
}
})
.withSimpleDialog(dialogText, (Activity)from_activity) // 全非同期タスクが終了するまでダイアログを出す
.whenAllTasksCompleted(new RunnerFollower(){
@Override
protected void exec() {
ActionResult ares = parentFlow.action_result;
// BLが実行された場合
if( ares != null )
{
// BLを非同期で実行完了後に,UIスレッド上で動く処理を実行
((IBaseActivity)from_activity).afterBLExecuted(ares);
// NOTE: Intentで画面遷移する場合は,Intent内にActionResultが自動的に格納されるので,
// 遷移先の画面でUI操作処理を記述すればよい。
// しかし,BL実行完了に画面遷移が伴わない場合は,同一アクティビティ内でBL実行完了後に
// UIスレッド上でUI操作する処理を記述できる場所が必要。それがこれ。
}
}
})
.begin(); // これら全ての処理を開始
}
}