/**
 * Copyright (C) 2009 eXo Platform SAS.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.exoplatform.portal.webui.navigation;

import java.util.Iterator;

import org.exoplatform.portal.mop.navigation.GenericScope;
import org.exoplatform.portal.mop.navigation.NodeChange;
import org.exoplatform.portal.mop.navigation.NodeChangeQueue;
import org.exoplatform.portal.mop.navigation.Scope;
import org.exoplatform.portal.mop.user.UserNavigation;
import org.exoplatform.portal.mop.user.UserNode;
import org.exoplatform.portal.mop.user.UserPortal;
import org.exoplatform.portal.webui.util.Util;
import org.exoplatform.webui.application.WebuiRequestContext;
import org.exoplatform.webui.config.annotation.ComponentConfig;
import org.exoplatform.webui.core.UIContainer;
import org.exoplatform.webui.core.UIRightClickPopupMenu;
import org.exoplatform.webui.core.UITree;

@ComponentConfig(template = "system:/groovy/portal/webui/navigation/UIPageNodeSelector.gtmpl")
public class UIPageNodeSelector extends UIContainer {
    private UserNode rootNode;

    private UserNode selectedNode;

    private UserPortal userPortal;

    public UIPageNodeSelector() throws Exception {
        UITree uiTree = addChild(UITree.class, null, "TreePageSelector");
        uiTree.setIcon("DefaultPageIcon");
        uiTree.setSelectedIcon("DefaultPageIcon");
        uiTree.setBeanIdField("URI");
        uiTree.setBeanLabelField("encodedResolvedLabel");
        uiTree.setBeanIconField("icon");
        uiTree.setBeanChildCountField("childrenCount");

        userPortal = Util.getPortalRequestContext().getUserPortalConfig().getUserPortal();
    }

    public void configure(UserNode node) throws Exception {
        if (node == null) {
            throw new IllegalArgumentException("node can't be null");
        }

        this.rootNode = node;
        while (rootNode.getParent() != null) {
            this.rootNode = rootNode.getParent();
        }
        setSelectedNode(node);
    }

    private void setSelectedNode(UserNode node) throws Exception {
        // If node is root node, and it's been deleted --> throw NavigationServiceException
        node = updateNode(node);

        // If node has been deleted --> select root node
        if (node == null) {
            configure(getRootNode());
        } else {
            UITree tree = getChild(UITree.class);
            tree.setSelected(node);
            UserNode parent = node.getParent();
            if (parent != null) {
                tree.setChildren(node.getChildren());
                tree.setSibbling(parent.getChildren());
                tree.setParentSelected(parent);
            } else {
                tree.setChildren(null);
                tree.setSibbling(node.getChildren());
                tree.setParentSelected(node);
            }
            selectedNode = node;
        }
    }

    private UserNode updateNode(UserNode node) {
        if (node == null) {
            return null;
        }

        NodeChangeQueue<UserNode> queue = new NodeChangeQueue<UserNode>();
        if (node.getParent() != null) {
            // The node may be resolved by UserPortal#resolvePath and this will filter all sibling nodes
            // We need to update from parent to make sure all sibling nodes can be retrieved
            userPortal.updateNode(node.getParent(), GenericScope.treeShape(3), queue);
        } else {
            userPortal.updateNode(node, Scope.GRANDCHILDREN, queue);
        }

        for (NodeChange<UserNode> change : queue) {
            if (change instanceof NodeChange.Removed) {
                UserNode deletedNode = ((NodeChange.Removed<UserNode>) change).getTarget();
                if (findUserNodeByURI(deletedNode, node.getURI()) != null) {
                    return null;
                }
            }
        }

        return node;
    }

    public void setSelectedURI(String uri) throws Exception {
        if (selectedNode == null) {
            throw new IllegalStateException("selectedNode is null, configure method must be called first");
        }

        UserNode node;
        if (selectedNode.getParent() != null) {
            node = findUserNodeByURI(selectedNode.getParent(), uri);
        } else {
            node = findUserNodeByURI(selectedNode, uri);
        }
        setSelectedNode(node);
    }

    private UserNode findUserNodeByURI(UserNode rootNode, String uri) {
        if (rootNode.getURI().equals(uri)) {
            return rootNode;
        }
        Iterator<UserNode> iterator = rootNode.getChildren().iterator();
        while (iterator.hasNext()) {
            UserNode next = iterator.next();
            UserNode node = findUserNodeByURI(next, uri);
            if (node == null) {
                continue;
            }
            return node;
        }
        return null;
    }

    public void processRender(WebuiRequestContext context) throws Exception {
        UIRightClickPopupMenu uiPopupMenu = getChild(UIRightClickPopupMenu.class);
        if (uiPopupMenu != null) {
            uiPopupMenu.setRendered(true);
        }
        super.processRender(context);
    }

    private UserNode getRootNode() {
        return this.rootNode;
    }

    public UserNode getSelectedNode() {
        return selectedNode;
    }

    public UserNavigation getNavigation() {
        return selectedNode.getNavigation();
    }
}
