package com.kurukurupapa.tryandroiddb.performance;

import com.kurukurupapa.tryandroid.fw.util.LogUtil;

import android.app.ProgressDialog;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import android.widget.TextView;

/**
 * DBパフォーマンス測定タスク
 */
public class PerformanceTask extends AsyncTask<Void, Integer, Void> {
	private Context context;
	private TextView textView;
	private ProgressDialog progressDialog;
	private DbHelper dbHelper;

	private int numLoop = 10;
	private int numSql = 10;
	private long insertOnlyMsec = 0;
	private long insertAndConnectionMsec = 0;
	private long queryOnlyMsec = 0;
	private long queryAndConnectionMsec = 0;

	public PerformanceTask(Context context, TextView textView) {
		this.context = context;
		this.textView = textView;
		this.dbHelper = new DbHelper(context);
	}

	/**
	 * スレッド開始前処理<br>
	 * UIスレッドでダイアログを表示する
	 */
	@Override
	protected void onPreExecute() {
		super.onPreExecute();
		LogUtil.called();

		// ProgressDialog作成
		progressDialog = new ProgressDialog(context);
		progressDialog.setMessage("測定中");
		progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
		progressDialog.setMax(numLoop);
		progressDialog.setProgress(0);

		// ProgressDialog表示
		progressDialog.show();
	}

	/**
	 * 別スレッドで処理する。
	 */
	@Override
	protected Void doInBackground(Void... arg0) {
		LogUtil.called();

		insertOnlyMsec = 0;
		insertAndConnectionMsec = 0;
		queryOnlyMsec = 0;
		queryAndConnectionMsec = 0;

		dbHelper.clear();

		for (int i = 0; i < numLoop; i++) {
			insertOnlyLoop();
			insertAndConnectionLoop();
			queryOnlyLoop();
			queryAndConnectionLoop();
			publishProgress(i);
		}

		dbHelper.clear();

		return null;
	}

	private void insertOnlyLoop() {
		long startTimestamp = System.currentTimeMillis();

		SQLiteDatabase db = dbHelper.getWritableDatabase();
		try {
			db.beginTransaction();
			for (int i = 0; i < numSql; i++) {
				insert(db, i);
			}
			db.setTransactionSuccessful();
		} finally {
			db.endTransaction();
			db.close();
		}

		long endTimestamp = System.currentTimeMillis();
		insertOnlyMsec += endTimestamp - startTimestamp;
	}

	private void insertAndConnectionLoop() {
		long startTimestamp = System.currentTimeMillis();

		for (int i = 0; i < numSql; i++) {
			SQLiteDatabase db = dbHelper.getWritableDatabase();
			try {
				insert(db, i);
			} finally {
				db.close();
			}
		}

		long endTimestamp = System.currentTimeMillis();
		insertAndConnectionMsec += endTimestamp - startTimestamp;
	}

	private void insert(SQLiteDatabase db, int i) {
		ContentValues values = new ContentValues();
		values.put("text", "text" + i);
		values.put("timestamp", System.currentTimeMillis());
		db.insertOrThrow("performance_entity", null, values);
	}

	private void queryOnlyLoop() {
		long startTimestamp = System.currentTimeMillis();

		SQLiteDatabase db = dbHelper.getReadableDatabase();
		try {
			db.beginTransaction();
			for (int i = 0; i < numSql; i++) {
				query(db, i);
			}
			db.setTransactionSuccessful();
		} finally {
			db.endTransaction();
			db.close();
		}

		long endTimestamp = System.currentTimeMillis();
		queryOnlyMsec += endTimestamp - startTimestamp;
	}

	private void queryAndConnectionLoop() {
		long startTimestamp = System.currentTimeMillis();

		for (int i = 0; i < numSql; i++) {
			SQLiteDatabase db = dbHelper.getReadableDatabase();
			try {
				query(db, i);
			} finally {
				db.close();
			}
		}

		long endTimestamp = System.currentTimeMillis();
		queryAndConnectionMsec += endTimestamp - startTimestamp;
	}

	private PerformanceEntity query(SQLiteDatabase db, int i) {
		PerformanceEntity entity = null;
		Cursor cursor = null;
		try {
			cursor = db.query("performance_entity", new String[] { "id",
					"text", "timestamp" }, "text=?",
					new String[] { "text" + i }, null, null, "id",
					String.valueOf(numSql));
			cursor.moveToNext();
			entity = new PerformanceEntity();
			entity.id = cursor.getInt(0);
			entity.text = cursor.getString(1);
			entity.timestamp = cursor.getLong(2);
		} finally {
			if (cursor != null) {
				cursor.close();
			}
		}

		return entity;
	}

	/**
	 * 状況表示処理<br>
	 * UIスレッドで処理する。
	 */
	@Override
	protected void onProgressUpdate(Integer... values) {
		super.onProgressUpdate(values);

		progressDialog.setProgress(values[0].intValue());
	}

	/**
	 * スレッド完了後処理<br>
	 * UIスレッドで処理する。
	 *
	 * @param result
	 */
	@Override
	protected void onPostExecute(Void result) {
		LogUtil.called();

		// 処理中ダイアログをクローズ
		progressDialog.dismiss();

		// 処理結果を表示する
		StringBuilder sb = new StringBuilder();
		sb.append("DB接続" + 1 + "回＆Insert " + numSql + "回\n");
		sb.append(insertOnlyMsec / numLoop + "ミリ秒\n");
		sb.append("DB接続" + numSql + "回＆Insert " + numSql + "回\n");
		sb.append(insertAndConnectionMsec / numLoop + "ミリ秒\n");
		sb.append("DB接続" + 1 + "回＆Query " + numSql + "回\n");
		sb.append(queryOnlyMsec / numLoop + "ミリ秒\n");
		sb.append("DB接続" + numSql + "回＆Query " + numSql + "回\n");
		sb.append(queryAndConnectionMsec / numLoop + "ミリ秒\n");
		textView.setText(textView.getText() + "\n" + sb.toString());
	}

}
