package com.alangpierce.lambdacalculusplayground;

import android.content.Context;
import android.widget.RelativeLayout;

import com.alangpierce.lambdacalculusplayground.dragdrop.DragManager;
import com.alangpierce.lambdacalculusplayground.expressioncontroller.ExpressionController;
import com.alangpierce.lambdacalculusplayground.expressioncontroller.ExpressionControllerFactory.ExpressionControllerFactoryFactory;
import com.alangpierce.lambdacalculusplayground.expressioncontroller.TopLevelExpressionController;
import com.alangpierce.lambdacalculusplayground.geometry.Point;
import com.alangpierce.lambdacalculusplayground.geometry.Views;
import com.alangpierce.lambdacalculusplayground.palette.PaletteController;
import com.alangpierce.lambdacalculusplayground.palette.PaletteLambdaController;
import com.alangpierce.lambdacalculusplayground.palette.PaletteView;
import com.alangpierce.lambdacalculusplayground.userexpression.UserExpression;
import com.google.common.collect.ImmutableList;

import java.util.Map.Entry;

public class TopLevelExpressionManagerImpl implements TopLevelExpressionManager {
    private final TopLevelExpressionState expressionState;
    private final ExpressionControllerFactoryFactory controllerFactoryFactory;
    private final DragManager dragManager;
    private final RelativeLayout rootView;
    private final Context context;

    public TopLevelExpressionManagerImpl(
            TopLevelExpressionState expressionState,
            ExpressionControllerFactoryFactory controllerFactoryFactory,
            DragManager dragManager, RelativeLayout rootView, Context context) {
        this.expressionState = expressionState;
        this.controllerFactoryFactory = controllerFactoryFactory;
        this.dragManager = dragManager;
        this.rootView = rootView;
        this.context = context;
    }

    @Override
    public void renderInitialExpressions() {
        for (Entry<Integer, ScreenExpression> entry : expressionState.expressionsById()) {
            int exprId = entry.getKey();
            ScreenExpression screenExpression = entry.getValue();
            renderTopLevelExpression(exprId, screenExpression);
        }
        renderPalette();
    }

    private void renderPalette() {
        PaletteView view = PaletteView.render(context, rootView);
        PaletteController controller = new PaletteController(view);
        controller.registerCallbacks(dragManager);

        int yPos = 100;
        for (String varName : ImmutableList.of("x", "y", "t", "f", "s", "z")) {
            renderPaletteLambda(Point.create(1750, yPos), varName);
            yPos += 200;
        }
    }

    private void renderPaletteLambda(Point canvasPos, String varName) {
        PaletteLambdaController controller = controllerFactoryFactory.create(this)
                .createPaletteLambdaController(varName);
        rootView.addView(controller.getView().getNativeView(),
                Views.layoutParamsForRelativePos(canvasPos));
    }

    @Override
    public TopLevelExpressionController createNewExpression(
            UserExpression expression, Point screenPos) {
        Point canvasPos = screenPos.minus(Views.getScreenPos(rootView));
        ScreenExpression screenExpression = ScreenExpression.create(expression, canvasPos);
        int exprId = expressionState.addScreenExpression(screenExpression);
        return renderTopLevelExpression(exprId, screenExpression);
    }

    @Override
    public TopLevelExpressionController sendExpressionToTopLevel(
            ExpressionController expression, Point screenPos) {
        Point canvasPos = screenPos.minus(Views.getScreenPos(rootView));
        ScreenExpression screenExpression = ScreenExpression.create(
                expression.getExpression(), canvasPos);
        int exprId = expressionState.addScreenExpression(screenExpression);
        TopLevelExpressionController controller = controllerFactoryFactory.create(this)
                .wrapInTopLevelController(expression, screenExpression);
        registerTopLevelExpression(exprId, controller, canvasPos);
        return controller;
    }

    /**
     * Given a new expression, create a view for it and hook up all necessary callbacks.
     */
    private TopLevelExpressionController renderTopLevelExpression(
            int exprId, ScreenExpression screenExpression) {
        TopLevelExpressionController controller =
                controllerFactoryFactory.create(this).createTopLevelController(screenExpression);
        registerTopLevelExpression(exprId, controller, screenExpression.getCanvasPos());
        return controller;
    }

    private void registerTopLevelExpression(
            int exprId, TopLevelExpressionController controller, Point canvasPos) {
        controller.setOnChangeCallback(
                // onChange
                (newController) -> {
                    if (newController != null) {
                        expressionState.modifyExpression(
                                exprId, newController.getScreenExpression());
                    } else {
                        expressionState.deleteExpression(exprId);
                    }
                });
        controller.getView().attachToRoot(canvasPos);
    }
}

@@ -2443,10 +2443,9 @@
 s = 
-10
+5
 0;%0A 
@@ -2509,16 +2509,21 @@
 t%22, %22f%22,
+ %22b%22,
  %22s%22, %22z
@@ -2523,16 +2523,26 @@
 %22s%22, %22z%22
+, %22n%22, %22m%22
 )) %7B%0A   
@@ -2630,11 +2630,11 @@
  += 
-200
+145
 ;%0A  

Add more variables to the palette