package jp.agentec.abook.abv.ui.viewer.activity;

import java.util.Arrays;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.GestureDetector.OnDoubleTapListener;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener;
import android.view.View;
import android.widget.ImageView;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.cl.util.BitmapUtil;
import jp.agentec.abook.abv.ui.common.util.DisplayUtil;

public class ImageViewActivity extends NoPdfViewActivity {
	private static final String TAG_LOG = "ImageViewActivity";
	private ABVImageView imageView;

	@Override
	public void onCreate(Bundle savedInstanceState) {
        Logger.i(TAG_LOG, "onCreate");
		super.onCreate(savedInstanceState);
        Intent intent = getIntent();
		String filepath =  intent.getStringExtra(FILEPATH);
		Logger.d(TAG_LOG, "onCreate:" + filepath);

		// イメージ設定
		long availableImageBytePerPage = (long) (Runtime.getRuntime().maxMemory() * 0.9); // １ページあたりオーサリング・イメージに使用できるメモリ量
		long totalBitmapSize = BitmapUtil.getTotalBitmapSize(Arrays.asList(filepath), Config.ARGB_8888); // イメージサイズ
		Bitmap bitmap;
		if (totalBitmapSize < availableImageBytePerPage) { // イメージをオリジナルサイズで描画してよいか
			bitmap = BitmapUtil.getBitmap(filepath, Bitmap.Config.ARGB_8888);
		}
		else {
			Point point = DisplayUtil.getDisplaySize(this);
			bitmap = BitmapUtil.getResizedBitmap(filepath, point.x, point.y, Config.ARGB_8888);
		}

		imageView = new ABVImageView(this, bitmap);
		addViewToMainFrame(imageView);
		
		// 最初はツールバーを表示しない
		getToolbar().setVisibility(View.GONE);
	}

	@Override
	public void onStop() {
		super.onStop();
		imageView.setImageDrawable(null);
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
	}

	/**
	 * イメージ表示ビュー
	 *
	 */
	class ABVImageView extends ImageView {
        private static final String TAG = "ABVImageView";
		
		// タッチの状態管理
		private static final int TOUCH_NONE   = 0;
		private static final int TOUCH_SINGLE = 1;
		private static final int TOUCH_MULTI  = 2;
		private int touchMode = TOUCH_NONE;
		// 画像処理
		private Matrix initMatrix = null; // 初期描画直後
		private Matrix baseMatrix = new Matrix(); // タッチダウン時の画像保存用
		private Matrix imgMatrix = new Matrix(); //画像変換用
		private PointF po0 = new PointF();   // 移動の開始点

		private ScaleGestureDetector mScaleGestureDetector;
		private GestureDetector mGestureDetector;
		
		private Bitmap mBitmap;
		private float mInitialScale;
		private float minScale = 0.3f;
		private float maxScale = 5f;
		private float viewWidth;
		private float viewHeight;
		private float bitmapWidth;
		private float bitmapHeight;
		private boolean doubleTap;

		public ABVImageView(Context context, Bitmap bitmap) {
			super(context);
			mBitmap = bitmap;
			setScaleType(ImageView.ScaleType.MATRIX);
			mScaleGestureDetector = new ScaleGestureDetector(context, onScaleGestureListener);
			mGestureDetector = new GestureDetector(context, mGestureListener);
			mGestureDetector.setOnDoubleTapListener(mDoubleTapListener);
		}

		@Override
		protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
			Logger.v(TAG, "onLayout");
			super.onLayout(changed, left, top, right, bottom);
			if (super.getWidth() == 0) { // Viewの幅が0の場合（まだViewが形成されていない）
				return;
			}
			drawImage();
		}

		/**
		 * 描画処理
		 */
		private void drawImage() {
			Logger.v(TAG, "drawImage");
			
			if (getDrawable() == null) { // 初期設定
				setImageBitmap(mBitmap);
				viewWidth = getWidth();
				viewHeight = getHeight();
				bitmapWidth = mBitmap.getWidth();
				bitmapHeight = mBitmap.getHeight();
				float scaleX = viewWidth / bitmapWidth;
				float scaleY = viewHeight / bitmapHeight;
				mInitialScale =  Math.min(scaleX, scaleY);
				if (Math.min(scaleX, scaleY) > 1) { // 画像が画面より小さい場合は原寸大で表示
					viewWidth = bitmapWidth;
					viewHeight = bitmapHeight;
					mInitialScale = 1;
					minScale = 0.5f;
					maxScale = Math.min(scaleX, scaleY);
				}
				
				minScale *= mInitialScale;
				maxScale *= mInitialScale;
				imgMatrix.postScale(mInitialScale, mInitialScale);
			}

			// センタリング
			float calX = getWidth() - bitmapWidth * mInitialScale;
            if (calX > 0) {
				setMatrixValue(Matrix.MTRANS_X, calX / 2, imgMatrix);
			}
			else {
				setMatrixValue(Matrix.MTRANS_X, 0f, imgMatrix);
			}

			float calY =  getHeight() - bitmapHeight * mInitialScale;
			if (calY > 0) {
				setMatrixValue(Matrix.MTRANS_Y, calY / 2, imgMatrix);
			}
			else {
				setMatrixValue(Matrix.MTRANS_Y, 0f, imgMatrix);
			}

			if (initMatrix == null) { // 初期値保存
				initMatrix = new Matrix();
				baseMatrix.set(imgMatrix);
				initMatrix.set(imgMatrix);
				Logger.v(TAG, "[drawImage] initMatrix=%s:%s:%s", getMatrixValue(initMatrix, Matrix.MSCALE_X), getMatrixValue(initMatrix, Matrix.MTRANS_X), getMatrixValue(initMatrix, Matrix.MTRANS_Y));
			}

			setImageMatrix(imgMatrix);
		}

