/**
 * License Agreement.
 *
 *  JBoss RichFaces - Ajax4jsf Component Library
 *
 * Copyright (C) 2007  Exadel, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 *
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */

package org.ajax4jsf.bean.tree;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import javax.faces.FacesException;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;

import org.ajax4jsf.bean.tree.rich.AudioLibrary;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.xmlrules.DigesterLoader;
import org.richfaces.component.UITree;
import org.richfaces.component.UITreeNode;
import org.richfaces.component.state.TreeStateAdvisor;
import org.richfaces.event.DropEvent;
import org.richfaces.event.NodeSelectedEvent;
import org.richfaces.model.TreeNode;
import org.richfaces.model.TreeNodeImpl;
import org.richfaces.model.TreeRowKey;
import org.xml.sax.SAXException;

/**
 * Copied from demo
 */
public class TreeTestBean {

    private TreeNode<String> rootNode = null;

    private String nodeTitle;

    private static final String DATA_PATH = "/simple-tree-data.properties";

    public void processSelection(NodeSelectedEvent event) {
        UITree tree = (UITree) event.getComponent();
    }

    private void addNodes(String path, TreeNode<String> node, Properties properties) {
        boolean end = false;
        int counter = 1;

        while (!end) {
            String key = path != null ? path + '.' + counter : String.valueOf(counter);

            String value = properties.getProperty(key);
            if (value != null) {
                TreeNode<String> nodeImpl = new TreeNodeImpl<String>();
                nodeImpl.setData(value);
                node.addChild(new Integer(counter), nodeImpl);
                addNodes(key, nodeImpl, properties);
                counter++;
            } else {
                end = true;
            }
        }
    }

    private void loadTree() {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        ExternalContext externalContext = facesContext.getExternalContext();
        InputStream dataStream = this.getClass().getClassLoader().getResourceAsStream(DATA_PATH);
        try {
            Properties properties = new Properties();
            properties.load(dataStream);

            rootNode = new TreeNodeImpl<String>();
            addNodes(null, rootNode, properties);

        } catch (IOException e) {
            throw new FacesException(e.getMessage(), e);
        } finally {
            if (dataStream != null) {
                try {
                    dataStream.close();
                } catch (IOException e) {
                    externalContext.log(e.getMessage(), e);
                }
            }
        }
    }

    public TreeNode<String> getTreeNode() {
        if (rootNode == null) {
            loadTree();
        }

        return rootNode;
    }

    private TreeNode<Object> richRootNode = null;

