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

import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
import android.view.DragEvent;
import android.view.GestureDetector;
import android.view.GestureDetector.OnDoubleTapListener;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.SimpleOnScaleGestureListener;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.RelativeLayout;

import java.util.List;

import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.bl.data.dao.AbstractDao;
import jp.agentec.abook.abv.bl.data.dao.ContentMemoDao;
import jp.agentec.abook.abv.bl.dto.ContentDto;
import jp.agentec.abook.abv.bl.dto.ContentMemoDto;
import jp.agentec.abook.abv.bl.dto.OperationTaskDto;
import jp.agentec.abook.abv.bl.logic.AbstractLogic;
import jp.agentec.abook.abv.bl.logic.MemoLogic;
import jp.agentec.abook.abv.launcher.android.R;
import jp.agentec.abook.abv.ui.common.constant.IFPDFConst;
import jp.agentec.abook.abv.ui.common.util.ClipboardUtil;
import jp.agentec.abook.abv.ui.common.view.ABVPopupListWindow;
import jp.agentec.abook.abv.ui.common.vo.Size;
import jp.agentec.abook.abv.ui.home.activity.GuideViewActivity;
import jp.agentec.abook.abv.ui.Interface.UnAuthorizedContentListener;
import jp.agentec.abook.abv.ui.viewer.activity.ContentViewActivity;
import jp.agentec.abook.abv.ui.viewer.view.action.MemoManager;
import jp.agentec.adf.util.DateTimeUtil;

/**
 * オーサリングしたオブジェクト等が配置されるレイア
 * MmainLayout-PageScrollView-RelativeLayout(mContentWrapLayout)の配下に位置する
 * @author jang
 *
 */
public class ZoomRelativeLayout extends RelativeLayout {
	private static final String TAG = "ZoomRelativeLayout";
	private ContentMemoDao contentMemoDao = AbstractDao.getDao(ContentMemoDao.class);
	private MemoLogic memoLogic = AbstractLogic.getLogic(MemoLogic.class);

	private float mScaleFactor = 1.0f;
	private float mLastTouchX;
	private float mLastTouchY;
	private static final int INVALID_POINTER_ID = -1;
	// The ‘active pointer’ is the one currently moving our object.
	private int mActivePointerId = INVALID_POINTER_ID;
	
	private PageScrollView mPageScrollView;
	
	private GestureDetector mGestureDetector;
	private ScaleGestureDetector mScaleDetector;
	
	private Matrix initMatrix = new Matrix();
	private Matrix baseMatrix = new Matrix(); // タッチダウン時の画像保存用
	private Matrix imgMatrix = new Matrix();
	
	private Size mPdfSize = null;
	private Size mAuthoringPageSize;
	private float mPdfScale;
	private float mAuthoringScale;
	private Context mContext;
	
	private int mPageNumber;
	private ContentDto mContentDto;

//	private boolean isFittingLandscape; // 画面サイズの横幅に合わせるかどうか
	
	private ViewMargin margin;
	private ABVPopupListWindow mShowedPopupWindow = null;
	private PageView mPageView;

	private UnAuthorizedContentListener mListener;

	private boolean isOperationPdf = false;
    private float fX;
    private float fY;

	class MyDragListener implements OnDragListener {
		@Override
		public boolean onDrag(View v, DragEvent event) {
			switch (event.getAction()) {
				case DragEvent.ACTION_DRAG_STARTED:
					//理由不明、イベントが二回くる、二回目でgetX()だけがマイナス
					if (event.getX() > 0) {
						fX = event.getX();
						fY = event.getY();
					}
					break;
				case DragEvent.ACTION_DRAG_ENTERED:
					break;
				case DragEvent.ACTION_DRAG_EXITED:
					break;
				case DragEvent.ACTION_DROP:
					View view = (View) event.getLocalState();
					float mX = event.getX();
					float mY = event.getY();

					float[] pdfMatrix = getMatrixValue(getPageView().imgMatrix);
					float scaledWidth = getScaledPDFWidth(pdfMatrix[Matrix.MSCALE_X]);
					float scaledHeight = getScaledPDFHeight(pdfMatrix[Matrix.MSCALE_Y]);
					float pdfX = pdfMatrix[Matrix.MTRANS_X];
					float pdfY = pdfMatrix[Matrix.MTRANS_Y];

					// If left-out or right-out of PDF
					if ((mX - pdfX) < 0) {
						mX = pdfX;
					} else if (((pdfX + scaledWidth) - mX) < 0) {
						mX = pdfX + scaledWidth;
					}
					// Yの座標がPDF範囲を超えたか判定フラグ
					boolean isOutTranslation = false;
					// If top-out or bottom-out of PDF
					// PDFの端上の基準値をピンとコードで分ける
					float checkTopY = (view instanceof ActionOperationTaskPin ? (mY + view.getHeight() / 2) : mY);
					if (checkTopY - pdfY < 0) {
						isOutTranslation = true;
						mY = pdfY;
					} else if (((pdfY + scaledHeight) - mY) < 0) {
						isOutTranslation = true;
						mY = pdfY + scaledHeight;
					}
					// 作業のx座標をセット
					view.setTranslationX(mX - view.getWidth() / 2);
					// 作業のy座標をセット(作業アイコンがピンで且つ、PDF範囲を超えたフラグ（isOutTranslation）がtrueの場合、（mY - アイコンの縦サイズ）で縦をセットする)
					view.setTranslationY(mY - (isOutTranslation && view instanceof ActionOperationTaskPin ? view.getHeight() : view.getHeight() / 2));
					// タップした座標をPDF用の座標に変換する
					PointF pdfPoint = convertToTapPoint(mX, view instanceof ActionOperationTaskPin && !isOutTranslation ? mY + view.getHeight() / 2 : mY);

					// 座標を更新する
					((ContentViewActivity) mContext).updateOperationTaskPosition(pdfPoint.x, pdfPoint.y);
					if (view instanceof ActionOperationTaskCode || view instanceof ActionOperationTaskPin) {
						((ContentViewActivity) mContext).updateOperationTaskPosition();
					}

					if (view.getVisibility() == View.INVISIBLE) {
						view.setVisibility(View.VISIBLE);
					}

					break;
				case DragEvent.ACTION_DRAG_ENDED:
				default:
					break;
			}
			return true;
		}
	}

