package com.yixia.camera.demo.ui.record;

import java.io.File;
import java.util.ArrayList;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Rect;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.CheckBox;
import android.widget.CheckedTextView;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;

import com.example.wechat01.R;
import com.yixia.camera.MediaRecorderBase;
import com.yixia.camera.MediaRecorderBase.OnErrorListener;
import com.yixia.camera.MediaRecorderBase.OnPreparedListener;
import com.yixia.camera.MediaRecorderNative;
import com.yixia.camera.MediaRecorderSystem;
import com.yixia.camera.VCamera;
import com.yixia.camera.demo.VCameraDemoApplication;
import com.yixia.camera.demo.common.CommonIntentExtra;
import com.yixia.camera.demo.log.Logger;
import com.yixia.camera.demo.ui.BaseActivity;
import com.yixia.camera.demo.ui.record.views.ProgressView;
import com.yixia.camera.demo.utils.ConvertToUtils;
import com.yixia.camera.model.MediaObject;
import com.yixia.camera.util.DeviceUtils;
import com.yixia.camera.util.FileUtils;
import com.yixia.videoeditor.adapter.UtilityAdapter;

/**
 * 瑙嗛褰曞埗
 * 
 * @author tangjun@yixia.com
 *
 */
public class MediaRecorderActivity extends BaseActivity implements
		OnErrorListener, OnClickListener, OnPreparedListener,
		MediaRecorderBase.OnEncodeListener {

	/** 褰曞埗鏈€闀挎椂闂?*/
	public final static int RECORD_TIME_MAX = 10 * 1000;
	/** 褰曞埗鏈€灏忔椂闂?*/
	public final static int RECORD_TIME_MIN = 3 * 1000;
	/** 鍒锋柊杩涘害鏉?*/
	private static final int HANDLE_INVALIDATE_PROGRESS = 0;
	/** 寤惰繜鎷嶆憚鍋滄 */
	private static final int HANDLE_STOP_RECORD = 1;
	/** 瀵圭劍 */
	private static final int HANDLE_HIDE_RECORD_FOCUS = 2;

	/** 涓嬩竴姝?*/
	private ImageView mTitleNext;
	/** 瀵圭劍鍥炬爣-甯﹀姩鐢绘晥鏋?*/
	private ImageView mFocusImage;
	/** 鍓嶅悗鎽勫儚澶村垏鎹?*/
	private CheckBox mCameraSwitch;
	/** 鍥炲垹鎸夐挳銆佸欢鏃舵寜閽€佹护闀滄寜閽?*/
	private CheckedTextView mRecordDelete;
	/** 闂厜鐏?*/
	private CheckBox mRecordLed;
	/** 鎷嶆憚鎸夐挳 */
	private ImageView mRecordController;

	/** 搴曢儴鏉?*/
	private RelativeLayout mBottomLayout;
	/** 鎽勫儚澶存暟鎹樉绀虹敾甯?*/
	private SurfaceView mSurfaceView;
	/** 褰曞埗杩涘害 */
	private ProgressView mProgressView;
	/** 瀵圭劍鍔ㄧ敾 */
	private Animation mFocusAnimation;

	/** SDK瑙嗛褰曞埗瀵硅薄 */
	private MediaRecorderBase mMediaRecorder;
	/** 瑙嗛淇℃伅 */
	private MediaObject mMediaObject;

	/** 闇€瑕侀噸鏂扮紪璇戯紙鎷嶆憚鏂扮殑鎴栬€呭洖鍒狅級 */
	private boolean mRebuild;
	/** on */
	private boolean mCreated;
	/** 鏄惁鏄偣鍑荤姸鎬?*/
	private volatile boolean mPressedStatus;
	/** 鏄惁宸茬粡閲婃斁 */
	private volatile boolean mReleased;
	/** 瀵圭劍鍥剧墖瀹藉害 */
	private int mFocusWidth;
	/** 搴曢儴鑳屾櫙鑹?*/
	private int mBackgroundColorNormal, mBackgroundColorPress;
	/** 灞忓箷瀹藉害 */
	private int mWindowWidth;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		mCreated = false;
		super.onCreate(savedInstanceState);
		VCameraDemoApplication.getInstance().addActivity(this);
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // 闃叉閿佸睆
		loadIntent();
		loadViews();
		mCreated = true;
	}

	/** 鍔犺浇浼犲叆鐨勫弬鏁?*/
	private void loadIntent() {
		mWindowWidth = DeviceUtils.getScreenWidth(this);

		mFocusWidth = ConvertToUtils.dipToPX(this, 64);
		mBackgroundColorNormal = getResources().getColor(R.color.black);// camera_bottom_bg
		mBackgroundColorPress = getResources().getColor(
				R.color.camera_bottom_press_bg);
	}

	/** 鍔犺浇瑙嗗浘 */
	private void loadViews() {
		setContentView(R.layout.activity_media_recorder);
		// ~~~ 缁戝畾鎺т欢
		mSurfaceView = (SurfaceView) findViewById(R.id.record_preview);
		mCameraSwitch = (CheckBox) findViewById(R.id.record_camera_switcher);
		mTitleNext = (ImageView) findViewById(R.id.title_next);
		mFocusImage = (ImageView) findViewById(R.id.record_focusing);
		mProgressView = (ProgressView) findViewById(R.id.record_progress);
		mRecordDelete = (CheckedTextView) findViewById(R.id.record_delete);
		mRecordController = (ImageView) findViewById(R.id.record_controller);
		mBottomLayout = (RelativeLayout) findViewById(R.id.bottom_layout);
		mRecordLed = (CheckBox) findViewById(R.id.record_camera_led);

		// ~~~ 缁戝畾浜嬩欢
		if (DeviceUtils.hasICS())
			mSurfaceView.setOnTouchListener(mOnSurfaveViewTouchListener);

		mTitleNext.setOnClickListener(this);
		findViewById(R.id.title_back).setOnClickListener(this);
		mRecordDelete.setOnClickListener(this);
		mBottomLayout.setOnTouchListener(mOnVideoControllerTouchListener);

		// ~~~ 璁剧疆鏁版嵁

		// 鏄惁鏀寔鍓嶇疆鎽勫儚澶?		if (MediaRecorderBase.isSupportFrontCamera()) {
			mCameraSwitch.setOnClickListener(this);
		} else {
			mCameraSwitch.setVisibility(View.GONE);
		}
		// 鏄惁鏀寔闂厜鐏?		if (DeviceUtils.isSupportCameraLedFlash(getPackageManager())) {
			mRecordLed.setOnClickListener(this);
		} else {
			mRecordLed.setVisibility(View.GONE);
		}

		try {
			mFocusImage.setImageResource(R.drawable.video_focus);
		} catch (OutOfMemoryError e) {
			Logger.e(e);
		}

		mProgressView.setMaxDuration(RECORD_TIME_MAX);
		initSurfaceView();
	}

	/** 鍒濆鍖栫敾甯?*/
	private void initSurfaceView() {
		final int w = DeviceUtils.getScreenWidth(this);
		((RelativeLayout.LayoutParams) mBottomLayout.getLayoutParams()).topMargin = w;
		int width = w;
		int height = w * 4 / 3;
		//
		RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) mSurfaceView
				.getLayoutParams();
		lp.width = width;
		lp.height = height;
		mSurfaceView.setLayoutParams(lp);
	}

	/** 鍒濆鍖栨媿鎽凷DK */
	private void initMediaRecorder() {
		mMediaRecorder = new MediaRecorderNative();
		mRebuild = true;

		mMediaRecorder.setOnErrorListener(this);
		mMediaRecorder.setOnEncodeListener(this);
		File f = new File(VCamera.getVideoCachePath());
		if (!FileUtils.checkFile(f)) {
			f.mkdirs();
		}
		String key = String.valueOf(System.currentTimeMillis());
		mMediaObject = mMediaRecorder.setOutputDirectory(key,
				VCamera.getVideoCachePath() + key);
		mMediaRecorder.setSurfaceHolder(mSurfaceView.getHolder());
		mMediaRecorder.prepare();
	}

	/** 鐐瑰嚮灞忓箷褰曞埗 */
	private View.OnTouchListener mOnSurfaveViewTouchListener = new View.OnTouchListener() {

		@Override
		public boolean onTouch(View v, MotionEvent event) {
			if (mMediaRecorder == null || !mCreated) {
				return false;
			}

			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				// 妫€娴嬫槸鍚︽墜鍔ㄥ鐒?				if (checkCameraFocus(event))
					return true;
				break;
			}
			return true;
		}

	};

	/** 鐐瑰嚮灞忓箷褰曞埗 */
	private View.OnTouchListener mOnVideoControllerTouchListener = new View.OnTouchListener() {

		@Override
		public boolean onTouch(View v, MotionEvent event) {
			if (mMediaRecorder == null) {
				return false;
			}

			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				// 妫€娴嬫槸鍚︽墜鍔ㄥ鐒?				// 鍒ゆ柇鏄惁宸茬粡瓒呮椂
				if (mMediaObject.getDuration() >= RECORD_TIME_MAX) {
					return true;
				}

				// 鍙栨秷鍥炲垹
				if (cancelDelete())
					return true;

				startRecord();

				break;

			case MotionEvent.ACTION_UP:
				// 鏆傚仠
				if (mPressedStatus) {
					stopRecord();

					// 妫€娴嬫槸鍚﹀凡缁忓畬鎴?					if (mMediaObject.getDuration() >= RECORD_TIME_MAX) {
						mTitleNext.performClick();
					}
				}
				break;
			}
			return true;
		}

	};

	@Override
	public void onResume() {
		super.onResume();
		UtilityAdapter.freeFilterParser();
		UtilityAdapter.initFilterParser();

		if (mMediaRecorder == null) {
			initMediaRecorder();
		} else {
			mRecordLed.setChecked(false);
			mMediaRecorder.prepare();
			mProgressView.setData(mMediaObject);
		}
	}

	@Override
	public void onPause() {
		super.onPause();
		stopRecord();
		UtilityAdapter.freeFilterParser();
		if (!mReleased) {
			if (mMediaRecorder != null)
				mMediaRecorder.release();
		}
		mReleased = false;
	}

	/** 鎵嬪姩瀵圭劍 */
	@SuppressLint("NewApi")
	@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
	private boolean checkCameraFocus(MotionEvent event) {
		mFocusImage.setVisibility(View.GONE);
		float x = event.getX();
		float y = event.getY();
		float touchMajor = event.getTouchMajor();
		float touchMinor = event.getTouchMinor();

		Rect touchRect = new Rect((int) (x - touchMajor / 2),
				(int) (y - touchMinor / 2), (int) (x + touchMajor / 2),
				(int) (y + touchMinor / 2));
		// The direction is relative to the sensor orientation, that is, what
		// the sensor sees. The direction is not affected by the rotation or
		// mirroring of setDisplayOrientation(int). Coordinates of the rectangle
		// range from -1000 to 1000. (-1000, -1000) is the upper left point.
		// (1000, 1000) is the lower right point. The width and height of focus
		// areas cannot be 0 or negative.
		// No matter what the zoom level is, (-1000,-1000) represents the top of
		// the currently visible camera frame
		if (touchRect.right > 1000)
			touchRect.right = 1000;
		if (touchRect.bottom > 1000)
			touchRect.bottom = 1000;
		if (touchRect.left < 0)
			touchRect.left = 0;
		if (touchRect.right < 0)
			touchRect.right = 0;

		if (touchRect.left >= touchRect.right
				|| touchRect.top >= touchRect.bottom)
			return false;

		ArrayList<Camera.Area> focusAreas = new ArrayList<Camera.Area>();
		focusAreas.add(new Camera.Area(touchRect, 1000));
		if (!mMediaRecorder.manualFocus(new Camera.AutoFocusCallback() {

			@Override
			public void onAutoFocus(boolean success, Camera camera) {
				// if (success) {
				mFocusImage.setVisibility(View.GONE);
				// }
			}
		}, focusAreas)) {
			mFocusImage.setVisibility(View.GONE);
		}

		RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) mFocusImage
				.getLayoutParams();
		int left = touchRect.left - (mFocusWidth / 2);// (int) x -
														// (focusingImage.getWidth()
														// / 2);
		int top = touchRect.top - (mFocusWidth / 2);// (int) y -
													// (focusingImage.getHeight()
													// / 2);
		if (left < 0)
			left = 0;
		else if (left + mFocusWidth > mWindowWidth)
			left = mWindowWidth - mFocusWidth;
		if (top + mFocusWidth > mWindowWidth)
			top = mWindowWidth - mFocusWidth;

		lp.leftMargin = left;
		lp.topMargin = top;
		mFocusImage.setLayoutParams(lp);
		mFocusImage.setVisibility(View.VISIBLE);

		if (mFocusAnimation == null)
			mFocusAnimation = AnimationUtils.loadAnimation(this,
					R.anim.record_focus);

		mFocusImage.startAnimation(mFocusAnimation);

		mHandler.sendEmptyMessageDelayed(HANDLE_HIDE_RECORD_FOCUS, 3500);// 鏈€澶?.5绉掍篃瑕佹秷澶?		return true;
	}

	/** 寮€濮嬪綍鍒?*/
	private void startRecord() {
		if (mMediaRecorder != null) {
			MediaObject.MediaPart part = mMediaRecorder.startRecord();
			if (part == null) {
				return;
			}

			// 濡傛灉浣跨敤MediaRecorderSystem锛屼笉鑳藉湪涓€斿垏鎹㈠墠鍚庢憚鍍忓ご锛屽惁鍒欐湁闂
			if (mMediaRecorder instanceof MediaRecorderSystem) {
				mCameraSwitch.setVisibility(View.GONE);
			}
			mProgressView.setData(mMediaObject);
		}

		mRebuild = true;
		mPressedStatus = true;
		mRecordController.setImageResource(R.drawable.record_controller_press);
		mBottomLayout.setBackgroundColor(mBackgroundColorPress);

		if (mHandler != null) {
			mHandler.removeMessages(HANDLE_INVALIDATE_PROGRESS);
			mHandler.sendEmptyMessage(HANDLE_INVALIDATE_PROGRESS);

			mHandler.removeMessages(HANDLE_STOP_RECORD);
			mHandler.sendEmptyMessageDelayed(HANDLE_STOP_RECORD,
					RECORD_TIME_MAX - mMediaObject.getDuration());
		}
		mRecordDelete.setVisibility(View.GONE);
		mCameraSwitch.setEnabled(false);
		mRecordLed.setEnabled(false);
	}

	@Override
	public void onBackPressed() {
		if (mRecordDelete != null && mRecordDelete.isChecked()) {
			cancelDelete();
			return;
		}

		if (mMediaObject != null && mMediaObject.getDuration() > 1) {
			// 鏈浆鐮?			new AlertDialog.Builder(this)
					.setTitle(R.string.hint)
					.setMessage(R.string.record_camera_exit_dialog_message)
					.setNegativeButton(
							R.string.record_camera_cancel_dialog_yes,
							new DialogInterface.OnClickListener() {

								@Override
								public void onClick(DialogInterface dialog,
										int which) {
									mMediaObject.delete();
									finish();
									overridePendingTransition(
											R.anim.push_bottom_in,
											R.anim.push_bottom_out);
								}

							})
					.setPositiveButton(R.string.record_camera_cancel_dialog_no,
							null).setCancelable(false).show();
			return;
		}

		if (mMediaObject != null)
			mMediaObject.delete();
		finish();
		overridePendingTransition(R.anim.push_bottom_in, R.anim.push_bottom_out);
	}

	/** 鍋滄褰曞埗 */
	private void stopRecord() {
		mPressedStatus = false;
		mRecordController.setImageResource(R.drawable.record_controller_normal);
		mBottomLayout.setBackgroundColor(mBackgroundColorNormal);

		if (mMediaRecorder != null) {
			mMediaRecorder.stopRecord();
		}

		mRecordDelete.setVisibility(View.VISIBLE);
		mCameraSwitch.setEnabled(true);
		mRecordLed.setEnabled(true);

		mHandler.removeMessages(HANDLE_STOP_RECORD);
		checkStatus();
	}

	@Override
	public void onClick(View v) {
		final int id = v.getId();
		if (mHandler.hasMessages(HANDLE_STOP_RECORD)) {
			mHandler.removeMessages(HANDLE_STOP_RECORD);
		}

		// 澶勭悊寮€鍚洖鍒犲悗鍏朵粬鐐瑰嚮鎿嶄綔
		if (id != R.id.record_delete) {
			if (mMediaObject != null) {
				MediaObject.MediaPart part = mMediaObject.getCurrentPart();
				if (part != null) {
					if (part.remove) {
						part.remove = false;
						mRecordDelete.setChecked(false);
						if (mProgressView != null)
							mProgressView.invalidate();
					}
				}
			}
		}

		switch (id) {
		case R.id.title_back:
			onBackPressed();
			break;
		case R.id.record_camera_switcher:// 鍓嶅悗鎽勫儚澶村垏鎹?			if (mRecordLed.isChecked()) {
				if (mMediaRecorder != null) {
					mMediaRecorder.toggleFlashMode();
				}
				mRecordLed.setChecked(false);
			}

			if (mMediaRecorder != null) {
				mMediaRecorder.switchCamera();
			}

			if (mMediaRecorder.isFrontCamera()) {
				mRecordLed.setEnabled(false);
			} else {
				mRecordLed.setEnabled(true);
			}
			break;
		case R.id.record_camera_led:// 闂厜鐏?			// 寮€鍚墠缃憚鍍忓ご浠ュ悗涓嶆敮鎸佸紑鍚棯鍏夌伅
			if (mMediaRecorder != null) {
				if (mMediaRecorder.isFrontCamera()) {
					return;
				}
			}

			if (mMediaRecorder != null) {
				mMediaRecorder.toggleFlashMode();
			}
			break;
		case R.id.title_next:// 鍋滄褰曞埗
			mMediaRecorder.startEncoding();
			finish();
			overridePendingTransition(R.anim.push_bottom_in,
					R.anim.push_bottom_out);
			break;
		case R.id.record_delete:
			// 鍙栨秷鍥炲垹
			if (mMediaObject != null) {
				MediaObject.MediaPart part = mMediaObject.getCurrentPart();
				if (part != null) {
					if (part.remove) {
						mRebuild = true;
						part.remove = false;
						mMediaObject.removePart(part, true);
						mRecordDelete.setChecked(false);
					} else {
						part.remove = true;
						mRecordDelete.setChecked(true);
					}
				}
				if (mProgressView != null)
					mProgressView.invalidate();

				// 妫€娴嬫寜閽姸鎬?				checkStatus();
			}
			break;
		}
	}

	/** 鍙栨秷鍥炲垹 */
	private boolean cancelDelete() {
		if (mMediaObject != null) {
			MediaObject.MediaPart part = mMediaObject.getCurrentPart();
			if (part != null && part.remove) {
				part.remove = false;
				mRecordDelete.setChecked(false);

				if (mProgressView != null)
					mProgressView.invalidate();

				return true;
			}
		}
		return false;
	}

	/** 妫€鏌ュ綍鍒舵椂闂达紝鏄剧ず/闅愯棌涓嬩竴姝ユ寜閽?*/
	private int checkStatus() {
		int duration = 0;
		if (!isFinishing() && mMediaObject != null) {
			duration = mMediaObject.getDuration();
			if (duration < RECORD_TIME_MIN) {
				if (duration == 0) {
					mCameraSwitch.setVisibility(View.VISIBLE);
					mRecordDelete.setVisibility(View.GONE);
				}
				// 瑙嗛蹇呴』澶т簬3绉?				if (mTitleNext.getVisibility() != View.INVISIBLE)
					mTitleNext.setVisibility(View.INVISIBLE);
			} else {
				// 涓嬩竴姝?				if (mTitleNext.getVisibility() != View.VISIBLE) {
					mTitleNext.setVisibility(View.VISIBLE);
				}
			}
		}
		return duration;
	}

	private Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case HANDLE_INVALIDATE_PROGRESS:
				if (mMediaRecorder != null && !isFinishing()) {
					if (mProgressView != null)
						mProgressView.invalidate();
					// if (mPressedStatus)
					// titleText.setText(String.format("%.1f",
					// mMediaRecorder.getDuration() / 1000F));
					if (mPressedStatus)
						sendEmptyMessageDelayed(0, 30);
				}
				break;
			}
		}
	};

	@Override
	public void onEncodeStart() {
		showProgress("", getString(R.string.record_camera_progress_message));
	}

	@Override
	public void onEncodeProgress(int progress) {
		Logger.e("[MediaRecorderActivity]onEncodeProgress..." + progress);
	}

	/** 杞爜瀹屾垚 */
	@Override
	public void onEncodeComplete() {
		hideProgress();
		Intent intent = new Intent(this, MediaPreviewActivity.class);
		Bundle bundle = getIntent().getExtras();
		if (bundle == null)
			bundle = new Bundle();
		bundle.putSerializable(CommonIntentExtra.EXTRA_MEDIA_OBJECT,
				mMediaObject);
		bundle.putString("output", mMediaObject.getOutputTempVideoPath());
		bundle.putBoolean("Rebuild", mRebuild);
		intent.putExtras(bundle);
		startActivity(intent);
		mRebuild = false;
		// finish();
		// overridePendingTransition(R.anim.push_bottom_in,
		// R.anim.push_bottom_out);
	}

	/**
	 * 杞爜澶辫触 妫€鏌dcard鏄惁鍙敤锛屾鏌ュ垎鍧楁槸鍚﹀瓨鍦?	 */
	@Override
	public void onEncodeError() {
		hideProgress();
		Toast.makeText(this, R.string.record_video_transcoding_faild,
				Toast.LENGTH_SHORT).show();
	}

	@Override
	public void onVideoError(int what, int extra) {

	}

	@Override
	public void onAudioError(int what, String message) {

	}

	@Override
	public void onPrepared() {

	}

	public void onFinished() {
		finish();
		overridePendingTransition(R.anim.push_bottom_in, R.anim.push_bottom_out);
	}
}