package electrosphere.menu;

import electrosphere.engine.Globals;
import electrosphere.entity.state.inventory.InventoryUtils;
import electrosphere.entity.state.inventory.RelationalInventoryState;
import electrosphere.entity.state.inventory.UnrelationalInventoryState;
import electrosphere.menu.ingame.MenuGeneratorsInventory;
import electrosphere.menu.mainmenu.MenuGeneratorsTitleMenu;
import electrosphere.renderer.ui.elements.Label;
import electrosphere.renderer.ui.elements.Window;
import electrosphere.renderer.ui.elementtypes.ContainerElement;
import electrosphere.renderer.ui.elementtypes.DrawableElement;
import electrosphere.renderer.ui.elementtypes.Element;

/**
 * Utils for native windowing framework
 */
public class WindowUtils {
    
    /**
     * Replaces the main menu contents
     * @param newMenu The new contents
     */
    public static void replaceMainMenuContents(Element newMenu){
        Element mainMenuEl = Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_MAIN);
        if(mainMenuEl != null && mainMenuEl instanceof Window){
            Window mainMenu = (Window) mainMenuEl;
            //todo: destroy elements as well
            mainMenu.clear();
            mainMenu.addChild(newMenu);
            mainMenu.applyYoga(0,0);
            Globals.elementManager.focusFirstElement();
        }
    }

    /**
     * Recursively sets a window as visible or not
     * @param topLevelMenu The window element
     * @param visible true for visible, false for invisible
     */
    public static void recursiveSetVisible(Element topLevelMenu, boolean visible){
        if(topLevelMenu instanceof DrawableElement){
            ((DrawableElement)topLevelMenu).setVisible(visible);
        }
        if(topLevelMenu instanceof ContainerElement){
            for(Element child : ((ContainerElement)topLevelMenu).getChildren()){
                recursiveSetVisible(child, visible);
            }
        }
        if(Globals.elementManager.getFocusedElement() == null){
            Globals.elementManager.focusFirstElement();
        }
        if(visible){
            topLevelMenu.applyYoga(0, 0);
        }
    }

    /**
     * Checks whether the window registered to the provided string is open
     * @param windowString The window string
     * @return true if the window is open, false otherwise
     */
    public static boolean windowIsOpen(String windowString){
        Element windowElement = Globals.elementManager.getWindow(windowString);
        return Globals.elementManager.getWindowList().contains(windowElement);
    }

    /**
     * Checks if a window is open or not
     * @return The window
     */
    public static boolean controlBlockingWindowIsOpen(){
        return windowIsOpen(WindowStrings.LEVEL_EDTIOR_SIDE_PANEL);
    }

    /**
     * Gets an inventory window string by the id of the inventory
     * @param id the id
     * @return the window string for said inventory window
     */
    public static String getInventoryWindowID(int id){
        return "INVENTORY-" + id;
    }

    public static void replaceWindowContents(String window, Element content){
        Element mainMenuEl = Globals.elementManager.getWindow(window);
        if(mainMenuEl != null && mainMenuEl instanceof Window){
            Window mainMenu = (Window) mainMenuEl;
            //todo: destroy elements as well
            mainMenu.getChildren().clear();
            mainMenu.addChild(content);
            Globals.elementManager.focusFirstElement();
        }
    }

    public static void pushItemIconToItemWindow(Element itemIcon){
        Window targetWindow = (Window) Globals.elementManager.getWindow(WindowStrings.WINDOW_ITEM_DRAG_CONTAINER);
        targetWindow.addChild(itemIcon);
        recursiveSetVisible(targetWindow,true);
        Globals.elementManager.pushWindowToFront(targetWindow);
    }

    public static void cleanItemDraggingWindow(){
        Window targetWindow = (Window) Globals.elementManager.getWindow(WindowStrings.WINDOW_ITEM_DRAG_CONTAINER);
        targetWindow.getChildren().clear();
        recursiveSetVisible(targetWindow, false);
    }

    public static void replaceWindow(String window, Window windowEl){
        Globals.elementManager.unregisterWindow(window);
        Globals.elementManager.registerWindow(window, windowEl);
        recursiveSetVisible(windowEl, true);
        Globals.elementManager.focusFirstElement();
    }

    /**
     * Cleans up a window visually and removes it from the element manager
     * @param window the window to clean up
     */
    public static void closeWindow(String window){
        Element windowEl = Globals.elementManager.getWindow(window);
        recursiveSetVisible(windowEl, false);
        Globals.elementManager.unregisterWindow(window);
    }



    /**
     * [CLIENT ONLY] Attempts to redraw open player character inventory screens (ie when there's an inventory update over network)
     */
    public static void attemptRedrawInventoryWindows(){
        //make sure we're client and the player entity exists
        if(Globals.RUN_CLIENT && Globals.playerEntity != null){
            //check equip inventory
            if(InventoryUtils.hasEquipInventory(Globals.playerEntity) && Globals.elementManager.containsWindow(WindowStrings.WINDOW_CHARACTER)){
                //redraw if necessary
                RelationalInventoryState inventory = InventoryUtils.getEquipInventory(Globals.playerEntity);
                WindowUtils.replaceWindow(WindowStrings.WINDOW_CHARACTER, MenuGeneratorsInventory.createCharacterInventoryMenu(inventory));
            }
            //check natural inventory
            if(InventoryUtils.hasNaturalInventory(Globals.playerEntity)){
                //we need to know the inventory to know which window to check as there can be multiple unrelational inventory screens open
                UnrelationalInventoryState inventory = InventoryUtils.getNaturalInventory(Globals.playerEntity);
                if(Globals.elementManager.containsWindow(WindowUtils.getInventoryWindowID(inventory.getId()))){
                    //once we have the natural inventory, redraw
                    WindowUtils.replaceWindow(WindowUtils.getInventoryWindowID(inventory.getId()), MenuGeneratorsInventory.createNaturalInventoryMenu(inventory));
                }
            }
        }
    }



    public static void initBaseWindows(){
        initLoadingWindow();
        initItemDropWindow();
        initItemDragContainerWindow();
        initMainMenuWindow();
    }

    static void initLoadingWindow(){
        Window loadingWindow = new Window(Globals.renderingEngine.getOpenGLState(), 0, 0, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT,false);
        Label loadingLabel = new Label(1.0f);
        loadingLabel.setText("LOADING");
        loadingWindow.addChild(loadingLabel);
        loadingWindow.applyYoga(0,0);
        Globals.elementManager.registerWindow(WindowStrings.WINDOW_LOADING, loadingWindow);
        WindowUtils.recursiveSetVisible(loadingWindow, true);
    }

    static void initMainMenuWindow(){
        Window mainMenuWindow = new Window(Globals.renderingEngine.getOpenGLState(), 0, 0, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT,false);
        Globals.elementManager.registerWindow(WindowStrings.WINDOW_MENU_MAIN, mainMenuWindow);
        WindowUtils.replaceMainMenuContents(MenuGeneratorsTitleMenu.createTitleMenu());
    }

    static void initItemDropWindow(){
        Globals.elementManager.registerWindow(WindowStrings.WINDDOW_ITEM_DROP, MenuGeneratorsInventory.worldItemDropCaptureWindow());
    }

    static void initItemDragContainerWindow(){
        Window itemDragContainerWindow = new Window(Globals.renderingEngine.getOpenGLState(), 0,0,Globals.WINDOW_WIDTH,Globals.WINDOW_HEIGHT,false);
        Globals.elementManager.registerWindow(WindowStrings.WINDOW_ITEM_DRAG_CONTAINER, itemDragContainerWindow);
    }

    public static void focusWindow(String window){
        Element windowEl = Globals.elementManager.getWindow(window);
        if(windowEl != null){
            Globals.elementManager.unregisterWindow(window);
            Globals.elementManager.registerWindow(window, windowEl);
        }
    }

    /**
     * Checks if the window is an inventory window or not
     * @param windowId The window id
     * @return true if is an inventory window, false otherwise
     */
    public static boolean isInventoryWindow(String windowId){
        return windowId.contains("INVENTORY") || windowId.equals(WindowStrings.WINDOW_MENU_INVENTORY) || windowId.equals(WindowStrings.WINDOW_CHARACTER);
    }

}