	public ZoomRelativeLayout(Context context) {
		super(context);
		mContext = context;
		mGestureDetector = new GestureDetector(context, mGestureListener); // 画面の通常ジェスチャーを制御する
		mGestureDetector.setOnDoubleTapListener(mDoubleTapListener); // 画面のダブルタップジェスチャーを制御する
		mScaleDetector = new ScaleGestureDetector(context, onScaleGestureListener); // 画面の拡大・縮小ジェスチャーを制御する
		mPdfScale = 1.0f;
	}

    public ZoomRelativeLayout(Context context, boolean isOperationPdf) {
        this(context);
        this.isOperationPdf = isOperationPdf;

        if(this.isOperationPdf) {
            this.setOnDragListener(new MyDragListener());
        }
    }
	
	@Override
	protected void dispatchDraw(Canvas canvas) {
		canvas.save();
		if (!isOperationPdf) {
			canvas.concat(imgMatrix);
		}
		super.dispatchDraw(canvas);
		invalidate();
		canvas.restore();
	}
	
	@Override
	protected void onConfigurationChanged(Configuration newConfig) {
		Logger.d(TAG, "onConfigurationChanged");
		super.onConfigurationChanged(newConfig);
	}
	
	@Override
	protected void onDetachedFromWindow() {
		Logger.d(TAG, "onDetachedFromWindow");
		if (mShowedPopupWindow != null && mShowedPopupWindow.isShowing()) {
            mShowedPopupWindow.dismiss();
        }
		super.onDetachedFromWindow();
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		Logger.d(TAG, "[onTouchEvent]:action=" + ev.getAction() + ", count=" + ev.getPointerCount() + ", mScaleFactor=" + mScaleFactor);
		
		// TODO later 要らない？ Jang
		if (mPageScrollView.isVideoMax()) {
			return false;
		}
		
		super.onTouchEvent(ev);
		// 
		ViewGroup parenGroup = (ViewGroup) getParent();
		
		if (parenGroup == null) {
			// ありえない?
			Logger.w(TAG, "[onTouchEvent]:parentGroup is null");
			return true;
		}
		
		// PageViewへ同様にタッチイベントを送る
		getPageView().onTouchEvent(ev);
		
		// スケールディテクターへタッチイベントを送る
		mScaleDetector.onTouchEvent(ev);
		if (mScaleDetector.isInProgress()) {
			Logger.d(TAG, "[onTouchEvent]:mScaleGestureDetector　isInProgressing");
			return true;
		}
		
		mGestureDetector.onTouchEvent(ev);

		if (mScaleFactor > 1.0f) {
			mPageScrollView.requestDisallowInterceptTouchEvent(true); // スクロールビューがイベント処理に干渉しないようにする
			final int action = ev.getAction();
		    switch (action & MotionEvent.ACTION_MASK) {
			    case MotionEvent.ACTION_DOWN: {
			        final float x = ev.getX();
			        final float y = ev.getY();
			        
			        mLastTouchX = x;
			        mLastTouchY = y;
			        mActivePointerId = ev.getPointerId(0);
			        baseMatrix.set(imgMatrix);
			        break;
			    }
			        
			    case MotionEvent.ACTION_MOVE: {
			    	if (mActivePointerId == INVALID_POINTER_ID) {
			    		break;
			    	}
			        final int pointerIndex = ev.findPointerIndex(mActivePointerId);
			        final float x = ev.getX(pointerIndex);
			        final float y = ev.getY(pointerIndex);
		
			        // Only move if the ScaleGestureDetector isn't processing a gesture.
			        if (!mScaleDetector.isInProgress()) {
			            final float dx = x - mLastTouchX;
			            final float dy = y - mLastTouchY;
			            Matrix checkMatrix = new Matrix();
			            checkMatrix.set(imgMatrix);
			            checkMatrix.postTranslate(dx, dy);
			        	imgMatrix.set(checkMatrix);
						invalidate();
			        }
		
			        mLastTouchX = x;
			        mLastTouchY = y;
					// 作業の座標をすべて調整する
					changeTaskChildView();
			        break;
			    }
			        
			    case MotionEvent.ACTION_UP: {
			        mActivePointerId = INVALID_POINTER_ID;
			        Logger.v(TAG, "[onTouchEvent]ACTION_UP");
			        fixPosition();
			        break;
			    }
			        
			    case MotionEvent.ACTION_CANCEL: {
			        mActivePointerId = INVALID_POINTER_ID;
			        break;
			    }
			    
			    case MotionEvent.ACTION_POINTER_UP: {
			    	Logger.v(TAG, "[onTouchEvent]ACTION_POINTER_UP");
			        final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) 
			                >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
			        final int pointerId = ev.getPointerId(pointerIndex);
			        if (pointerId == mActivePointerId) {
			            // This was our active pointer going up. Choose a new
			            // active pointer and adjust accordingly.
			            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
			            mLastTouchX = ev.getX(newPointerIndex);
			            mLastTouchY = ev.getY(newPointerIndex);
			            mActivePointerId = ev.getPointerId(newPointerIndex);
			        }
			        break;
			    }
		    }
		} else {
	    	mPageScrollView.requestDisallowInterceptTouchEvent(false);
	    	if (mContext instanceof ContentViewActivity) {
				((ContentViewActivity)mContext).setDefaultVideo();
			} else {
				((GuideViewActivity)mContext).setDefaultVideo();
			}
	    }
		return true;
	}
	
	private PageView getPageView() {
		ViewGroup parenGroup = (ViewGroup) getParent();
		if (mPageView == null && parenGroup != null) {
			for (int i = 0; i < parenGroup.getChildCount(); i++) {
				View view = parenGroup.getChildAt(i);
				if (!view.equals(this) && view instanceof PageView) {
					Logger.d(TAG, "child view=" + view);
					mPageView = (PageView) view;
					break;
				}
			}
		}
		return mPageView;
	}

	/**
	 * 作業の座標をすべて調整する
	 */
	public void changeTaskChildView() {
    	if (getChildCount() > 0) {
			for (int i = 0; i < getChildCount(); i++) {
				View view = getChildAt(i);
				if (view instanceof ActionOperationTaskCode) {
					setTaskTranslationCode((ActionOperationTaskCode) view);
				} else if (view instanceof ActionOperationTaskPin) {
					setTaskTranslationPin((ActionOperationTaskPin) view);
				}
			}
		}
	}

	/**
	 * ActionOperationTaskCodeのx,y座標をセット
	 * @param view
	 */
	private void setTaskTranslationCode(ActionOperationTaskCode view) {
		OperationTaskDto dto = view.mOperationTaskDto;
		PointF point = convertToScalePoint(dto.pdfX, dto.pdfY);
		view.setTranslationX(point.x - (view.getWidth() / 2));
		view.setTranslationY(point.y - (view.getHeight() / 2));
	}

	/**
	 * ActionOperationTaskPinのx,y座標をセット
	 * @param view
	 */
	private void setTaskTranslationPin(ActionOperationTaskPin view) {
		OperationTaskDto dto = view.mOperationTaskDto;
		PointF point = convertToScalePoint(dto.pdfX, dto.pdfY);
		view.setTranslationX(point.x - (view.getWidth() / 2));
		view.setTranslationY(point.y - view.getHeight());
	}

	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		Logger.v(TAG, "[onSizeChanged]:width=%s, height=%s oldw=%s, oldh=%s,pageNumber=%s", w, h, oldw, oldh, mPageNumber);
		super.onSizeChanged(w, h, oldw, oldh);
	}
	
	// Set Get Method--------------------------------------------------------------------
	public float getPDFPageScale() {
		return mPdfScale;
	}
	
	public void setPageScrollView(PageScrollView pageScrollView) {
		mPageScrollView = pageScrollView;
	}
	
	public void setPageSize(Size pdfSize) {
		mPdfSize = pdfSize;
	}
	
	public void setAuthoringPageSize(int width, int height) {
		mAuthoringPageSize = new Size(width, height);
	}
	
	// ↓ MemoAction用追加 Tanigawa 2012/4/19 ↓
	public void setPageNumber(int PageNumber) {
		mPageNumber = PageNumber;
	}

	public void setContentDto(ContentDto contentDto) {
		mContentDto = contentDto;
	}

	public void setUnAuthorizedContentListener(UnAuthorizedContentListener listener) {
		mListener = listener;
	}

	// ↑ MemoAction用追加 Tanigawa 2012/4/19 ↑
	
	public float[] getMatrixValue() {
		return getMatrixValue(imgMatrix);
	}
	
	public ViewMargin getContentPageMargin() {
		Logger.d(TAG, "getContentPageMargin():=%s", margin);
		return margin;
	}
	
	public void setPageMargin(int width, int height) {
		margin = new ViewMargin();
		mPdfScale = Math.min(width / (float)mPdfSize.width, height / (float)mPdfSize.height);
		margin.left = (width - (int)getDefaultPDFWidth()) / 2;
		margin.top = (height - (int)getDefaultPDFHeight()) / 2;
		margin.right = width - (int)getDefaultPDFWidth() - margin.left;
		margin.bottom = height - (int)getDefaultPDFHeight() - margin.top;
		Logger.d(TAG, "ZoomLayout.width=%s, height=%s margin=%s Page=%s mPdfScale=%s", width, height, margin, mPageNumber, mPdfScale);
		
	}

	private float getMarginX(float scale) {
		return (getWidth() - mPdfSize.width * scale) / 2;
	}
	
	private float getMarginY(float scale) {
		return (getHeight() - mPdfSize.height * scale) / 2;
	}
	
	private float[] getMatrixValue(Matrix matrix) {
		float[] value = new float[9];
		if (matrix != null) {
			matrix.getValues(value);
		}
		return value;
	}

    private float getDefaultPDFWidth() {
		return getScaledPDFWidth(1);
	}

    private float getDefaultPDFHeight() {
		return getScaledPDFHeight(1);
	}
	
	public float getScaledPDFWidth(float matrixScale) {
		return mPdfSize.width * mPdfScale * matrixScale;
	}
	
	public float getScaledPDFHeight(float matrixScale) {
		return mPdfSize.height * mPdfScale * matrixScale;
	}
	
	
	public float getAuthoringScale() {
		return mAuthoringScale;
	}

	public void setAuthoringScale(float authoringScale) {
		this.mAuthoringScale = authoringScale;
	}

	public int getResizedForDisplayScale(float aValue) {
		return (int) (mAuthoringScale * aValue);
	}
	
	public int getPageNumber() {
		return mPageNumber;
	}
	

	private SimpleOnScaleGestureListener onScaleGestureListener = new SimpleOnScaleGestureListener() {
		
		@Override
		public boolean onScale(ScaleGestureDetector detector) {
			Matrix checkMatrix = new Matrix();
			checkMatrix.set(baseMatrix);
			checkMatrix.postScale(detector.getScaleFactor(),
					detector.getScaleFactor(), detector.getFocusX(),
					detector.getFocusY());
			float[] matrixValue = getMatrixValue(checkMatrix);
			float matrixScale = matrixValue[Matrix.MSCALE_X];
			if (IFPDFConst.MIN_SCALE < matrixScale && matrixScale < IFPDFConst.MAX_SCALE) {
				imgMatrix.set(baseMatrix);
				imgMatrix.postScale(detector.getScaleFactor(), detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY());
				mScaleFactor = matrixScale;
				invalidate();
			}
			// 作業の座標をすべて調整する
			changeTaskChildView();
			Logger.v(TAG, "SimpleOnScaleGestureListener:[onScale]:scaleFactor=%s", mScaleFactor);
			
			return super.onScale(detector);
		}

        @Override
		public boolean onScaleBegin(ScaleGestureDetector detector) {
			mPageScrollView.requestDisallowInterceptTouchEvent(true);
			mPageScrollView.setZoomingFlag(true);
			if (mContext instanceof ContentViewActivity) {
				((ContentViewActivity)mContext).setToolbarVisable(false);
				((ContentViewActivity)mContext).stopVideo();
			} else {
				((GuideViewActivity)mContext).setToolbarVisable(false);
				((GuideViewActivity)mContext).stopVideo();
			}

			mPdfScale = Math.min(getWidth() / (float)mPdfSize.width, getHeight() / (float)mPdfSize.height);
			baseMatrix.set(imgMatrix);
			Logger.v(TAG, "SimpleOnScaleGestureListener:[onScaleBegin]:mPdfScale=%s, width=%s", mPdfScale, getWidth());
			return super.onScaleBegin(detector);
		}
		
		@Override
		public void onScaleEnd(ScaleGestureDetector detector) {
			fixPosition();
			mPageScrollView.requestDisallowInterceptTouchEvent(false);

            if (isOperationPdf) {
                ((ContentViewActivity) mContext).setScaleZoomIcon(mScaleFactor);
            }
		}
		
	};

	/**
	 * 指を離したあとの座標を補正する
	 */
	private void fixPosition() {
		float[] matrixValue = getMatrixValue(imgMatrix);
		
		final float matrixScale = matrixValue[Matrix.MSCALE_X];
		float matrixX = matrixValue[Matrix.MTRANS_X];// 左上のマトリックスX座標
		float matrixY = matrixValue[Matrix.MTRANS_Y];// 左上のマトリックスY座標
		
		Logger.d(TAG, "[fixPosition][start]:(matrix)scale=%s, (Display)width=%s, height=%s", matrixScale, getWidth(), getHeight());
		if (matrixScale < 1.0f) {
			Logger.v(TAG, "[fixPosition]:init");
			// 初期サイズへ変更
			mScaleFactor = 1.0f;
			mPageScrollView.setZoomingFlag(false);
			imgMatrix.set(initMatrix);
			invalidate();
			// 作業の座標をすべて調整する
			changeTaskChildView();
		} else {
			mScaleFactor = matrixScale;
			
			Logger.v(TAG, "[fixPosition][before]x=%s, y=%s", matrixX, matrixY);
			
			float scaledPDFWidth = getScaledPDFWidth(matrixScale);
			float scaledPDFHeight = getScaledPDFHeight(matrixScale);
			
			// 横幅の拡大サイズが画面サイズより小さい
			if (scaledPDFWidth < getWidth()) {
				// 真ん中に移動
				matrixX = (getWidth() / 2) - (getWidth() * matrixScale / 2);
				Logger.v(TAG, "[fixPosition]center horizontal");
			}
			// 縦幅の拡大サイズが画面サイズより小さい
			if (scaledPDFHeight < getHeight()) {
				// 真ん中に移動
				matrixY = getHeight() / 2 - getHeight() * matrixScale / 2;
				Logger.v(TAG, "[fixPosition]center vectical");
			}
			
			// 画面上でPDFサイズを除いたマージサイズ
			float marginWidth = (getWidth() * matrixScale - scaledPDFWidth) / 2;
			float marginHeight = (getHeight() * matrixScale - scaledPDFHeight) / 2;
			
			// マージンを適用したPDF座標
			float minX = matrixX + marginWidth;// PDFの左上のX座標
			float minY = matrixY + marginHeight;// PDFの左上のY座標
			
			float maxX = minX + scaledPDFWidth;// PDFの右上のX座標
			float maxY = minY + scaledPDFHeight;// PDFの右上のY座標
			
			if (minX < 0 && maxX < getWidth()) {
				// 左側によっていて、右側があいている状況
				minX += getWidth() - maxX; // 右側へ寄せる
				matrixX = minX - marginWidth;
				Logger.v(TAG, "[fixPosition]:fittingToRight:x=%s", matrixX);
			} else if (minX > 0 && maxX > getWidth()) {
				// 右側によっていて、左側があいている状況
				minX = 0; // 左側へ寄せる
				matrixX = minX - marginWidth;
				Logger.v(TAG, "[fixPosition]:fittingToLeft:x=%s", matrixX);
			}
			
			if (minY < 0 && maxY < getHeight()) {
				// 上側によっていて、下側があいている状況
				minY += getHeight() - maxY; // 下側に寄せる
				matrixY = minY - marginHeight;
				Logger.v(TAG, "[fixPosition]:fittingToBottom:y=%s", matrixY);
			} else if (minY > 0 && maxY > getHeight()) {
				// 下側ｊによっていて、上側があいている状況
				minY = 0; // 上側へ寄せる
				matrixY = minY - marginHeight;
				Logger.v(TAG, "[fixPosition]:fittingToTop:y=%s", matrixY);
			}
			
			// 座標が変更された場合
			if (matrixX != matrixValue[Matrix.MTRANS_X] || matrixY != matrixValue[Matrix.MTRANS_Y]) {
				matrixValue[Matrix.MTRANS_X] = matrixX;
				matrixValue[Matrix.MTRANS_Y] = matrixY;
				imgMatrix.setValues(matrixValue);
				invalidate();
				// 作業の座標をすべて調整する
				changeTaskChildView();
				Logger.v(TAG, "[fixPosition]invalidate");
			}
			Logger.v(TAG, "[fixPosition][after]x=%s, y=%s", matrixValue[Matrix.MTRANS_X], matrixValue[Matrix.MTRANS_Y]);
		}
		Logger.d(TAG, "[fixPosition]:[end]");
	}
	
	/**
	 * --------------------------------------------------------------------------
	 * メモ関連処理
	 * --------------------------------------------------------------------------
	 */
	
	public void addMemo() {
		// DBデータ取得
		List<ContentMemoDto> listMemo = contentMemoDao.getMemoList(mContentDto.contentId, mPageNumber);
		for (int i = 0; i < listMemo.size(); i++) {
			// アイコン追加
			ContentMemoDto dto = listMemo.get(i);
			Point point = convertToMemoViewPoint(dto.axisX, dto.axisY);
			dto.viewX = point.x;
			dto.viewY = point.y;
			MemoManager.addMemoIcon(this, dto);
		}
	}

	/**
	 * ドロップ＆ドラッグ・ダブルタップ時のx,y座標をPDFに合わせて変換
	 * @param x
	 * @param y
	 * @return
	 */
	public PointF convertToTapPoint(float x, float y) {
		float[] pdfMatrix = getMatrixValue(getPageView().imgMatrix);

		float scaleX = (float)mAuthoringPageSize.width / getScaledPDFWidth(pdfMatrix[Matrix.MSCALE_X]);
		float scaleY = (float)mAuthoringPageSize.height / getScaledPDFHeight(pdfMatrix[Matrix.MSCALE_Y]);
		float pdfX = (x - pdfMatrix[Matrix.MTRANS_X]) * scaleX;
		float pdfY = (y - pdfMatrix[Matrix.MTRANS_Y]) * scaleY;

		return new PointF(pdfX, pdfY);
	}

	/**
	 * 作業の位置調整
	 * @param x
	 * @param y
	 * @return
	 */
	public PointF convertToScalePoint(float x, float y) {
		float[] pdfMatrix = getMatrixValue(getPageView().imgMatrix);

		float scaleX = getScaledPDFWidth(pdfMatrix[Matrix.MSCALE_X]) / (float)mAuthoringPageSize.width;
		float scaleY = getScaledPDFHeight(pdfMatrix[Matrix.MSCALE_Y]) / (float)mAuthoringPageSize.height;
		float pdfX = (x * scaleX) + pdfMatrix[Matrix.MTRANS_X];
		float pdfY = (y * scaleY) + pdfMatrix[Matrix.MTRANS_Y];

		return new PointF(pdfX, pdfY);
	}

	/**
	 * 作業の生成時、座標をPDFサイズによる変換処理
	 * @param x
	 * @param y
	 * @return
	 */
	public PointF convertToViewPoint(float x, float y) {
		Logger.d(TAG, "convertToViewPoint:x=%s, y=%s", x, y);
		// 初期表示時、getPageView()がnullの場合があるので、初期情報を元にx, y座標を変換する
		if (getPageView() != null) {
			return convertToScalePoint(x, y);
		}
		// 初期表示の場合は、PDFPageビューが存在しないので、初期表示のみ以下の処理で行われる
		// オーサリング基準座標から変換PDF基準座標に変換
		float scaleX = getDefaultPDFWidth() / (float) mAuthoringPageSize.width;
		float scaleY = getDefaultPDFHeight() / (float) mAuthoringPageSize.height;

		// PDF座標からタッチ座標に変換
		float viewX = (x * scaleX) + margin.left;
		float viewY = (y * scaleY) + margin.top;
		Logger.d(TAG, "convertToViewPoint:marginX=%s, marginY=%s, mPdfScale=%s viewX=%s, viewY=%s", margin.left, margin.top, mPdfScale, viewX, viewY);
		return new PointF(viewX, viewY);
	}

	public Point convertToMemoViewPoint(float x, float y) {
		Logger.d(TAG, "convertToViewPoint:x=%s, y=%s", x, y);
		// オーサリング基準座標から変換PDF基準座標に変換
		float scale = Math.min(getDefaultPDFWidth() / (float)mAuthoringPageSize.width, getDefaultPDFHeight() / (float)mAuthoringPageSize.height);
		float pdfX = x * scale;
		float pdfY = y * scale;
		Logger.d(TAG, "convertToMemoViewPoint:scale=%s scaledWidth=%s, scaledHeight=%s pdfX=%s, pdfY=%s", scale, getDefaultPDFWidth(), getDefaultPDFHeight(), pdfX, pdfY);

		// PDF座標からタッチ座標に変換
		float viewX = pdfX + margin.left;
		float viewY = pdfY + margin.top;
		Logger.d(TAG, "convertToMemoViewPoint:marginX=%s, marginY=%s, mPdfScale=%s viewX=%s, viewY=%s", margin.left, margin.top, mPdfScale, viewX, viewY);
		Point point = new Point((int)viewX, (int)viewY);
		return point;
	}

	public Point convertToMemoAuthoringPoint(float x, float y) {
		Logger.d(TAG, "convertToMemoAuthoringPoint:x=%s, y=%s", x, y);
		// タッチ座標からPDF座標に変換
		mPdfScale = Math.min(getWidth() / (float)mPdfSize.width, getHeight() / (float)mPdfSize.height);
		float marginX = getMarginX(mPdfScale);
		float marginY = getMarginY(mPdfScale);
		float pdfX = x - marginX;
		float pdfY = y - marginY;
		Logger.d(TAG, "convertToMemoAuthoringPoint:marginX=%s, marginY=%s, mPdfScale=%s pdfX=%s, pdfY=%s", margin.left, margin.top, mPdfScale, pdfX, pdfY);

		// 変換PDF基準座標からオーサリング基準座標に変換
		float scale = Math.min((float)mAuthoringPageSize.width / getDefaultPDFWidth(), (float)mAuthoringPageSize.height / getDefaultPDFHeight());
		Point point = new Point((int)(pdfX * scale), (int)(pdfY * scale));
		Logger.d(TAG, "convertToScalePoint:scale=%s  scaledWidth=%s, scaledHeight=%s authX=%s, auyhY=%s", scale, getDefaultPDFWidth(), getDefaultPDFHeight(), (pdfX * scale), (pdfY * scale));
		return point;
	}

    public boolean isLeftSideOfPdf(int x) {
	    return x < mAuthoringPageSize.width / 2;
    }
	
	private void showMemoMenu(final float x, final float y) {
		final Point convertedPoint = convertToMemoAuthoringPoint(x, y);
		if (contentMemoDao.getCopiedMemo() != null) {
			// メモのコピーまたは切り取り中
			final ABVPopupListWindow memoPopupWindow = createSimplePopupWindow();
			memoPopupWindow.setWidth((int)getResources().getDimension(R.dimen.memo_popup_size_width));
			memoPopupWindow.setRepresentNames(new String[] { getContext().getResources().getString(R.string.new_memo),
					getContext().getResources().getString(R.string.paste_memo),
					getContext().getResources().getString(R.string.clear_memo)});
			memoPopupWindow.getListView().setOnItemClickListener(new OnItemClickListener() {

				@Override
				public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
					if (position == 0) {
						// 新規
						ContentMemoDto dto = new ContentMemoDto();
						dto.axisX = convertedPoint.x;
						dto.axisY = convertedPoint.y;
						dto.viewX = (int)x;
						dto.viewY = (int)y;
						dto.contentId = mContentDto.contentId;
						dto.pageNum = mPageNumber;
						
						MemoManager.showMemoDialog(ZoomRelativeLayout.this, dto);
					} else {
						ContentMemoDto dto = contentMemoDao.getCopiedMemo();
						if (position == 1) {
							// 貼り付け
							if (dto.delFlg) {
								// 切り取りの場合
								// 既存アイコンを削除する
								MemoManager.setIconStatus(ZoomRelativeLayout.this, dto.memoId, MemoManager.ICON_DELETE);
								contentMemoDao.deleteMemo(dto);
							}
							dto.contentId = mContentDto.contentId;
							dto.pageNum = mPageNumber;
							dto.axisX = convertedPoint.x;
							dto.axisY = convertedPoint.y;
							dto.viewX = (int)x;
							dto.viewY = (int)y;
							dto.copyFlg = false;
							dto.delFlg = false;
							dto.insertDate = DateTimeUtil.getCurrentUTCDate();
							dto.updateDate = DateTimeUtil.getCurrentUTCDate();
							
							memoLogic.insertContentMemo(dto);
							MemoManager.addMemoIcon(ZoomRelativeLayout.this, dto);
						} else {
							// クリアする
							if (dto.delFlg) {
								// 貼り付けの場合disableからenableに戻す
								MemoManager.setIconStatus(ZoomRelativeLayout.this, dto.memoId, MemoManager.ICON_ENABLE);
							}
							ClipboardUtil.setText(getContext(), "");
							contentMemoDao.clearCopiedMemo();
							
						}
					}
					memoPopupWindow.dismiss();
				}
			});
			
			// 端末の端っこを押した場合、表示位置をずらすための処理
			int popX = (int)x;
			int popY = (int)y;
			if (x > getDefaultPDFWidth() - 200) {
				popX -= 200;
			}
			if (y > getDefaultPDFHeight() - 250) {
				popY -= 250;
			}
			memoPopupWindow.showAtLocation(ZoomRelativeLayout.this, Gravity.NO_GRAVITY, popX, popY);
			
		} else {
			ContentMemoDto dto = new ContentMemoDto();
			dto.axisX = convertedPoint.x;
			dto.axisY = convertedPoint.y;
			dto.viewX = (int)x;
			dto.viewY = (int)y;
			dto.pageNum = mPageNumber;
			dto.contentId = mContentDto.contentId;
			MemoManager.showMemoDialog(ZoomRelativeLayout.this, dto);
		}										
	}
	
	private SimpleOnGestureListener mGestureListener = new SimpleOnGestureListener() {
		
		@Override
		public void onLongPress(MotionEvent e) {
			if (isOperationPdf) {
				return;
			}

			if (mContentDto != null) {
				if (mContentDto != null && mContentDto.isUnAuthorizedContent) {
					mListener.unAuthorizedContentNotification(getResources().getString(R.string.memo_unusable));
					return;
				}
				//jeonghun 앙케이트 모드일때 메모 안되게 제어
				boolean enqueteMode = ((ContentViewActivity)mContext).isEnqueteStatus();

				if (enqueteMode) {
					return;
				}
			}

			Logger.i(TAG, "[SimpleOnGestureListener]:[onLongPress]");

			//if (!mScaleDetector.isInProgress() && pageScrollView.isScrollable()) {
			//스크롤 픽스 상태였을 경우 메모 추가가 안 되어서 
			if (!mScaleDetector.isInProgress() && mPageScrollView.isMemocheck()) {
				
				// MemoAction
				for (int i = 0; i < getChildCount(); i++) {
					View child = getChildAt(i);
					if (child instanceof Action3DImageView) {
						Action3DImageView a3dv = (Action3DImageView)child;
						if (a3dv.getEventFlg() == true) {
							// 3Dモードの場合は長押しメモ処理を行わない
							return;
						}
					}
		    	}
				
				// PDF画面外側をタッチしているかチェック
				mPdfScale = Math.min(getWidth() / (float)mPdfSize.width, getHeight() / (float)mPdfSize.height);
				float marginX = getMarginX(mPdfScale);
				float marginY = getMarginY(mPdfScale);
				final float x = e.getX();
				final float y = e.getY();
				if (x < marginX || x > marginX + getDefaultPDFWidth() || 
						y < marginY || y > marginY + getDefaultPDFHeight()) {
					return;
				}
				if (mContentDto != null) {
					showMemoMenu(x, y);
				}
			}
			
			super.onLongPress(e);
		}
	};
	
	public void setDefaultScale() {
		Logger.v(TAG, "[setDefaultScale]");
		mPageScrollView.setZoomingFlag(false);
		mPageScrollView.requestDisallowInterceptTouchEvent(false);
		
		imgMatrix.set(initMatrix);
		mScaleFactor = 1.0f;
		if (mContext instanceof ContentViewActivity) {
			((ContentViewActivity)mContext).setDefaultVideo();
			((ContentViewActivity)mContext).resetScrollStatus();
		} else {
			((GuideViewActivity)mContext).setDefaultVideo();
			((GuideViewActivity)mContext).resetScrollStatus();
		}

	}
	
	private OnDoubleTapListener mDoubleTapListener = new OnDoubleTapListener() {
		
		@Override
		public boolean onSingleTapConfirmed(MotionEvent e) {
			Logger.v(TAG, "[OnDoubleTapListener]:[onSingleTapConfirmed]");
			if (mContext instanceof ContentViewActivity) {
				((ContentViewActivity) mContext).singleTapMotion();
			} else {
				((GuideViewActivity) mContext).singleTapMotion();
			}
			return false;
		}
		
		@Override
		public boolean onDoubleTapEvent(MotionEvent e) {
			Logger.v(TAG, "[OnDoubleTapListener]:[onDoubleTapEvent]");
			return true;
		}
		
		@Override
		public boolean onDoubleTap(MotionEvent e) {
			if (mContext instanceof ContentViewActivity) {
				((ContentViewActivity) mContext).setToolbarVisable(false);
			} else {
				((GuideViewActivity) mContext).setToolbarVisable(false);
			}
			// 通常、1回のみの処理であればこのメソッドで実装する
			Logger.v(TAG, "[OnDoubleTapListener]:[onDoubleTap]");

			if (isOperationPdf && mContext instanceof ContentViewActivity) {
				if(((ContentViewActivity) mContext).getOpenedProjestTask() || !((ContentViewActivity) mContext).isReportEdit() || ((ContentViewActivity) mContext).mMoveTaskFlg) {
			        return true;
                }

                final float x = e.getX();
                final float y = e.getY();

				float[] pdfMatrix = getMatrixValue(getPageView().imgMatrix);
				float scaledWidth = getScaledPDFWidth(pdfMatrix[Matrix.MSCALE_X]);
				float scaledHeight = getScaledPDFHeight(pdfMatrix[Matrix.MSCALE_Y]);
				float pdfX = pdfMatrix[Matrix.MTRANS_X];
				float pdfY = pdfMatrix[Matrix.MTRANS_Y];

				// ダブルタップがPDF表示の横領域を超えた場合は、以下の処理を行わない
				if ((x - pdfX) < 0 || ((pdfX + scaledWidth) - x) < 0) {
					return true;
				}

				// ダブルタップがPDF表示の縦領域を超えた場合は、以下の処理を行わない
				if ((y - pdfY) < 0 || ((pdfY + scaledHeight) - y) < 0) {
					return true;
				}

				// タップしたx, yをPDF用の座標に変換
                PointF pointPdf = convertToTapPoint(x, y);

                OperationTaskDto dto = new OperationTaskDto();
                dto.operationId = ((ContentViewActivity) mContext).getOperationId();
                dto.taskKey = OperationTaskLayout.getTempTaskKey();
                dto.pdfX = pointPdf.x;
                dto.pdfY = pointPdf.y;
                dto.pageNum = mPageNumber;
                // 作業登録画面の表示
                ((ContentViewActivity) mContext).showOperationTaskLayout(ZoomRelativeLayout.this, dto, x);
            } else {
                float[] matrixValue = getMatrixValue(imgMatrix);
                float nowScale = matrixValue[Matrix.MSCALE_X];
                float nextMatrixScale;
                if (nowScale < IFPDFConst.MAX_SCALE / 1.5f) { // MAX_SCALEの3分の２以下の場合
                    nextMatrixScale = IFPDFConst.MAX_SCALE / 1.5f / nowScale;
                } else {
                    if (nowScale == IFPDFConst.MAX_SCALE) {
                        nextMatrixScale = 1.5f;// ただMax値を超える値にさせるため
                    } else {
                        nextMatrixScale = IFPDFConst.MAX_SCALE / nowScale;
                    }
                }

                Matrix checkMatrix = new Matrix(imgMatrix);
                checkMatrix.postScale(nextMatrixScale, nextMatrixScale, e.getX(), e.getY());
                matrixValue = getMatrixValue(checkMatrix);
                float matrixScale = matrixValue[Matrix.MSCALE_X];
                Logger.d(TAG, "perscale=" + matrixValue[Matrix.MSCALE_X] + ", nextscale=" + nextMatrixScale + ", matrixScale=" + matrixScale);
                if (matrixScale > IFPDFConst.MAX_SCALE) {
                    // 拡大の設定解除
                    setDefaultScale();
                } else {
                    // 拡大の設定
                    mPdfScale = Math.min(getWidth() / (float) mPdfSize.width, getHeight() / (float) mPdfSize.height);
                    mPageScrollView.setZoomingFlag(true);
                    mPageScrollView.requestDisallowInterceptTouchEvent(true);
                    if (mContext instanceof ContentViewActivity) {
                        ((ContentViewActivity) mContext).stopVideo();
                    } else {
                        ((GuideViewActivity) mContext).stopVideo();
                    }
                    imgMatrix.set(checkMatrix);
                    mScaleFactor = matrixScale;
                }
            }
			invalidate();
			return true;
		}
	};

	public boolean isZooming() {
		return mScaleFactor > 1.0f;
	}
	
	public float getScaleFactor() {
		return mScaleFactor;
	}

    public void setScaleFactor(float scaleFactor) {
        mScaleFactor = scaleFactor;
    }

    public void setScaleFactorAndMatrix(float scaleFactor) {
        setScaleFactor(scaleFactor);

        if (scaleFactor == 1.0f) {
            mPageScrollView.setZoomingFlag(false);
            imgMatrix.set(initMatrix);
        }
    }
	
	public void setZoomMatrix(Matrix matrix) {
		getPageView().setZoomMatrix(matrix);
		
		float[] m = getMatrixValue(matrix);
		float scale = m[Matrix.MSCALE_X];
		float scaledWidth = getScaledPDFWidth(scale);
		float scaledHeight = getScaledPDFHeight(scale);
		Logger.v(TAG, "setZoomMatrix:width=%s, scaledWidth=%s", getWidth(), scaledWidth);
		Logger.v(TAG, "setZoomMatrix=before:x:%s,y:%s,scale=%s", m[Matrix.MTRANS_X], m[Matrix.MTRANS_Y], m[Matrix.MSCALE_X]);
		m[Matrix.MTRANS_X] = m[Matrix.MTRANS_X] - (getWidth() * scale - scaledWidth) / 2;
		m[Matrix.MTRANS_Y] = m[Matrix.MTRANS_Y] - (getHeight() * scale - scaledHeight) / 2;
		this.imgMatrix.setValues(m);
        Logger.v(TAG, "setZoomMatrix=after:x:%s,y:%s,scale=%s", m[Matrix.MTRANS_X], m[Matrix.MTRANS_Y], m[Matrix.MSCALE_X]);
		fixPosition();
		invalidate();
	}
	
	public ABVPopupListWindow createSimplePopupWindow() {
		if (mShowedPopupWindow != null && mShowedPopupWindow.isShowing()) {
			mShowedPopupWindow.dismiss();
		}
		mShowedPopupWindow = new ABVPopupListWindow(this.getContext());
		Logger.d(TAG, "createSimplePopupWindow");
		return mShowedPopupWindow;
	}
	
	public static class ViewMargin {
		public int left;
		public int top;
		public int right;
		public int bottom;
		public String toString() {
			return "left=" + left + ", top=" + top + ", right=" + right + ", bottom=" + bottom;
			
		}
	}
}
