package com.mobify.astro.plugins;

import android.animation.LayoutTransition;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

import com.mobify.astro.AstroActivity;
import com.mobify.astro.AstroPlugin;
import com.mobify.astro.PluginResolver;
import com.mobify.astro.messaging.EventRegistrar;
import com.mobify.astro.messaging.MessageSender;
import com.mobify.astro.messaging.annotations.RpcMethod;
import com.mobify.astro.plugins.layouts.AnimatableSectionedContainerView;
import com.mobify.astro.utilities.ViewUtilities;

import org.json.JSONException;
import org.json.JSONObject;

public class AnchoredLayoutPlugin extends AstroPlugin {

    private static final String TAG = AnchoredLayoutPlugin.class.getName();

    AnimatableSectionedContainerView containerView;

    public AnchoredLayoutPlugin(@NonNull AstroActivity activity, @NonNull PluginResolver pluginResolver,
                                @NonNull EventRegistrar eventRegistrar, @NonNull MessageSender messageSender) {
        super(activity, pluginResolver, eventRegistrar, messageSender);
    }

    @Override
    public void initialize() {
        containerView = new AnimatableSectionedContainerView(activity);
    }

    private static boolean retrieveAnimatedOption(JSONObject options) {
        final String animatedKey = "animated";
        boolean animated = false;

        try {
            if (options.has(animatedKey)) {
                animated = options.getBoolean(animatedKey);
            }
        } catch (JSONException e) {
            Log.d(TAG, e.getMessage());
        }
        return animated;
    }

    private static int retrieveAnimationDurationOption(JSONObject options) {
        final String animationDurationKey = "animationDuration";
        int animationDuration = AnimatableSectionedContainerView.DEFAULT_ANIMATION_DURATION;
        try {
            if (options.has(animationDurationKey)) {
                animationDuration = options.getInt(animationDurationKey);
            }
        } catch (JSONException e) {
            Log.d(TAG, e.getMessage());
        }
        return animationDuration;
    }

    private void setAnimationTransition(LayoutTransition layoutTransition) {
        containerView.setLayoutTransition(layoutTransition);
    }

    private void disableAnimations() {
        setAnimationTransition(null);
    }

    private void enableAnimations(int animationDuration, boolean fadesItems) {
        setAnimationTransition(AnimatableSectionedContainerView.getDefaultLayoutTransition(fadesItems));
        containerView.setAnimationDuration(animationDuration);
    }

    private void setAnimationState(JSONObject options, boolean fadesItems) {
        if (options == null || !retrieveAnimatedOption(options)) {
            disableAnimations();
            return;
        }

        enableAnimations(retrieveAnimationDurationOption(options), fadesItems);
    }

    @Override
    public View getView() {
        return containerView;
    }

    /**
     * Sets the main content view.
     * @param address the address of the view to set
     */
    @RpcMethod(methodName = "setContentView", parameterNames = {"address"})
    public void setContentView(String address)  throws Exception {
        AstroPlugin plugin = pluginResolver.instanceForAddress(address);
        View view = plugin.getView();
        disableAnimations();
        containerView.addMiddleView(view);
    }

    /**
     * Adds and anchors a view to the top.
     * @param address the address of the view to add
     * @param options optional [boolean]visible and [integer]height options
     */
    @RpcMethod(methodName = "addTopView", parameterNames = {"address", "options"})
    public void addTopView(String address, JSONObject options) throws Exception {
        AstroPlugin plugin = pluginResolver.instanceForAddress(address);
        View view = plugin.getView();
        setAnimationState(options, false);
        containerView.addTopView(view, options);
    }

    /**
     * Adds and anchors a view to the bottom.
     * @param address the address of the view to add
     */
    @RpcMethod(methodName = "addBottomView", parameterNames = {"address", "options"})
    public void addBottomView(String address, JSONObject options) throws Exception {
        AstroPlugin plugin = pluginResolver.instanceForAddress(address);
        View view = plugin.getView();
        setAnimationState(options, false);
        if (view.getParent() != null) {
            ((ViewGroup)view.getParent()).removeView(view);
        }
        containerView.addBottomView(view, options);
    }

    /**
     * Clears the top container by removing (not destroy) all of the children views
     */
    @RpcMethod(methodName = "clearTopViews", parameterNames = {"options"})
    public void clearTopViews(JSONObject options) {
        setAnimationState(options, false);
        containerView.removeTopViews();
    }

    /**
     * Clears the content container by removing (not destroy) all of the children views
     */
    @RpcMethod(methodName = "clearContentView")
    public void clearContentView() {
        disableAnimations();
        containerView.removeMiddleView();
    }

    /**
     * Clears the bottom container by removing (not destroy) all of the children views
     */
    @RpcMethod(methodName = "clearBottomViews", parameterNames = {"options"})
    public void clearBottomViews(JSONObject options) {
        setAnimationState(options, true);
        containerView.removeBottomViews();
    }

    /**
     * Shows a plugin that has already been added.
     */
    @RpcMethod(methodName = "showView", parameterNames = {"address", "options"})
    public void showView(String address, JSONObject options) {
        AstroPlugin plugin = pluginResolver.instanceForAddress(address);
        View view = plugin.getView();
        setAnimationState(options, false);
        containerView.setChildVisibility(view, View.VISIBLE);
    }

    /**
     * Hides a plugin that has already been added.
     */
    @RpcMethod(methodName = "hideView", parameterNames = {"address", "options"})
    public void hideView(String address, JSONObject options) {
        AstroPlugin plugin = pluginResolver.instanceForAddress(address);
        View view = plugin.getView();
        setAnimationState(options, false);
        containerView.setChildVisibility(view, View.GONE);
    }

    @RpcMethod(methodName = "showTopViews", parameterNames = {"options"})
    public void showTopViews(JSONObject options) {
        setAnimationState(options, false);
        containerView.setVisibilityTopViews(View.VISIBLE);
    }

    @RpcMethod(methodName = "hideTopViews", parameterNames = {"options"})
    public void hideTopViews(JSONObject options) {
        setAnimationState(options, false);
        containerView.setVisibilityTopViews(View.GONE);
    }

    @RpcMethod(methodName = "showBottomViews", parameterNames = {"options"})
    public void showBottomViews(JSONObject options) {
        setAnimationState(options, true);
        containerView.setVisibilityBottomViews(View.VISIBLE);
    }

    @RpcMethod(methodName = "hideBottomViews", parameterNames = {"options"})
    public void hideBottomViews(JSONObject options) {
        setAnimationState(options, true);
        containerView.setVisibilityBottomViews(View.GONE);
    }

    /**
     * Toggles visibility of a plugin that has already been added.
     */
    @RpcMethod(methodName = "toggleView", parameterNames = {"address", "options"})
    public void toggleView(String address, JSONObject options) {
        AstroPlugin plugin = pluginResolver.instanceForAddress(address);
        View view = plugin.getView();
        int currentVisibility = view.getVisibility();
        int toggledVisibility;

        if (currentVisibility == View.GONE || currentVisibility == View.INVISIBLE) {
            toggledVisibility = View.VISIBLE;
        } else {
            toggledVisibility = View.GONE;
        }
        setAnimationState(options, false);
        containerView.setChildVisibility(view, toggledVisibility);
    }
}
