// Path: flow/src/main/java/flow/Dispatcher.java
// public interface Dispatcher {
//   /**
//    * Called when the history is about to change.  Note that Flow does not consider the
//    * Traversal to be finished, and will not actually update the history, until the callback is
//    * triggered. Traversals cannot be canceled.
//    *
//    * @param callback Must be called to indicate completion of the traversal.
//    */
//   void dispatch(@NonNull Traversal traversal, @NonNull TraversalCallback callback);
// }
// 
// Path: app/src/main/java/leonardo2204/com/br/flowtests/flow/FlowUtils.java
// public final class FlowUtils {
// 
//     public interface OnMeasuredCallback {
//         void onMeasured(View view, int width, int height);
//     }
// 
//     public static void waitForMeasure(final View view, final OnMeasuredCallback callback) {
//         int width = view.getWidth();
//         int height = view.getHeight();
// 
//         if (width > 0 && height > 0) {
//             callback.onMeasured(view, width, height);
//             return;
//         }
// 
//         view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
//             @Override
//             public boolean onPreDraw() {
//                 final ViewTreeObserver observer = view.getViewTreeObserver();
//                 if (observer.isAlive()) {
//                     observer.removeOnPreDrawListener(this);
//                 }
// 
//                 callback.onMeasured(view, view.getWidth(), view.getHeight());
// 
//                 return true;
//             }
//         });
//     }
// 
//     private FlowUtils() {
//     }
// }
// 
// Path: app/src/main/java/leonardo2204/com/br/flowtests/screen/BaseScreen.java
// public abstract class BaseScreen extends ClassKey implements InjectionComponent {
// 
//     public abstract
//     @LayoutRes
//     int layoutResId();
// }


import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.support.annotation.LayoutRes;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.Locale;
import flow.Direction;
import flow.Dispatcher;
import flow.Traversal;
import flow.TraversalCallback;
import leonardo2204.com.br.flowtests.R;
import leonardo2204.com.br.flowtests.flow.FlowUtils;
import leonardo2204.com.br.flowtests.screen.BaseScreen;
package leonardo2204.com.br.flowtests.flow.dispatcher;




/**
 * Created by Leonardo on 04/03/2016.
 */
public final class BasicDispatcher implements Dispatcher {

    //private static Map<Class,Integer> LAYOUT_CACHE = new LinkedHashMap<>();
    private final Activity activity;

    public BasicDispatcher(Activity activity) {
        this.activity = activity;
    }

    @Override
    public void dispatch(final Traversal traversal, final TraversalCallback callback) {
        Object dest = traversal.destination.top();

        final ViewGroup frame = (ViewGroup) activity.findViewById(R.id.content);

        View fromView = null;
        if(traversal.origin != null){
            if(frame.getChildCount() > 0){
                fromView = frame.getChildAt(0);
                traversal.getState(traversal.origin.top()).save(frame.getChildAt(0));
            }
        }

        if (!(dest instanceof BaseScreen))
            throw new IllegalStateException(String.format(Locale.getDefault(), "The screen %s must implement BaseScreen", dest.getClass().getName()));

        @LayoutRes final int layout = ((BaseScreen) dest).layoutResId();

        final View incomingView = LayoutInflater.from(traversal.createContext(dest,activity)).inflate(layout,frame,false);

        traversal.getState(traversal.destination.top()).restore(incomingView);

        if(fromView == null || traversal.direction == Direction.REPLACE) {
            frame.removeAllViews();
            frame.addView(incomingView);
            callback.onTraversalCompleted();
        }else{
            frame.addView(incomingView);
            final View fromViewFinal = fromView;
// Path: flow/src/main/java/flow/Dispatcher.java
// public interface Dispatcher {
//   /**
//    * Called when the history is about to change.  Note that Flow does not consider the
//    * Traversal to be finished, and will not actually update the history, until the callback is
//    * triggered. Traversals cannot be canceled.
//    *
//    * @param callback Must be called to indicate completion of the traversal.
//    */
//   void dispatch(@NonNull Traversal traversal, @NonNull TraversalCallback callback);
// }
// 
// Path: app/src/main/java/leonardo2204/com/br/flowtests/flow/FlowUtils.java
// public final class FlowUtils {
// 
//     public interface OnMeasuredCallback {
//         void onMeasured(View view, int width, int height);
//     }
// 
//     public static void waitForMeasure(final View view, final OnMeasuredCallback callback) {
//         int width = view.getWidth();
//         int height = view.getHeight();
// 
//         if (width > 0 && height > 0) {
//             callback.onMeasured(view, width, height);
//             return;
//         }
// 
//         view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
//             @Override
//             public boolean onPreDraw() {
//                 final ViewTreeObserver observer = view.getViewTreeObserver();
//                 if (observer.isAlive()) {
//                     observer.removeOnPreDrawListener(this);
//                 }
// 
//                 callback.onMeasured(view, view.getWidth(), view.getHeight());
// 
//                 return true;
//             }
//         });
//     }
// 
//     private FlowUtils() {
//     }
// }
// 
// Path: app/src/main/java/leonardo2204/com/br/flowtests/screen/BaseScreen.java
// public abstract class BaseScreen extends ClassKey implements InjectionComponent {
// 
//     public abstract
//     @LayoutRes
//     int layoutResId();
// }


// Path: app/src/main/java/leonardo2204/com/br/flowtests/flow/dispatcher/BasicDispatcher.java
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.support.annotation.LayoutRes;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.Locale;
import flow.Direction;
import flow.Dispatcher;
import flow.Traversal;
import flow.TraversalCallback;
import leonardo2204.com.br.flowtests.R;
import leonardo2204.com.br.flowtests.flow.FlowUtils;
import leonardo2204.com.br.flowtests.screen.BaseScreen;

package leonardo2204.com.br.flowtests.flow.dispatcher;




/**
 * Created by Leonardo on 04/03/2016.
 */
public final class BasicDispatcher implements Dispatcher {

    //private static Map<Class,Integer> LAYOUT_CACHE = new LinkedHashMap<>();
    private final Activity activity;

    public BasicDispatcher(Activity activity) {
        this.activity = activity;
    }

    @Override
    public void dispatch(final Traversal traversal, final TraversalCallback callback) {
        Object dest = traversal.destination.top();

        final ViewGroup frame = (ViewGroup) activity.findViewById(R.id.content);

        View fromView = null;
        if(traversal.origin != null){
            if(frame.getChildCount() > 0){
                fromView = frame.getChildAt(0);
                traversal.getState(traversal.origin.top()).save(frame.getChildAt(0));
            }
        }

        if (!(dest instanceof BaseScreen))
            throw new IllegalStateException(String.format(Locale.getDefault(), "The screen %s must implement BaseScreen", dest.getClass().getName()));

        @LayoutRes final int layout = ((BaseScreen) dest).layoutResId();

        final View incomingView = LayoutInflater.from(traversal.createContext(dest,activity)).inflate(layout,frame,false);

        traversal.getState(traversal.destination.top()).restore(incomingView);

        if(fromView == null || traversal.direction == Direction.REPLACE) {
            frame.removeAllViews();
            frame.addView(incomingView);
            callback.onTraversalCompleted();
        }else{
            frame.addView(incomingView);
            final View fromViewFinal = fromView;
            FlowUtils.waitForMeasure(incomingView, new FlowUtils.OnMeasuredCallback() {