
package com.github.andlyticsproject.view;

import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Animation.AnimationListener;

/**
 * This code was extracted from the Transition3D sample activity found in the Android ApiDemos. The
 * animation is made of two smaller animations: the first half rotates the list by 90 degrees on the
 * Y axis and the second half rotates the picture by 90 degrees on the Y axis. When the first half
 * finishes, the list is made invisible and the picture is set visible.
 */
public class ViewSwitcher3D {
	private static final String TAG = "ViewSwitcher";
	private ViewGroup mContainer;
	private View mFrondside;
	private View mBackside;

	private long mDuration = 600;
	private float mDepthOfRotation = 300f;

	private ViewSwitcherListener listener;

	public ViewSwitcher3D(ViewGroup container) {

		mContainer = container;
		mFrondside = container.getChildAt(0);
		mBackside = container.getChildAt(1);

		// Since we are caching large views, we want to keep their cache
		// between each animation
		mContainer.setPersistentDrawingCache(ViewGroup.PERSISTENT_ANIMATION_CACHE);

	}

	public void setDuration(long duration) {
		mDuration = duration;
	}

	public void swap() {
		float start, end;

		if (isFrontsideVisible()) {
			Log.v(TAG, "turning to the backside!");
			start = 0;
			end = 90;
		} else {
			Log.v(TAG, "turning to the frontside!");
			start = 180;
			end = 90;
		}

		Rotate3dAnimation rotation = new Rotate3dAnimation(start, end,
				mContainer.getWidth() / 2.0f, mContainer.getHeight() / 2.0f, mDepthOfRotation,
				true, getListener());
		rotation.setDuration(mDuration / 2);
		rotation.setFillAfter(true);
		rotation.setInterpolator(new AccelerateInterpolator());
		rotation.setAnimationListener(new TurnAroundListener());

		mContainer.startAnimation(rotation);
	}

	public boolean isFrontsideVisible() {
		return mFrondside.getVisibility() == View.VISIBLE;
	}

	public boolean isBacksideVisible() {
		return mBackside.getVisibility() == View.VISIBLE;
	}

	/**
	 * Listen for the end of the first half of the animation. Then post a new action that
	 * effectively swaps the views when the container is rotated 90 degrees and thus invisible.
	 */
	private final class TurnAroundListener implements Animation.AnimationListener {

		public void onAnimationStart(Animation animation) {
		}

		public void onAnimationEnd(Animation animation) {
			mContainer.post(new SwapViews());
		}

		public void onAnimationRepeat(Animation animation) {
		}
	}

	/**
	 * Swapping the views and start the second half of the animation.
	 */
	private final class SwapViews implements Runnable {

		public void run() {
			final float centerX = mContainer.getWidth() / 2.0f;
			final float centerY = mContainer.getHeight() / 2.0f;
			Rotate3dAnimation rotation;

			if (isFrontsideVisible()) {
				mFrondside.setVisibility(View.GONE);
				mBackside.setVisibility(View.VISIBLE);
				unmirrorTheBackside();
				mBackside.requestFocus();

				rotation = new Rotate3dAnimation(90, 180, centerX, centerY, mDepthOfRotation,
						false, getListener());
			} else {
				mBackside.setVisibility(View.GONE);
				mBackside.clearAnimation(); // remove the mirroring
				mFrondside.setVisibility(View.VISIBLE);
				mFrondside.requestFocus();

				rotation = new Rotate3dAnimation(90, 0, centerX, centerY, mDepthOfRotation, false,
						getListener());
			}

			rotation.setDuration(mDuration / 2);
			rotation.setFillAfter(true);
			rotation.setInterpolator(new DecelerateInterpolator());
			rotation.setAnimationListener(new AnimationListener() {

				@Override
				public void onAnimationStart(Animation animation) {
				}

				@Override
				public void onAnimationRepeat(Animation animation) {
				}

				@Override
				public void onAnimationEnd(Animation animation) {
					if (listener != null) {
						listener.onViewChanged(isFrontsideVisible());
					}
				}
			});

			mContainer.startAnimation(rotation);

		}
	}

	private void unmirrorTheBackside() {
		Rotate3dAnimation rotation = new Rotate3dAnimation(0, 180, mContainer.getWidth() / 2.0f,
				mContainer.getHeight() / 2.0f, mDepthOfRotation, false, getListener());
		rotation.setDuration(0);
		rotation.setFillAfter(true);
		mBackside.startAnimation(rotation);
	}

	public void setListener(ViewSwitcherListener listener) {
		this.listener = listener;
	}

	public ViewSwitcherListener getListener() {
		return listener;
	}

	public interface ViewSwitcherListener {
		public void onViewChanged(boolean frontsideVisible);

		public void onRender();
	}
}
