/*****************************************************************************
 *                        Web3d.org Copyright (c) 2001-2007
 *                               Java Source
 *
 * This source is licensed under the BSD license.
 * Please read docs/BSD.txt for the text of the license.
 *
 * This software comes with the standard NO WARRANTY disclaimer for any
 * purpose. Use it at your own risk. If there's a problem you get to fix it.
 *
 ****************************************************************************/

import java.awt.*;
import java.util.HashMap;
import javax.swing.*;

import org.web3d.x3d.sai.*;

/**
 * A simple example of how to use SAI to walk a scene and change field values.
 *
 * @author Alan Hudson
 * @version
 */
public class SAISGWalkDemo extends JFrame {

    /**
     * Constructor for the demo.
     */
    public SAISGWalkDemo() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        Container contentPane = getContentPane();

        // Create an SAI component
        X3DComponent x3dComp = BrowserFactory.createX3DComponent(null);

        // Add the component to the UI
        JComponent x3dPanel = (JComponent)x3dComp.getImplementation();
        contentPane.add(x3dPanel, BorderLayout.CENTER);

        // Get an external browser
        ExternalBrowser x3dBrowser = x3dComp.getBrowser();

        setSize(500,500);
        setVisible(true);


        // Create an X3D scene by loading a file
        X3DScene mainScene = x3dBrowser.createX3DFromURL(new String[] { "boxes.x3dv" });

        // Replace the current world with the new one
        x3dBrowser.replaceWorld(mainScene);

        X3DNode[] roots = mainScene.getRootNodes();

        findMaterial(roots);
        
        findTransform(roots);
    }

    /**
     * Find all the material nodes and change them to red.
     */
    private void findMaterial(X3DNode[] nodes) {
        int len = nodes.length;
        int types[];

        X3DFieldDefinition[] decls;
        int dlen;
        X3DNode node;

        for(int i=0; i < len; i++) {
            node = nodes[i];

            if (typeEquals(node, X3DNodeTypes.X3DMaterialNode)) {

                // Get the diffuseColor field
                SFColor color = (SFColor) node.getField("diffuseColor");

                // Set its value to green
                float[] green = {0,1,0};
                color.setValue(green);
            }

            decls = node.getFieldDefinitions();
            dlen = decls.length;
            int ftype;
            int atype;
            MFNode mfnode;
            SFNode sfnode;

            X3DNode[] snodes;

            for(int j=0; j < dlen; j++) {
                ftype = decls[j].getFieldType();
                atype = decls[j].getAccessType();

                if (atype == X3DFieldTypes.INPUT_OUTPUT || atype == X3DFieldTypes.INITIALIZE_ONLY) {
                    if (ftype == X3DFieldTypes.MFNODE) {
                        mfnode = (MFNode) node.getField(decls[j].getName());
                        snodes = new X3DNode[mfnode.getSize()];

                        mfnode.getValue(snodes);
                        findMaterial(snodes);
                    } else if (ftype == X3DFieldTypes.SFNODE) {
                        sfnode = (SFNode) node.getField(decls[j].getName());
                        snodes = new X3DNode[1];

                        snodes[0] = sfnode.getValue();

                        if (snodes[0] != null) {
                            findMaterial(snodes);
                        }
                    }
                }
            }
        }
    }

    /**
     * Find all the material nodes and change them to red.
     */
    private void findTransform(X3DNode[] nodes) {
        int len = nodes.length;
        int types[];

        X3DFieldDefinition[] decls;
        int dlen;
        X3DNode node;

        for(int i=0; i < len; i++) {
            node = nodes[i];

            if (typeEquals(node, X3DNodeTypes.X3DGroupingNode) && node.getNodeName().equals("Transform")) {

                // Get the diffuseColor field
                SFVec3f trans = (SFVec3f) node.getField("translation");

                // Set its value to blue
                float[] loc = new float[3];
                trans.getValue(loc);
                loc[1] += 3;
                
                trans.setValue(loc);
            }

            decls = node.getFieldDefinitions();
            dlen = decls.length;
            int ftype;
            int atype;
            MFNode mfnode;
            SFNode sfnode;

            X3DNode[] snodes;

            for(int j=0; j < dlen; j++) {
                ftype = decls[j].getFieldType();
                atype = decls[j].getAccessType();

                if (atype == X3DFieldTypes.INPUT_OUTPUT || atype == X3DFieldTypes.INITIALIZE_ONLY) {
                    if (ftype == X3DFieldTypes.MFNODE) {
                        mfnode = (MFNode) node.getField(decls[j].getName());
                        snodes = new X3DNode[mfnode.getSize()];

                        mfnode.getValue(snodes);
                        findTransform(snodes);
                    } else if (ftype == X3DFieldTypes.SFNODE) {
                        sfnode = (SFNode) node.getField(decls[j].getName());
                        snodes = new X3DNode[1];

                        snodes[0] = sfnode.getValue();

                        if (snodes[0] != null) {
                            findTransform(snodes);
                        }
                    }
                }
            }
        }
    }

    /**
     *  Check that a node is of a specific X3D Abstract type.
     *  
     * @param node The node to check
     * @param type The type to look for
     * @return TRUE if one of the types match
     */
    private boolean typeEquals(X3DNode node, int type) {
        int[] nodeTypes = node.getNodeType();
        
        int len = nodeTypes.length;
        
        for(int i=0; i < len; i++) {
        	if (nodeTypes[i] == type)
        		return true;
        }
        
        return false;
    }
    
    /**
     * Main method.
     *
     * @param args None handled
     */
    public static void main(String[] args) {

        SAISGWalkDemo demo = new SAISGWalkDemo();
    }

}
