package com.tryandroid.media;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

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

import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PictureCallback;
import android.os.Environment;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class CameraViewHelper implements SurfaceHolder.Callback,
		PictureCallback, View.OnTouchListener {

	private SimpleDateFormat timestampFormat = new SimpleDateFormat(
			"yyyyMMdd-HHmmss");
	private Camera camera;
	private Context context;
	private String workName;
	private TextView indexTextView;
	private SurfaceView cameraView;
	private int index;
	private TextView workTextView;

	public CameraViewHelper(Context context, SurfaceView cameraView,
			TextView workTextView, TextView indexTextView) {
		this.context = context;
		this.cameraView = cameraView;
		this.workTextView = workTextView;
		this.indexTextView = indexTextView;

		// カメラのプレビュー設定
		SurfaceHolder surfaceHolder = cameraView.getHolder();
		surfaceHolder.addCallback(this);
		// カメラ映像をGPUに直接送り込むための設定
		surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

		cameraView.setOnTouchListener(this);
	}

	@Override
	public void surfaceCreated(SurfaceHolder surfaceHolder) {
		LogUtil.called();

		try {
			// 存在すればカメラオブジェクト開放
			releaseCamera();

			// カメラの準備
			camera = Camera.open();
			camera.setPreviewDisplay(surfaceHolder);

		} catch (Exception e) {
			String msg = "カメラの準備に失敗しました。";
			LogUtil.e(msg, e);
			Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
			releaseCamera();
		}
	}

	@Override
	public void surfaceChanged(SurfaceHolder surfaceHolder, int format,
			int width, int height) {
		LogUtil.called();

		if (camera == null) {
			return;
		}

		try {
			// プレビュー画像サイズ設定
			Parameters params = camera.getParameters();
			params.setPreviewSize(width, height);
			camera.setParameters(params);

			// プレビュー開始
			camera.startPreview();

		} catch (Exception e) {
			String msg = "プレビュー開始に失敗しました。";
			LogUtil.e(msg, e);
			Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
			releaseCamera();
		}
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
		LogUtil.called();

		if (camera == null) {
			return;
		}

		try {
			// プレビュー終了
			camera.stopPreview();
		} finally {
			releaseCamera();
		}
	}

	/**
	 * Viewをタッチされた時のイベント<br>
	 * 撮影を行う。
	 */
	@Override
	public boolean onTouch(View view, MotionEvent motionEvent) {
		LogUtil.called();

		if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
			try {
				// 撮影要求
				camera.takePicture(null, null, this);
				// プレビュー再開
				camera.startPreview();
			} catch (Exception e) {
				String msg = "カメラ撮影に失敗しました。";
				LogUtil.e(msg, e);
				Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
				releaseCamera();
			}
			return false;
		}

		return true;
	}

	/**
	 * カメラオブジェクトからの撮影結果を受け取るイベント<br>
	 * ファイルへ保存する。
	 */
	@Override
	public void onPictureTaken(byte[] data, Camera camera) {
		LogUtil.called();

		String path = null;

		try {
			// ファイル名取得
			path = KomadoriUtil.getJpgFilePath(context, workName, index);

			// ディレクトリ作成
			File dir = KomadoriUtil.getBaseDir(context, workName);
			if (!dir.exists()) {
				dir.mkdirs();
			}

			// ファイル保存
			save(path, data);

			// 結果をトースト表示
			Toast.makeText(context, "ファイルを保存しました。\n" + path, Toast.LENGTH_LONG)
					.show();

			// インデックスをカウントアップ
			index++;
			indexTextView.setText(String.valueOf(index));

		} catch (Exception e) {
			String msg = "ファイル保存に失敗しました。";
			LogUtil.e(msg, e);
			Toast.makeText(context, msg + "\n" + path, Toast.LENGTH_LONG)
					.show();
			releaseCamera();
		}
	}

	public void setWorkName(String workName) {
		this.workName = workName;
		index = 1;
		workTextView.setText(workName);
		indexTextView.setText(String.valueOf(index));
	}

	private void releaseCamera() {
		// カメラの開放
		if (camera != null) {
			camera.release();
			camera = null;
		}
	}

	private void save(String path, byte[] data) throws IOException {
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(path);
			fos.write(data);
		} finally {
			if (fos != null) {
				fos.close();
			}
		}
	}

}