    public TreeNode<Object> getRichTreeNode() {
        if (null == richRootNode) {
            Digester digester = DigesterLoader.createDigester(getClass().getResource("/rich-digester-rules.xml"));
            AudioLibrary library = new AudioLibrary();
            digester.push(library);
            try {
                digester.parse(getClass().getResourceAsStream("/audio-library.xml"));
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (SAXException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            richRootNode = library;
        }

        return richRootNode;
    }

    private javax.swing.tree.TreeNode swingRootNode = null;

    public javax.swing.tree.TreeNode getSwingTreeNode() {
        if (null == swingRootNode) {
            Digester digester = DigesterLoader.createDigester(getClass().getResource("/swing-digester-rules.xml"));
            org.ajax4jsf.bean.tree.swing.AudioLibrary library = new org.ajax4jsf.bean.tree.swing.AudioLibrary();
            digester.push(library);
            try {
                digester.parse(getClass().getResourceAsStream("/audio-library.xml"));
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (SAXException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            swingRootNode = library;
        }

        return swingRootNode;
    }

    private boolean isRichModel = true;

    /**
     * Gets value of isRichModel field.
     * @return value of isRichModel field
     */
    public boolean isRichModel() {
        return isRichModel;
    }

    /**
     * Set a new value for isRichModel field.
     * @param isRichModel a new value for isRichModel field
     */
    public void setRichModel(boolean isRichModel) {
        this.isRichModel = isRichModel;
    }

    public Object getRootNode() {
        if(isRichModel) {
            return getRichTreeNode();
        } else {
            return getSwingTreeNode();
        }
    }

    public String getNodeTitle() {
        return nodeTitle;
    }

    public void setNodeTitle(String nodeTitle) {
        this.nodeTitle = nodeTitle;
    }

    public void dropListener(DropEvent dropEvent) {
        //we have only one tree: destination tree coincides with source one
        UITree tree = ((UITreeNode) dropEvent.getSource()).getUITree();

        TreeRowKey<Object> dropNodeKey = (TreeRowKey<Object>) dropEvent.getDropValue();
        TreeNode<Object> dropNode = tree.getTreeNode(dropNodeKey);

        TreeRowKey<Object> draggedNodeKey = (TreeRowKey<Object>) dropEvent.getDragValue();
        TreeNode<Object> draggedNode = tree.getTreeNode(draggedNodeKey);

        //mark destination node as wanting rerendering
        tree.addRequestKey(dropNodeKey);
        Object state = null;
        if(null != draggedNodeKey) {
            // 1. mark its parent as wanting rerendering
            tree.addRequestKey(tree.getTreeNodeRowKey(draggedNode.getParent()));
            // 2. remove node from tree
            state = tree.removeNode(draggedNodeKey);
            // 3. add the node at the new place
            tree.addNode(dropNodeKey, draggedNode, System.currentTimeMillis(), state);
        }
    }

    private String switchType = "ajax";

    /**
     * Gets value of switchType field.
     * @return value of switchType field
     */
    public String getSwitchType() {
        return switchType;
    }

    /**
     * Set a new value for switchType field.
     * @param switchType a new value for switchType field
     */
    public void setSwitchType(String switchType) {
        this.switchType = switchType;
    }

    private boolean toggleOnClick = false;

    /**
     * Gets value of toggleOnClick field.
     * @return value of toggleOnClick field
     */
    public boolean isToggleOnClick() {
        return toggleOnClick;
    }

    /**
     * Set a new value for toggleOnClick field.
     * @param toggleOnClick a new value for toggleOnClick field
     */
    public void setToggleOnClick(boolean toggleOnClick) {
        this.toggleOnClick = toggleOnClick;
    }

    private boolean ajaxSubmitSelection = false;

    /**
     * Gets value of ajaxSubmitSelection field.
     * @return value of ajaxSubmitSelection field
     */
    public boolean isAjaxSubmitSelection() {
        return ajaxSubmitSelection;
    }

    /**
     * Set a new value for ajaxSubmitSelection field.
     * @param ajaxSubmitSelection a new value for ajaxSubmitSelection field
     */
    public void setAjaxSubmitSelection(boolean ajaxSubmitSelection) {
        this.ajaxSubmitSelection = ajaxSubmitSelection;
    }

    public void initToggleOnClickTestServerMode() {
        setToggleOnClick(true);
        setSwitchType("server");
        setAjaxSubmitSelection(false);
        setRichModel(true);
    }

    public void initToggleOnClickTestAjaxMode() {
        setToggleOnClick(true);
        setSwitchType("ajax");
        setAjaxSubmitSelection(false);
        setRichModel(true);
    }

    public void initToggleOnClickTestClientMode() {
        setToggleOnClick(true);
        setSwitchType("client");
        setAjaxSubmitSelection(false);
        setRichModel(true);
    }
    public void initAjaxSubmitSelectionTest() {
        setSwitchType("client");
        setAjaxSubmitSelection(true);
        setToggleOnClick(false);
        setRichModel(true);
    }

    public void initAjaxCoreTest() {
        setSwitchType("ajax");
        setToggleOnClick(false);
        setAjaxSubmitSelection(false);
        setRichModel(true);
    }

    public void initAjaxCoreTestWithSwingModel() {
        setSwitchType("ajax");
        setToggleOnClick(false);
        setAjaxSubmitSelection(false);
        setRichModel(false);
    }

    public void initServerMode() {
        setSwitchType("server");
        setToggleOnClick(false);
        setAjaxSubmitSelection(false);
        setRichModel(true);
    }

    public void initAjaxMode() {
        setSwitchType("ajax");
        setToggleOnClick(false);
        setAjaxSubmitSelection(false);
        setRichModel(true);
    }

    public void initClientMode() {
        setSwitchType("client");
        setToggleOnClick(false);
        setAjaxSubmitSelection(false);
        setRichModel(true);
    }

    public void initDragAndDropTest() {
        if(advisor == null) {
            setAdvisor(new TestAdvisor());
        }
    }

    private TreeStateAdvisor advisor;

    /**
     * Gets value of advisor field.
     * @return value of advisor field
     */
    public TreeStateAdvisor getAdvisor() {
        return advisor;
    }

    /**
     * Set a new value for advisor field.
     * @param advisor a new value for advisor field
     */
    public void setAdvisor(TreeStateAdvisor advisor) {
        this.advisor = advisor;
    }

    public void initStateAdvisorTest() {
        if(advisor == null) {
            setAdvisor(new TestAdvisor());
        }
    }

    static class TestAdvisor implements TreeStateAdvisor {

        public Boolean adviseNodeOpened(UITree tree) {
            return true;
        }

        public Boolean adviseNodeSelected(UITree tree) {
            return null;
        }
    }

    public void tearDown() {
        setAdvisor(null);
    }

}
