package com.mobify.astro.plugins;

import android.support.annotation.NonNull;
import android.support.v4.widget.DrawerLayout;
import android.view.Gravity;
import android.view.View;

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.utilities.LocaleChangedListener;
import com.mobify.astro.utilities.LocalizationUtilities;

public class DrawerPlugin extends AstroPlugin implements LocaleChangedListener {
    protected LocalizationUtilities localizationUtilities;
    protected DrawerLayout drawerLayout;
    private View contentView;
    private View leftMenuView;
    private View rightMenuView;

    private String leftViewAddress;
    private String rightViewAddress;

    /**
     * Creates a new DrawerPlugin and attaches it to the activity provided
     *
     * It's important to note that "secondaryMenu" is always the menu on the right,
     * and "menu" is always the menu on the left.
     *
     * @param activity the activity to attach the DrawerPlugin to
     */
    public DrawerPlugin(@NonNull AstroActivity activity, @NonNull PluginResolver pluginResolver,
                        @NonNull EventRegistrar eventRegistrar, @NonNull MessageSender messageSender) {
        super(activity, pluginResolver, eventRegistrar, messageSender);

        localizationUtilities = activity.getLocalizationUtilities();
        drawerLayout = new DrawerLayout(activity);
        localizationUtilities.addLocaleChangedListener(this);
    }

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

    protected View getLeftView() {
        return leftMenuView;
    }

    protected View getRightView() {
        return rightMenuView;
    }


    protected boolean isLeftMenuShowing() {
        if (this.leftMenuView == null) {
            return false;
        }
        return drawerLayout.isDrawerOpen(leftMenuView);
    }

    protected boolean isRightMenuShowing() {
        if (this.rightMenuView == null) {
            return false;
        }
        return drawerLayout.isDrawerOpen(rightMenuView);
    }

    /**
     * Sets the view for the main content who's address is provided
     * @param address the address of the plugin you want to have in the main
     * content of the drawer
     */
    @RpcMethod(methodName = "setContentView", parameterNames = {"address"})
    public void setContentView(String address) {
        AstroPlugin plugin = pluginResolver.instanceForAddress(address);
        View view = plugin.getView();

        if (contentView != null) {
            drawerLayout.removeView(contentView);
        }
        drawerLayout.addView(view, 0);
        contentView = view;
    }

    //region Left menu.

    /**
     * Sets the view for the left drawer to the plugin who's address is provided
     * @param address the address of the plugin you want to have in the left drawer
     */
    @RpcMethod(methodName = "setLeftMenu", parameterNames = {"address"})
    public void setLeftMenu(String address) {
        leftViewAddress = address;
        AstroPlugin plugin = pluginResolver.instanceForAddress(address);

        View view = plugin.getView();

        // The proper way to align the icons for ltr and rtl is to use start/end instead of left/right
        // The problem with this is an activity restart is required for the layout to change after
        // the locale changes. Using left/right allows us to change the layout on the fly.
        int leftGravity = localizationUtilities.leftToRight() ?
                Gravity.LEFT :
                Gravity.RIGHT;
        DrawerLayout.LayoutParams leftMenuLayoutParams = new DrawerLayout.LayoutParams(
                DrawerLayout.LayoutParams.MATCH_PARENT,
                DrawerLayout.LayoutParams.MATCH_PARENT,
                leftGravity
        );

        if (leftMenuView != null) {
            drawerLayout.removeView(leftMenuView);
        }
        drawerLayout.addView(view, leftMenuLayoutParams);
        leftMenuView = view;
    }

    /**
     * Slides open the left menu
     */
    @RpcMethod(methodName = "showLeftMenu")
    public void showLeftMenu() {
        // Since DrawerLayout doesn't auto-close the other side menu, we must close it ourselves.
        if (isRightMenuShowing()) {
            hideRightMenu();
        }
        if (leftMenuView != null) {
            activity.hideKeyboard();
            drawerLayout.openDrawer(leftMenuView);
        }
    }

    /**
     * Closes the left menu
     */
    @RpcMethod(methodName = "hideLeftMenu")
    public void hideLeftMenu() {
        if (leftMenuView != null && isLeftMenuShowing()) {
            activity.hideKeyboard();
            drawerLayout.closeDrawer(leftMenuView);
        }
    }

    /**
     * Toggles showing of the left menu.
     */
    @RpcMethod(methodName = "toggleLeftMenu")
    public void toggleLeftMenu() {
        if (!isLeftMenuShowing()) {
            showLeftMenu();
        }
        else {
            hideLeftMenu();
        }
    }

    //endregion

    //region Right menu.

    /**
     * Sets the view for the right drawer to the plugin who's address is provided
     * @param address the address of the plugin you want to have in the right drawer
     */
    @RpcMethod(methodName = "setRightMenu", parameterNames = {"address"})
    public void setRightMenu(String address) {
        rightViewAddress = address;
        AstroPlugin plugin = pluginResolver.instanceForAddress(address);

        View view = plugin.getView();

        int rightGravity = localizationUtilities.leftToRight() ?
                Gravity.RIGHT :
                Gravity.LEFT;
        DrawerLayout.LayoutParams rightMenuLayoutParams = new DrawerLayout.LayoutParams(
                DrawerLayout.LayoutParams.MATCH_PARENT,
                DrawerLayout.LayoutParams.MATCH_PARENT,
                rightGravity
        );

        if (rightMenuView != null) {
            drawerLayout.removeView(rightMenuView);
        }
        drawerLayout.addView(view, rightMenuLayoutParams);
        rightMenuView = view;
    }

    /**
     * Slides open the right menu
     */
    @RpcMethod(methodName = "showRightMenu")
    public void showRightMenu() {
        // Since DrawerLayout doesn't auto-close the other side menu, we must close it ourselves.
        if (isLeftMenuShowing()) {
            hideLeftMenu();
        }
        if (rightMenuView != null) {
            activity.hideKeyboard();
            drawerLayout.openDrawer(rightMenuView);
        }
    }

    /**
     * Closes the right menu
     */
    @RpcMethod(methodName = "hideRightMenu")
    public void hideRightMenu() {
        if (rightMenuView != null && isRightMenuShowing()) {
            activity.hideKeyboard();
            drawerLayout.closeDrawer(rightMenuView);
        }
    }

    /**
     * Toggles showing of the right menu.
     */
    @RpcMethod(methodName = "toggleRightMenu")
    public void toggleRightMenu() {
        if (!isRightMenuShowing()) {
            showRightMenu();
        } else {
            hideRightMenu();
        }
    }

    /**
     * Locks the right drawer menu. Locking the menu will also close it.
     */
    @RpcMethod(methodName="lockRightMenuClosed")
    public void lockRightMenuClosed() {
        drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, Gravity.RIGHT);
    }

    /**
     * Unlocks the right drawer menu.
     */
    @RpcMethod(methodName="unlockRightMenu")
    public void unlockRightMenu() {
        drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, Gravity.RIGHT);
    }

    /**
     * Locks the left drawer menu. Locking the menu will also close it.
     */
    @RpcMethod(methodName="lockLeftMenuClosed")
    public void lockLeftMenuClosed() {
        drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, Gravity.LEFT);
    }

    /**
     * Unlocks the left drawer menu.
     */
    @RpcMethod(methodName="unlockLeftMenu")
    public void unlockLeftMenu() {
        drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, Gravity.LEFT);
    }

    @Override
    public void localeDidChange() {
        if (leftViewAddress != null) {
            setLeftMenu(leftViewAddress);
        }

        if (rightViewAddress != null) {
            setRightMenu(rightViewAddress);
        }
    }

    //endregion
}
