package com.netease.nim.uikit.common.ui.imageview;

/*
 * Copyright 2012 Laurence Dawson
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * This class is based upon the file ImageViewTouchBase.java which can be found at:
 * https://dl-ssl.google.com/dl/googlesource/git-repo/repo
 *  
 * Copyright (C) 2009 The Android Open Source Project
 */

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;

public class MultiTouchZoomableImageView extends BaseZoomableImageView {
    // Scale and gesture listeners for the view
    private GestureDetector mGestureDetector;
    private ScaleGestureDetector mScaleDetector;
    protected boolean transIgnoreScale = false;
    private boolean scaleRecognized = false;

    // Programatic entry point
    public MultiTouchZoomableImageView(Context context) {
        super(context);
        initMultiTouchZoomableImageView(context);
    }

    // XML entry point
    public MultiTouchZoomableImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initMultiTouchZoomableImageView(context);
    }

    // Setup the view
    protected void initMultiTouchZoomableImageView(Context context) {
        // Setup the gesture and scale listeners
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
        mGestureDetector = new GestureDetector(context, new MyGestureListener());
    }


    // Adjusts the zoom of the view
    class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            // Check if the detector is in progress in order to proceed
            if (detector != null && detector.isInProgress()) {
                try {
                    // Grab the scale
                    float targetScale = getScale() * detector.getScaleFactor();
                    // Correct for the min scale
                    targetScale = Math.min(maxZoom(), Math.max(targetScale, 1.0f));

                    // Zoom and invalidate the view
                    zoomTo(targetScale, detector.getFocusX(), detector.getFocusY());
                    invalidate();

                    scaleRecognized = true;

                    return true;
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                }
            }
            return false;
        }
    }

    // Handles taps and scrolls of the view
    private class MyGestureListener extends GestureDetector.SimpleOnGestureListener {

        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            if (mImageGestureListener != null) {
                mImageGestureListener.onImageGestureSingleTapConfirmed();
                return false;
            }

            return super.onSingleTapConfirmed(e);
        }

        public void onLongPress(MotionEvent e) {
            if (mImageGestureListener != null && !scaleRecognized) {
                mImageGestureListener.onImageGestureLongPress();
            }
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            try {
                // Skip if there are multiple points of contact
                if ((e1 != null && e1.getPointerCount() > 1) || (e2 != null && e2.getPointerCount() > 1) || (mScaleDetector != null && mScaleDetector.isInProgress()))
                    return false;

                // Scroll the bitmap
                if (transIgnoreScale || getScale() > zoomDefault()) {
                    stopFling();
                    postTranslate(-distanceX, -distanceY);

                    if (isScrollOver(distanceX)) {
                        if (mViewPager != null) {
                            mViewPager.requestDisallowInterceptTouchEvent(false);
                        }
                    } else {
                        if (mViewPager != null) {
                            mViewPager.requestDisallowInterceptTouchEvent(true);
                        }
                    }

                    center(true, true, false);
                } else {
                    if (mViewPager != null) {
                        mViewPager.requestDisallowInterceptTouchEvent(false);
                    }
                }
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            }

            // Default case
            return true;
        }

        @Override
        public boolean onDoubleTap(MotionEvent e) {
            // If the zoom is over 1x, reset to 1x
            if (getScale() != zoomDefault()) {
                zoomTo(zoomDefault());
            }
            // If the zoom is default, zoom into 2x
            else
                zoomTo(zoomDefault() * 3, e.getX(), e.getY(), 200);

            // Always true as double tap was performed
            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            if ((e1 != null && e1.getPointerCount() > 1) || (e2 != null && e2.getPointerCount() > 1))
                return false;
            if (mScaleDetector.isInProgress()) return false;

            final float FLING_MIN_DISTANCE = 100;
            final float FLING_MIN_VELOCITY = 200;
            if (e1.getX() - e2.getX() > FLING_MIN_DISTANCE
                    && Math.abs(velocityX) > FLING_MIN_VELOCITY) {
                Log.i("MultiTouchZoomableImageView", "Fling Left");
            } else if (e2.getX() - e1.getX() > FLING_MIN_DISTANCE
                    && Math.abs(velocityX) > FLING_MIN_VELOCITY) {
                Log.i("MultiTouchZoomableImageView", "Fling Right");
            } else if (e1.getY() - e2.getY() > FLING_MIN_DISTANCE
                    && Math.abs(velocityY) > FLING_MIN_VELOCITY) {
                Log.i("MultiTouchZoomableImageView", "Fling Up");
            } else if (e2.getY() - e1.getY() > FLING_MIN_DISTANCE
                    && Math.abs(velocityY) > FLING_MIN_VELOCITY) {
                Log.i("MultiTouchZoomableImageView", "Fling Down");

                if (!transIgnoreScale && getScale() <= zoomDefault()) {
                    mImageGestureListener.onImageGestureFlingDown();
                    return true;
                }
            }

            try {
                float diffX = e2.getX() - e1.getX();
                float diffY = e2.getY() - e1.getY();

                if (Math.abs(velocityX) > 800 || Math.abs(velocityY) > 800) {
                    scrollBy(diffX / 2, diffY / 2, 300);
                    invalidate();
                }
            } catch (NullPointerException e) {

            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            }

            return super.onFling(e1, e2, velocityX, velocityY);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        try {
            if (mViewPager != null) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_MOVE:
                        mViewPager.requestDisallowInterceptTouchEvent(true);
                        break;
                    case MotionEvent.ACTION_UP:
                    case MotionEvent.ACTION_CANCEL:
                        mViewPager.requestDisallowInterceptTouchEvent(false);
                        scaleRecognized = false;
                        break;
                }
            }

            // If the bitmap was set, check the scale and gesture detectors
            if (mBitmap != null) {
                // Check the scale detector
                mScaleDetector.onTouchEvent(event);

                // Check the gesture detector
                if (!mScaleDetector.isInProgress())
                    mGestureDetector.onTouchEvent(event);
            } else {
                mImageGestureListener.onImageGestureSingleTapConfirmed();
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return true;
    }
}
