package com.alangpierce.lambdacalculusplayground.dragdrop;

import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import com.alangpierce.lambdacalculusplayground.drag.PointerMotionEvent;
import com.alangpierce.lambdacalculusplayground.expressioncontroller.TopLevelExpressionController;
import com.alangpierce.lambdacalculusplayground.geometry.Point;
import com.alangpierce.lambdacalculusplayground.geometry.Views;

import java.util.Collections;
import java.util.List;

import autovalue.shaded.com.google.common.common.collect.Lists;
import rx.Observable;

public class DragSourceManagerImpl implements DragManager {
    private final RelativeLayout rootView;

    private final List<DragSource> dragSources = Collections.synchronizedList(Lists.newArrayList());
    private final List<DropTarget> dropTargets = Collections.synchronizedList(Lists.newArrayList());

    public DragSourceManagerImpl(RelativeLayout rootView) {
        this.rootView = rootView;
    }

    @Override
    public void registerDragSource(DragSource dragSource) {
        Observable<? extends Observable<PointerMotionEvent>> dragObservable =
                dragSource.getDragObservable();

        dragObservable.subscribe(dragEvents -> {
            /*
             * TODO: We're assuming that the observable doesn't even get created until the drag
             * action starts, which might not be true.
             */
            TopLevelExpressionController expressionController = dragSource.handleStartDrag();
            LinearLayout view = expressionController.getView().getNativeView();
            rootView.addView(view);
            expressionController.setCallbacks(
                    // onChange
                    // TODO: Register the callback correctly.
                    (newScreenExpression) -> {},
//                    (newScreenExpression) ->
//                            expressionState.modifyExpression(exprId, newScreenExpression),
                    // onDetach
                    rootView::removeView);

            dragEvents.subscribe(event -> {
                switch (event.getAction()) {
                    case DOWN:
                        view.animate().setDuration(100)
                                .translationZBy(10).scaleX(1.05f).scaleY(1.05f);
                        // Fall through.
                    case MOVE: {
                        setViewScreenPos(view, event.getScreenPos());
                        break;
                    }
                    case UP:
                        view.animate().setDuration(100)
                                .translationZBy(-10).scaleX(1.0f).scaleY(1.0f);
                        break;
                }
            });
        });
    }

    private void setViewScreenPos(LinearLayout view, Point screenPos) {
        Point relativePos = screenPos.minus(Views.getScreenPos(rootView));
        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        layoutParams.leftMargin = relativePos.getX();
        layoutParams.topMargin = relativePos.getY();
        view.setLayoutParams(layoutParams);
    }
}

@@ -481,16 +481,68 @@
 il.List;
+%0Aimport java.util.concurrent.atomic.AtomicReference;
 %0A%0Aimport
@@ -1296,161 +1296,200 @@
     
-/*%0A             * TODO: We're assuming that the observable doesn't 
+AtomicReference%3CLinearLayout%3E viewReference = new AtomicReference%3C%3E();%0A            dragEvents.subscribe(event -%3E %7B%0A                switch (
 even
- get created until the drag%0A             * action starts, which might not be true.
+t.getAction()) %7B%0A                    case DOWN: %7B
 %0A   
@@ -1501,12 +1501,8 @@
     
- */%0A
     
@@ -1587,24 +1587,36 @@
 tartDrag();%0A
+            
             
@@ -1699,32 +1699,285 @@
     
-rootView.addView(view);%0A
+            viewReference.set(view);%0A                        Point screenPos = expressionController.getView().getScreenPos();%0A                        rootView.addView(view, Views.layoutParamsForScreenPosition(%0A                                rootView, screenPos));%0A            
     
@@ -2035,24 +2035,36 @@
             
+            
 // onChange%0A
@@ -2063,16 +2063,28 @@
 nChange%0A
+            
         
@@ -2149,32 +2149,44 @@
                 
+            
 (newScreenExpres
@@ -2195,16 +2195,49 @@
 on) -%3E %7B
+%0A                                
 %7D,%0A//   
@@ -2371,16 +2371,28 @@
 ssion),%0A
+            
         
@@ -2427,32 +2427,44 @@
                 
+            
 rootView::remove
@@ -2474,128 +2474,8 @@
 w);%0A
-%0A            dragEvents.subscribe(event -%3E %7B%0A                switch (event.getAction()) %7B%0A                    case DOWN:
 %0A   
@@ -2632,28 +2632,9 @@
     
-    // Fall through.
+%7D
 %0A   
@@ -2691,51 +2691,46 @@
     
-setViewScreenPos(view, event.getScreenPos()
+LinearLayout view = viewReference.get(
 );%0A 
@@ -2744,38 +2744,51 @@
                 
-break;
+if (view == null) %7B
 %0A               
@@ -2784,33 +2784,46 @@
                 
-%7D
+        break;
 %0A               
@@ -2831,16 +2831,13 @@
     
-case UP:
+    %7D
 %0A   
@@ -2866,34 +2866,60 @@
 iew.
-animate().setDura
+setLayoutParams(Views.layoutParamsForScreenPosi
 tion(
-100)
 %0A   
@@ -2951,53 +2951,39 @@
     
-.translationZBy(-10).scaleX(1.0f).scaleY(1.0f
+rootView, event.getScreenPos())
 );%0A 
@@ -3020,32 +3020,36 @@
                 
+    
 %7D%0A            %7D)
@@ -3042,27 +3042,40 @@
             
-%7D);
+        case UP:
 %0A        %7D);
@@ -3075,499 +3075,380 @@
     
-%7D);%0A
     
-%7D%0A%0A
     
-private void setViewScreenPos(LinearLayout view, Point screenPos) %7B%0A        Point relativePos = screenPos.minus(Views.getScreenPos(rootView));%0A        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(%0A                RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);%0A        layoutParams.leftMargin = relativePos.getX();%0A        layoutParams.topMargin = relativePos.getY();%0A        view.setLayoutParams(layoutParams
+        LinearLayout view = viewReference.get();%0A                        if (view == null) %7B%0A                            break;%0A                        %7D%0A                        view.animate().setDuration(100)%0A                                .translationZBy(-10).scaleX(1.0f).scaleY(1.0f);%0A                        break;%0A                %7D%0A            %7D);%0A        %7D
 );%0A 

Fix bug with dragging views out of expressions