		/**
		 * Matrixオブジェクトに値を設定する
		 * @param index
		 * @param value
		 * @param matrix
		 */
		private void setMatrixValue(int index, float value, Matrix matrix) {
			float[] values = new float[9];
			matrix.getValues(values);
			values[index] = value;
			matrix.setValues(values);
		}

		private float getMatrixValue(Matrix matrix, int index) {
			float[] value = new float[9];
			if (matrix != null) {
				matrix.getValues(value);
			}
			return value[index];
		}

		@Override
		public boolean onTouchEvent(MotionEvent event) {
			Logger.v(TAG, "[onTouchEvent]%s", event);

			if (event.getPointerCount() >= 2) {
				mScaleGestureDetector.onTouchEvent(event);
			}

			mGestureDetector.onTouchEvent(event);
			if (doubleTap) {
				doubleTap = false;
				return true;
			}

			switch(event.getAction() & MotionEvent.ACTION_MASK) {
			case MotionEvent.ACTION_DOWN:
				if (touchMode == TOUCH_NONE && event.getPointerCount() == 1) {
					Logger.v("touch", "DOWN");
					po0.set(event.getX(), event.getY());
					baseMatrix.set(imgMatrix);
					touchMode = TOUCH_SINGLE;
				}
				break;
			case MotionEvent.ACTION_MOVE:
				if (touchMode == TOUCH_SINGLE) {
					Logger.v("touch", "MOVE");
					imgMatrix.set(baseMatrix);
					imgMatrix.postTranslate(event.getX() - po0.x, event.getY() - po0.y);
				}
				break;
			case MotionEvent.ACTION_UP:
				if (touchMode == TOUCH_SINGLE) {
					Logger.v("touch", "UP");
					touchMode = TOUCH_NONE;
				}
				break;
			}

			setImageMatrix(imgMatrix);
			return true;
		}

		private SimpleOnGestureListener mGestureListener = new SimpleOnGestureListener() {};
		
		private final SimpleOnScaleGestureListener onScaleGestureListener = new SimpleOnScaleGestureListener() {

			@Override
			public boolean onScale(ScaleGestureDetector detector) {
				Logger.v(TAG, "[onScale]%s", detector.getScaleFactor());
				float scale = getMatrixValue(imgMatrix, Matrix.MSCALE_X) * detector.getScaleFactor();
				if (minScale < scale && scale < maxScale) {
					imgMatrix.set(baseMatrix);
					imgMatrix.postScale(detector.getScaleFactor(), detector.getScaleFactor(),
							detector.getFocusX(), detector.getFocusY());
				}
				return super.onScale(detector);
			}

			@Override
			public boolean onScaleBegin(ScaleGestureDetector detector) {
				Logger.v(TAG, "[onScaleBegin]%s", detector);
				baseMatrix.set(imgMatrix);
				touchMode = TOUCH_MULTI;
				return super.onScaleBegin(detector);
			}

			@Override
			public void onScaleEnd(ScaleGestureDetector detector) {
				Logger.v(TAG, "[onScaleEnd]%s", detector);
				touchMode = TOUCH_NONE;
				super.onScaleEnd(detector);
			} 
		};

		protected OnDoubleTapListener mDoubleTapListener = new OnDoubleTapListener() {

			@Override
            public boolean onSingleTapConfirmed(MotionEvent e) {
				Logger.d(TAG, "[OnDoubleTapListener]:[onSingleTapConfirmed]");
                if (getToolbar().getVisibility() == View.VISIBLE) {
                    getToolbar().setVisibility(View.INVISIBLE);
                } else {
                    getToolbar().setVisibility(View.VISIBLE);
                }
				setMeetingParticipantCount(getToolbar().getVisibility() == View.VISIBLE, ImageViewActivity.this.findViewById(android.R.id.content));
				return false;
			}

			@Override
            public boolean onDoubleTapEvent(MotionEvent e) {
				Logger.d(TAG, "[OnDoubleTapListener]:[onDoubleTapEvent]");
				return true;
			}

			@Override
            public boolean onDoubleTap(MotionEvent e) {
				doubleTap = true;
				// 通常、1回のみの処理であればこのメソッドで実装する
				float nowScale = getMatrixValue(imgMatrix,Matrix.MSCALE_X);
				Logger.d(TAG, "[OnDoubleTapListener]:[onDoubleTap] nowScale=" + nowScale + " maxScale=" + maxScale);
				float nextScale;
				if (nowScale < mInitialScale) {
					nextScale = mInitialScale / nowScale;
				}
				else if (nowScale < maxScale/ 1.5f) { // MAX_SCALEの3分の２以下の場合
					nextScale = maxScale / 1.5f / nowScale;
				} else if (nowScale > maxScale * 0.95) {
					imgMatrix.set(initMatrix);
					setImageMatrix(imgMatrix);
					return true;
				} else {
					nextScale = maxScale / nowScale;
				}
				Logger.d(TAG, "[OnDoubleTapListener]:[onDoubleTap] nextScale=" + nextScale);

				Matrix checkMatrix = new Matrix(imgMatrix);
				checkMatrix.postScale(nextScale, nextScale, e.getX(), e.getY());
				imgMatrix.set(checkMatrix);

				Logger.v(TAG, "[onDoubleTap:setImageMatrix] %s", getMatrixValue(imgMatrix, Matrix.MSCALE_X));
				setImageMatrix(imgMatrix);
				return true;
			}
		};

	}
}

