/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * 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.
 */

package com.example.android.toongame;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RelativeLayout;

/**
 * This activity, launched from the ToonGame activity, takes the user between three
 * different setup screens where they choose a name, choose a difficulty rating, and
 * enter important financial information. All of the screens are meant to be
 * simple, engaging, and fun.
 */
public class PlayerSetupActivity extends Activity {

    private static final AccelerateInterpolator sAccelerator = new AccelerateInterpolator();
    private static final LinearInterpolator sLinearInterpolator = new LinearInterpolator();
    ViewGroup mContainer;
    EditText mEditText;
    
    private static final int NAME_STATE = 0;
    private static final int DIFFICULTY_STATE = 1;
    private static final int CREDIT_STATE = 2;
    private int mEntryState = NAME_STATE;

    SkewableTextView mNameTV, mDifficultyTV, mCreditTV;
    
    ViewGroup mNameButtons, mDifficultyButtons, mCreditButtons1, mCreditButtons2;
    
    Button mBobButton, mJaneButton, mPatButton;
    
    private static final TimeInterpolator sOvershooter = new OvershootInterpolator();
    private static final DecelerateInterpolator sDecelerator = new DecelerateInterpolator();
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.player_setup_layout);
        overridePendingTransition(0, 0);
        
        mContainer = (ViewGroup) findViewById(R.id.container);
        mContainer.getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
        
        mNameTV = (SkewableTextView) findViewById(R.id.nameTV);
        mDifficultyTV = (SkewableTextView) findViewById(R.id.ageTV);
        mCreditTV = (SkewableTextView) findViewById(R.id.creditTV);
        
        mBobButton = setupButton(R.id.bobButton);
        setupButton(R.id.janeButton);
        setupButton(R.id.patButton);
        setupButton(R.id.easyButton);
        setupButton(R.id.hardButton);
        setupButton(R.id.megaHardButton);
        
        mNameButtons = (ViewGroup) findViewById(R.id.nameButtons);
        mDifficultyButtons = (ViewGroup) findViewById(R.id.difficultyButtons);
        mCreditButtons1 = (ViewGroup) findViewById(R.id.creditButtons1);
        mCreditButtons2 = (ViewGroup) findViewById(R.id.creditButtons2);
    }
    
    @Override
    public void finish() {
        super.finish();
        overridePendingTransition(0, 0);
    }

    private Button setupButton(int resourceId) {
        Button button = (Button) findViewById(resourceId);
        button.setOnTouchListener(mButtonPressListener);
        return button;
    }
    
    private View.OnTouchListener mButtonPressListener =
            new View.OnTouchListener() {
                public boolean onTouch(View v, MotionEvent event) {
                    switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        v.animate().setDuration(ToonGame.SHORT_DURATION).
                                scaleX(.8f).scaleY(.8f).setInterpolator(sDecelerator);
                        break;
                    case MotionEvent.ACTION_UP:
                        v.animate().setDuration(ToonGame.SHORT_DURATION).
                                scaleX(1).scaleY(1).setInterpolator(sAccelerator);
                        break;
                    default:
                        break;
                    }
                    return false;
                }
            };

    public void buttonClick(View clickedView, int alignmentRule) {
        ViewGroup parent = (ViewGroup) clickedView.getParent();
        for (int i = 0; i < parent.getChildCount(); ++i) {
            Button child = (Button) parent.getChildAt(i);
            if (child != clickedView) {
                child.animate().alpha(0);
            } else {
                final Button buttonCopy = new Button(this);
                child.setVisibility(View.INVISIBLE);
                buttonCopy.setBackground(child.getBackground());
                buttonCopy.setText(((Button) child).getText());
                RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
                        RelativeLayout.LayoutParams.WRAP_CONTENT,
                        RelativeLayout.LayoutParams.WRAP_CONTENT);
                params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
                params.addRule(alignmentRule);
                params.setMargins(25, 50, 25, 50);
                buttonCopy.setLayoutParams(params);
                buttonCopy.setPadding(child.getPaddingLeft(), child.getPaddingTop(),
                        child.getPaddingRight(), child.getPaddingBottom());
                buttonCopy.setTextSize(TypedValue.COMPLEX_UNIT_PX, child.getTextSize());
                buttonCopy.setTypeface(child.getTypeface(), Typeface.BOLD);
                ColorStateList colors = child.getTextColors();
                buttonCopy.setTextColor(colors.getDefaultColor());
                final int[] oldLocationInWindow = new int[2];
                child.getLocationInWindow(oldLocationInWindow);
                mContainer.addView(buttonCopy);
                buttonCopy.getViewTreeObserver().addOnPreDrawListener(
                        new ViewTreeObserver.OnPreDrawListener() {
                    
                    @Override
                    public boolean onPreDraw() {
                        buttonCopy.getViewTreeObserver().removeOnPreDrawListener(this);
                        int[] locationInWindow = new int[2];
                        buttonCopy.getLocationInWindow(locationInWindow);
                        float deltaX = oldLocationInWindow[0] - locationInWindow[0];
                        float deltaY = oldLocationInWindow[1] - locationInWindow[1];
    
                        buttonCopy.setTranslationX(deltaX);
                        buttonCopy.setTranslationY(deltaY);
                        
                        PropertyValuesHolder pvhSX =
                                PropertyValuesHolder.ofFloat(View.SCALE_X, 3);
                        PropertyValuesHolder pvhSY =
                                PropertyValuesHolder.ofFloat(View.SCALE_Y, 3);
                        ObjectAnimator bounceAnim = ObjectAnimator.ofPropertyValuesHolder(
                                buttonCopy, pvhSX, pvhSY);
                        bounceAnim.setRepeatCount(1);
                        bounceAnim.setRepeatMode(ValueAnimator.REVERSE);
                        bounceAnim.setInterpolator(sDecelerator);
                        bounceAnim.setDuration(300);
                        
                        PropertyValuesHolder pvhTX =
                                PropertyValuesHolder.ofFloat(View.TRANSLATION_X, 0);
                        PropertyValuesHolder pvhTY =
                                PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 0);
                        ObjectAnimator moveAnim = ObjectAnimator.ofPropertyValuesHolder(
                                buttonCopy, pvhTX, pvhTY);
                        moveAnim.setDuration(600);
                        bounceAnim.start();
                        moveAnim.start();
                        moveAnim.addListener(new AnimatorListenerAdapter() {
                            public void onAnimationEnd(Animator animation) {
                                switch (mEntryState) {
                                case (NAME_STATE) :
                                {
                                    Runnable runnable = new Runnable() {
                                        public void run() {
                                            mDifficultyButtons.setVisibility(View.VISIBLE);
                                            mNameButtons.setVisibility(View.GONE);
                                            popChildrenIn(mDifficultyButtons, null);
                                        }
                                    };
                                    slideToNext(mNameTV, mDifficultyTV, runnable);
                                    mEntryState = DIFFICULTY_STATE;
                                    break;
                                }
                                case (DIFFICULTY_STATE) :
                                {
                                    mDifficultyButtons.setVisibility(View.GONE);
                                    for (int i = 0; i < 5; ++i) {
                                        mCreditButtons1.addView(setupNumberButton(i));
                                    }
                                    for (int i = 5; i < 10; ++i) {
                                        mCreditButtons2.addView(setupNumberButton(i));
                                    }
                                    Runnable runnable = new Runnable() {
                                        public void run() {
                                            mCreditButtons1.setVisibility(View.VISIBLE);
                                            Runnable runnable = new Runnable() {
                                                public void run() {
                                                    mCreditButtons2.setVisibility(View.VISIBLE);
                                                    popChildrenIn(mCreditButtons2, null);
                                                }
                                            };
                                            popChildrenIn(mCreditButtons1, runnable);
                                        }
                                    };
                                    slideToNext(mDifficultyTV, mCreditTV, runnable);
                                    mEntryState = CREDIT_STATE;
                                }
                                    break;
                                }
                            }
                        });
                        return true;
                    }
                });
            }
        }
    }
    
    public void selectDifficulty(View clickedView) {
        buttonClick(clickedView, RelativeLayout.ALIGN_PARENT_RIGHT);
    }
    
    public void selectName(View clickedView) {
        buttonClick(clickedView, RelativeLayout.ALIGN_PARENT_LEFT);
    }
    
    private Button setupNumberButton(int number) {
        Button button = new Button(PlayerSetupActivity.this);
        button.setTextSize(15);
        button.setTextColor(Color.WHITE);
        button.setTypeface(mBobButton.getTypeface(), Typeface.BOLD);
        button.setText(Integer.toString(number));
        button.setPadding(0, 0, 0, 0);
        
        OvalShape oval = new OvalShape();
        ShapeDrawable drawable = new ShapeDrawable(oval);
        drawable.getPaint().setColor(0xFF << 24 | (int) (50 + 150 * Math.random()) << 16 |
                (int) (50 + 150 * Math.random()) << 8 |  (int) (50 + 150 * Math.random()));
        button.setBackground(drawable);

        button.setOnTouchListener(mButtonPressListener);

        return button;
    }

    ViewTreeObserver.OnPreDrawListener mPreDrawListener =
            new ViewTreeObserver.OnPreDrawListener() {
        
        @Override
        public boolean onPreDraw() {
            mContainer.getViewTreeObserver().removeOnPreDrawListener(this);
            mContainer.setScaleX(0);
            mContainer.setScaleY(0);
            mContainer.animate().scaleX(1).scaleY(1).setInterpolator(new OvershootInterpolator());
            mContainer.animate().setDuration(ToonGame.LONG_DURATION).withEndAction(new Runnable() {
                
                @Override
                public void run() {
                    ViewGroup buttonsParent = (ViewGroup) findViewById(R.id.nameButtons);
                    buttonsParent.setVisibility(View.VISIBLE);
                    popChildrenIn(buttonsParent, null);
                }
            });
            return false;
        }
    };
    
    private void popChildrenIn(ViewGroup parent, final Runnable endAction) {
        // for all children, scale in one at a time
        TimeInterpolator overshooter = new OvershootInterpolator();
        int childCount = parent.getChildCount();
        ObjectAnimator[] childAnims = new ObjectAnimator[childCount];
        for (int i = 0; i < childCount; ++i) {
            View child = parent.getChildAt(i);
            child.setScaleX(0);
            child.setScaleY(0);
            PropertyValuesHolder pvhSX = PropertyValuesHolder.ofFloat(View.SCALE_X, 1);
            PropertyValuesHolder pvhSY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1);
            ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(child, pvhSX, pvhSY);
            anim.setDuration(150);
            anim.setInterpolator(overshooter);
            childAnims[i] = anim;
        }
        AnimatorSet set = new AnimatorSet();
        set.playSequentially(childAnims);
        set.start();
        if (endAction != null) {
            set.addListener(new AnimatorListenerAdapter() {
                public void onAnimationEnd(Animator animation) {
                    endAction.run();
                }
            });
        }
    }
    
    private void slideToNext(final SkewableTextView currentView,
            final SkewableTextView nextView, final Runnable endAction) {
        // skew/anticipate current view, slide off, set GONE, restore translation
        ObjectAnimator currentSkewer = ObjectAnimator.ofFloat(currentView, "skewX", -.5f);
        currentSkewer.setInterpolator(sDecelerator);
        ObjectAnimator currentMover = ObjectAnimator.ofFloat(currentView, View.TRANSLATION_X,
                -mContainer.getWidth());
        currentMover.setInterpolator(sLinearInterpolator);
        currentMover.setDuration(ToonGame.MEDIUM_DURATION);
        
        // set next view visible, translate off to right, skew,
        // slide on in parallel, overshoot/wobble, unskew
        nextView.setVisibility(View.VISIBLE);
        nextView.setSkewX(-.5f);
        nextView.setTranslationX(mContainer.getWidth());
        
        ObjectAnimator nextMover = ObjectAnimator.ofFloat(nextView, View.TRANSLATION_X, 0);
        nextMover.setInterpolator(sAccelerator);
        nextMover.setDuration(ToonGame.MEDIUM_DURATION);
        ObjectAnimator nextSkewer = ObjectAnimator.ofFloat(nextView, "skewX", 0);
        nextSkewer.setInterpolator(sOvershooter);
        
        AnimatorSet moverSet = new AnimatorSet();
        moverSet.playTogether(currentMover, nextMover);
        AnimatorSet fullSet = new AnimatorSet();
        fullSet.playSequentially(currentSkewer, moverSet, nextSkewer);
        fullSet.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                currentView.setSkewX(0);
                currentView.setVisibility(View.GONE);
                currentView.setTranslationX(0);
                if (endAction != null) {
                    endAction.run();
                }
            }
        });
        
        fullSet.start();
    }

}